I want to receive a sms in my app, but I don't want my Android to show a notification about that event. Algorithm:
Receive sms (it's ok)
If this is a sms with special content-format (for my app) - process it with my app and don't display a notification.
If this is a simple message - I don't want to process it, so a notification must be displayed.
I tried to use an ordered broadcast, but it doesn't help. Somewhere I read that SMS_RECEIVE's broadcast is not ordered, but I saw some apps, which can receive SMS without notify.
Does anyone can help me or show me the right way to solve this problem?
Calling abortBroadcast() in broadcast doesn't help
set priority in your intent-filter
// in manifest
<intent-filter android:priority="100"> /*your receiver get high priority*/
// in broadcast receiver
if (keyword_match)
{
// Stop it being passed to the main Messaging inbox
abortBroadcast();
}
This should be possible by registering your app to receive SMS messages and then using abortBroadcast() when you detect your message has arrived. You say abortBroadcast() doesn't work - is the SMS definitely getting handled by your SMS receiver?
For anybody else wanting to do this, read on...
First, declare the SMS receiver in your AndroidManifest.xml and make sure the app has permission to receive SMS messages.
<receiver android:name="mypackage.SMSReceiver">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
<uses-permission android:name="android.permission.RECEIVE_SMS" />
Here's some example code to handle the SMS messages:
public class SMSReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getExtras();
Object[] pdus = (Object[])extras.get("pdus");
for (Object pdu: pdus)
{
SmsMessage msg = SmsMessage.createFromPdu((byte[])pdu);
String origin = msg.getOriginatingAddress();
String body = msg.getMessageBody();
// Parse the SMS body
if (isMySpecialSMS)
{
// Stop it being passed to the main Messaging inbox
abortBroadcast();
}
}
}
}
You should not do this. Other apps might want or need to receive the SMS_RECEIVED broadcast. Aborting it will disrupt 3rd party apps from running properly. This is a bad way to program. you should only abort broadcasts that you create, not system broadcasts. I don't know why the Android OS lets you do this.
not sure if i know exactly what you are trying to do but from what i understand you just want to know how to not send a notification?
why cant you just do:
If(instance 2){
//do your processing
}else{
//send notification
}
if you mean you want to block the OS from broadcasting it then you might be out of luck because i dont believe you can do that
yo need android:priority attribute for that to work
<intent-filter android:priority="1">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
You are doing one mistake,
because you fired abortBroadcast(); if your special message so the message broadcasting is aborted, therefore SMS notification is not Showing, and sms is not saving in Inbox,
You have to make your own Notification in "onRecive" if your special message is received.
Example:
public class SMSReceiver extends BroadcastReceiver
{
#Override
public void onReceive(Context context, Intent intent)
{
Bundle extras = intent.getExtras();
Object[] pdus = (Object[])extras.get("pdus");
for (Object pdu: pdus)
{
SmsMessage msg = SmsMessage.createFromPdu((byte[])pdu);
String origin = msg.getOriginatingAddress();
String body = msg.getMessageBody();
// Parse the SMS body
if (isMySpecialSMS)
{ // Stop it being passed to the main Messaging inbox
abortBroadcast();
NotificationManager notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
Notification notification = new Notification(R.drawable.ic_launcher, "New Message (My Messaging app)", System.currentTimeMillis());
// Uses the default lighting scheme
notification.defaults |= Notification.DEFAULT_LIGHTS;
// Will show lights and make the notification disappear when the presses it
notification.flags |= Notification.FLAG_AUTO_CANCEL | Notification.FLAG_SHOW_LIGHTS;
Intent notificationIntent = new Intent(context, SplashActivity.class);
PendingIntent pendingIntent =PendingIntent.getActivity(context, 0,
new Intent(context, SplashActivity.class), 0);
Log.i("Wakeup", "Display Wakeup");
PowerManager pm = (PowerManager)context.getApplicationContext().getSystemService(Context.POWER_SERVICE);
WakeLock wakeLock = pm.newWakeLock((PowerManager.SCREEN_BRIGHT_WAKE_LOCK | PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP), "Phone WakeUp");
wakeLock.acquire();
notification.setLatestEventInfo(context, "My Messaging App(New Message)",msg, pendingIntent);
//notification.sound.
notification.defaults |= Notification.DEFAULT_SOUND;
notificationManager.notify(9999, notification);
}
else{
//Continue Broadcasting to main android app
}
}
}
}
I hope this will solve your Problem
Related
On the Android app, I need to open a specific activity on clicking push notification. I am directly sending the message from the firebase FCM console. I Did the configuration below, with some condition to open different activities. It is working properly while the app is in the foreground.
While the app is in the foreground, on clicking the received notification, it opens the corresponding activity based on given condition. Everything working fine.
But while the app is in the background, on clicking push notification, it opens the main activity. Also, the message showing is the message I gave in the Notification payload of FCM(Not that given in data payload/Additional section of FCM console).
I need app to open specific activity on clicking push notification while the app is in the background as well.
Can't I do this from the FCM console directly?
please advise
public class MyFireBaseMessagingService extends FirebaseMessagingService {
private static final String TAG = "FCM Service";
private static int count = 0;
#Override
public void onNewToken(#NonNull String s) {
super.onNewToken(s);
Log.e(TAG, "onNewToken: " + s);
}
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
Map<String,String> opendata = remoteMessage.getData();
String actionValue = opendata.get("openactivity");
Intent intent=new Intent();
assert actionValue != null;
switch (actionValue) {
case "Activity1":
intent = new Intent(this, Activity1.class);
break;
case "Activity2":
intent = new Intent(this, Activity2.class);
break;
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.putExtra("pushnotification","True");
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationManager mNotifyManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel mChannel = new NotificationChannel("MyID", "Myapp", importance);
mChannel.setDescription(remoteMessage.getData().get("message"));
mChannel.enableLights(true);
mChannel.setLightColor(Color.RED);
mChannel.enableVibration(true);
mNotifyManager.createNotificationChannel(mChannel);
}
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this, "MyID");
mBuilder.setContentTitle(remoteMessage.getData().get("title"))
.setContentText(remoteMessage.getData().get("message"))
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.maft_logo))
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setColor(Color.parseColor("#FFD600"))
.setContentIntent(pendingIntent)
.setChannelId("Myid")
.setPriority(NotificationCompat.PRIORITY_LOW);
mNotifyManager.notify(count, mBuilder.build());
count++;
}
}
Manifest
<service
android:name=".MyFireBaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
If notification clicks on app background state, then that will open app launcher activity. In launcher activity you need to check if there is any pending intent from notification and execute that.
Try this in your launcher activity(MainActivity).
Intent intent=new Intent();
Intent fromIntent = getIntent();
if (fromIntent.getExtras()!=null){
try {
Map<String,String> opendata = remoteMessage.getData();
String actionValue = opendata.get("openactivity");
switch (actionValue){
case "Activity1":
intent=new Intent(this, Activity1.class);
break;
case "Activity2":
intent=new Intent(this, Activity2.class);
break;
default:
intent = new Intent(MainActivity.this, DefaultActivity.class);
break
}
} catch(Exception e){
intent = new Intent(MainActivity.this, DefaultActivity.class);
}
} else{
intent = new Intent(MainActivity.this, DefaultActivity.class);
}
startActivity(intent);
when your app in background, the method onMessageReceived never invoked, system notification auto show on your notification tray instead, so you need implement some logic (same in onMessageReceived method) in your main activity to navigate user to the destination screen.
There are two type of notification :
Data message notification other one is
Normal notification
In Data message notification send from server, when your app is kill then we got payload in onMessageReceive method.
But in case of Notification fire from other like console and your app is kill then you got default notification there is no callback in onMessageReceive method.
For testing you can set log in your onMessageReceive method but your log not print, when your app is kill and you fire notification from console, but with server because of data message
you got callback in onMessageReceive.
In your case everything working fine, you have to try with actual server.
I recently discovered that almost everything about the notification is managed by the cloud messaging function. You don't need to create a NotificationManager inside the onMessageReceived. The function presets the title & body. It can also set the activity to be opened when the notification is clicked.
You just need to include the payload parameter "click_action" that is sent alongside the notification. Your payload needs to look something like this:
return admin.messaging().sendToTopic(
topicId,
{
notification: {
title: "Custom title",
body: "Custom body",
click_action: "DestinationActivity"
},
data: {
"payload": myPayload
}
}
More on cloud functions here.
Now move to your project's Manifest and find the destination activity. Make the following changes (make sure to set the exported attribute to true):
<activity
android:name="DestinationActivity"
android:exported="true">
<intent-filter>
<action android:name="DestinationActivity" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
The intent filter picks the click_action parameter from the payload so any notification with "DestinationActivity" as its click action shall be handled by the Destination activity. I am starting to think that one doesn't even need to override the onMessageReceived method. FCM makes it really convenient.
I have created android application to receive push notification from server but it is not working.
When app is in foreground, it works perfectly. But when we force close app from system tray it does not work.
Below is my json code which I send to FCM.
{"to":"\/topics\/global","data":{"title":"Title","body":"Body"}}
Below is my android function
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
Log.d("Msg", "Message received ["+remoteMessage+"]");
Map<String, String> data = remoteMessage.getData();
DatabaseHandler db = new DatabaseHandler(getApplicationContext());
db.addData(data.get("body"));
Intent resultIntent = new Intent(getApplicationContext(), MainActivity.class);
resultIntent.putExtra("message", data.get("body"));
showNotificationMessage(getApplicationContext(), data.get("title"), data.get("body"), "", resultIntent);
}
Below is code to show notification.
private void showNotificationMessage(Context context, String title, String message, String timeStamp, Intent intent) {
notificationUtils = new NotificationUtils(context);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
notificationUtils.showNotificationMessage(title, message, timeStamp, intent);
}
I can not find any problem, can any one please help me.
Thank you very much in advance.
Edit :
I have solved my problem by changing phone, in samsung device code is working fine but its problem with MI device itself.
I have also got solution for MI devices, use below steps to enable auto start that application.
Go to settings --> permissions --> autostart. From there, pick the apps you want to receive notifications, and toggle the switch to turn it on.
As per the doc there are two possibilities when notification arrived.
Application is in foreground.
You will get notify in onMessageReceived, and you can get data in this method. You need to generate local notification in system tray.
Handle Notification
You have done this code as mentioned in question.
Application is in background.
You get notification in system tray. You don't need to generate notification here. You will get data in Intent of launcher Activity.
Handle Notification
Here is code of launcher activity
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = getIntent();
if (intent == null || intent.getExtras() == null) {
// your code to handle if there is no notification
} else {
// handle notification
String body = intent.getStringExtra("body");
String title = intent.getStringExtra("title");
//TODO your code to open activity as per notification
}
}
I have done this, and its works for me.
From here,
When in the background, apps receive the notification payload in the notification tray, and only handle the data payload when the user taps on the notification.
And from this,
This includes messages that contain both notification and data payload (and all messages sent from the Notifications console). In these cases, the notification is delivered to the device's system tray, and the data payload is delivered in the extras of the intent of your launcher Activity
You might get complete help from receive message tutorial
In my IntentService class, i create a Notification and assign ID=1213, and the notification will show up once the apps is open.
Intent cancelScan = new Intent();
cancelScan.setAction(CANCEL);
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 1213, cancelScan, PendingIntent.FLAG_UPDATE_CURRENT);
mNbuilder.addAction(android.R.drawable.ic_menu_close_clear_cancel,"Cancel Scanning",pendingIntent);
NotificationManager manager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
manager.notify(NOTIFICATION_ID, mNbuilder.build());
in my BroadcastReceiver class
if(CANCEL.equals(intent.getAction())){
Log.i(TAG,"Received Broadcasr Receiver");
NotificationManager nm = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
//context.stopService(new Intent(context,ScanService.class));
nm.cancel(NOTIFICATION_ID);
}
}
and, my Manifest.XML
<receiver android:name=".WifiScanReceiver" android:enabled="true">
<intent-filter>
<action android:name="CANCEL"/>
</intent-filter>
</receiver>
I had tried couple times when i click the action button beneath the notification, but the Logcat did not print anything. Which parts i had done wrong? Thank in Advance.
The values of CANCEL and the value declared as action ("CANCEL") in your manifest must be equal, or it won't work. Your's don't, that's why you don't reach your if statement. Your receiver is triggered though, because you send a broadcast with the correct action.
To make sure you use the correct values in your code, you can declare a static final in your WifiScanReceiver:
public class WifiScanReceiver {
public static final String CANCEL = "CANCEL";
...
}
So you can also use it in you code when you send the broadcast:
Intent cancelScan = new Intent();
cancelScan.setAction(WifiScanReceiver.CANCEL);
That way you are always certain that you use the same value. The only one that you have to make sure is also correct, is the one in your manifest.
I'm developing ,for educational purposes, a Android APP.
This APP have a GCMService and works well, but I'm trying to start a simple sound or alarm when the APP receive a certain message from GCM Service.
How I can do this?
I'm searching for information, but always see the people start a Service or Activity, and I think this is much easy.
Thanks ALL!
You can write the code into onMessage() of GCMIntentService like
#Override
protected void onMessage(Context context, Intent intent) {
Log.i(TAG, "Received message");
String message = getString(R.string.gcm_message);
displayMessage(context, message);
// notifies user
generateNotification(context, message);
//Write here for sound notification
//for example
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone ringer = RingtoneManager.getRingtone(getApplicationContext(), notification);
ringer.play();
}
start a simple sound or alarm when the APP receive a certain message
from GCM Service
You can put condition in above method and play soound. like
if ("XYZ".equals(message)) {
//Then Play a sound
Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
Ringtone ringer = RingtoneManager.getRingtone(getApplicationContext(), notification);
ringer.play();
}
I'm developing a business SMS application. In this app, if an incoming message is from a particular number, say 999999999, it should go to the application's inbox and not to the default native inbox. All other messages should go to the phone's native inbox. How do I do this?
When SMS is received by the Android system, it broadcasts an ordered broadcast Intent with action "android.provider.Telephony.SMS_RECEIVED". All registered receivers, including the system default SMS application, receive this Intent in order of priority that was set in their intent-filter. The order for broadcast receirers with the same priority is unspecified. Any BroadcastReceiver could prevent any other registered broadcast receivers from receiving the broadcast using abortBroadcast().
So, everything you need is broadcast receiver like this:
public class SmsFilter extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.provider.Telephony.SMS_RECEIVED")) {
Bundle extras = intent.getExtras();
if (extras != null) {
Object[] pdus = (Object[])extras.get("pdus");
if (pdus.length < 1) return; // Invalid SMS. Not sure that it's possible.
StringBuilder sb = new StringBuilder();
String sender = null;
for (int i = 0; i < pdus.length; i++) {
SmsMessage message = SmsMessage.createFromPdu((byte[]) pdus[i]);
if (sender == null) sender = message.getOriginatingAddress();
String text = message.getMessageBody();
if (text != null) sb.append(text);
}
if (sender != null && sender.equals("999999999")) {
// Process our sms...
abortBroadcast();
}
return;
}
}
// ...
}
}
Looks like the system default SMS processing application uses priority of 0, so you could try 1 for your application to be before it. Add these lines to your AndroidManifest.xml:
<receiver android:name=".SmsFilter">
<intent-filter android:priority="1">
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
Don't forget about necessary permissions:
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
By the way, you can find all registered receivers and their priorities using this code:
Intent smsRecvIntent = new Intent("android.provider.Telephony.SMS_RECEIVED");
List<ResolveInfo> infos = context.getPackageManager().queryBroadcastReceivers(smsRecvIntent, 0);
for (ResolveInfo info : infos) {
System.out.println("Receiver: " + info.activityInfo.name + ", priority=" + info.priority);
}
Update: As FantasticJamieBurn said below, starting from Android 4.4 the only app that can intercept SMS (and block if it wish) is the default SMS app (selected by user). All other apps can only listen for incoming SMS if default SMS app not blocked it.
See also SMS Provider in the Android 4.4 APIs.
With the release of Android 4.4 KitKat (API level 19), the option to block an SMS message and prevent it from being delivered to the default SMS app has been removed. Non-default SMS app's may observe SMS messages as they are received, but any attempt to abort the broadcast will be ignored by Android 4.4+.
If you have an existing app which relies on aborting SMS message broadcasts then you may want to consider the impact this change in behaviour will have when your users upgrade to Android 4.4+.
http://android-developers.blogspot.co.uk/2013/10/getting-your-sms-apps-ready-for-kitkat.html
Yes it can be DOne
public void onReceive(Context context, Intent intent)
{
Bundle bundle=intent.getExtras();
Object[] messages=(Object[])bundle.get("pdus");
SmsMessage[] sms=new SmsMessage[messages.length];
Toast.makeText(context, "Hello", 1).show();
for(int n=0;n<messages.length;n++){
sms[n]=SmsMessage.createFromPdu((byte[]) messages[n]);
}
for(SmsMessage msg:sms){
if(msg.getOriginatingAddress().endsWith(number))
{
SMS.updateMessageBox("\nFrom: "+msg.getOriginatingAddress()+"\n"+
"Message: "+msg.getMessageBody()+"\n");
/*((SMS) context).delete();*/
abortBroadcast();
}
}
}
just use abortbroadcast() after receiving in app
Are you the one sending the messages? If so consider using datasms instead as they will not show up in the inbox.
Check this question for more info on how to use it
Check the sender number is equal to the mobile number of your sms sending phone.
replace the following code line of Mr "praetorian droid"
if (sender != null && sender.equals("999999999")) {
to
if (sender != null && sender.equals("YOUR SMS SENDING MOBILE NUMBER HERE")) {
further more you can give a setting to user to manually add sms sending number if he want to change it.