I'm writing my own SMS messenger and I need to completely suppress new SMS notification raised by default stock messenger. For sure I'm intercepting incoming SMS notification and aborting Broadcast through BroadcastReceiver.abortBroadcast(), like:
public void onReceive(Context context, Intent intent) {
Map<String, String> msgs = retrieveMessages(intent);
for (String address : msgs.keySet()) {
String msg = msgs.get(address);
Log.i(TAG, "New sms received=" + msg);
//saving message in phone
Message message = Message.createIncomingMessage(address, msg);
message.setSeen(1); ////mark message seen, so stock messenger couldn't arose notification
message.setRead(1); //mark message read, so stock messenger couldn't report it as unread
message.setUnread(true); //mark message unread for our messenger
message = Me.getMe().getMessageDAO().save(context, message); //saving message
SmsReceiver.updateNotification(context, message, true, true); //raise notification from "our" messenger
}
//aborting default broadcast, since everything already done and no need to do more
this.abortBroadcast();
}
Everything works as planned. But whenever I'm inserting new SMS into database through Me.getMe().getMessageDAO().save(context, message); within few seconds stock messenger somehow is being notified about new message in database and again raises notification.
Question is: how to suppress this notification?
first you need to set priority of your receiver see docs.
secondly, call abortBroadCast before you do heavy processing task(storing into DB).
or you can try this db storing thing in a thread, Start the thread and call abortBroadcast() immediately.
Related
I try to get the payload data from a fcm message, while my app is in the background. So I read this documentation and they say,
I can get the data in the extras of the intent from my launcher activity, because if you click on the notification by default your launcher activity will open.
I send the message via the firebase console, then my app is in the foreground, I can handle all this via the onMessageReceived() method.
This is my code to achieve this, but the intent extras are null..
if (getIntent().getExtras() != null) {
bundleFCM = getIntent().getExtras();
for (String key : bundleFCM.keySet()) {
Log.d(TAG, "payload keys: " + key);
}
}
Okay my problem was, that I have a SplashActivity and the data payload was sent to this activity, so I transfer the data from the SplashActivity to my HomeActivity and all works fine.
I won't show a received push notification from appearing top notifications menu my notification if it has for example key update. For now if I get notification with this key, all notifications are in the notification bar. I want to not present this notifications for user.
I'm using WakefulBroadcastReceiver for handle notifications like below:
public class PusherReceiver extends WakefulBroadcastReceiver {
private boolean isAppOnForeground(Context context) {
ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);
List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
if (appProcesses == null)
return false;
final String packageName = context.getPackageName();
for (ActivityManager.RunningAppProcessInfo appProcess : appProcesses) {
if (appProcess.importance == ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND && appProcess.processName.equals(packageName)) {
return true;
}
}
return false;
}
public void onReceive(final Context context, Intent intent) {
Log.i("SimpleWakefulReceiver", "Starting service # " + SystemClock.elapsedRealtime());
if (!isAppOnForeground((context))) {
String pushNotificationBody = intent.getStringExtra("alert");
try {
JSONObject notificationData = new JSONObject(pushNotificationBody);
// This is the Intent to deliver to our service.
Intent service = new Intent(context, BackgroundService.class);
// Put here your data from the json as extra in in the intent
service.putExtra("notification", pushNotificationBody);
Log.i("PUSH_NOTIFICATION_JSON", "RECEIVED JSON " + notificationData);
// Start the service, keeping the device awake while it is launching.
if (!notificationData.has("update")) {
startWakefulService(context, service);
} else {
// Do nothing
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
UPDATE:
I changed project a little and with Onesignal and his NotificationExtenderService, I did something like below:
public class NotificationNotDisplayingExtender extends NotificationExtenderService {
#Override
protected boolean onNotificationProcessing(OSNotificationReceivedResult receivedResult) {
String notification = receivedResult.toString();
String notificationBody = receivedResult.payload.body;
JSONObject notificationBodyJSON = null;
try {
notificationBodyJSON = new JSONObject(notificationBody);
} catch (JSONException e) {
e.printStackTrace();
}
JSONObject pushNotificationData = notificationBodyJSON;
boolean hidden = false;
if (pushNotificationData.has("update")) {
Log.i("NOTIFICATION MANAGER", "PREVENT DISPLAY NOTIFICATION");
hidden = true;
}
// Return true to stop the notification from displaying.
return hidden;
}
}
And it prevent displaying notifications with update key, but now I don't receive it in my PusherReceiver to start my service. Is there easy way to send data from my NotificationNotDisplayingExtender receivedResult to my PusherReceiver?
For now it looks like my PusherReceiver don't fire his onReceive method.
Many thanks for help in advance.
There are two types of payload.
1. Data
2. Notification
https://developers.google.com/cloud-messaging/concept-options
Use only data payload. Then you always get the call in FirebaseMessagingService onMessageRececived Method
The thing is basically we have two type of notifications.
One which can be called Notification Type, is that the push has a notification object in sent/received bundle, in which you have to handle it when your app is in foreground and the notification is received. In this case, if your app is in foreground, then you can handle it and do whatever you like which is not showing a notification. But if the app is in background, a notification will automatically create by google and it takes predefined title and message objects within the received push bundle to make the notification.
Second type which can be called Data Type, do not have any notification object in the sent/received bundle. In this scenario, your app is in foreground or background, you should handle everything. So, if you put your data in data object of your push notification message, everything will be in your hands.
So, in short, just put your data in data object of your notification and implement your desired logic.
I do not see the JSON data you are referring to. However, I suppose the update key in your JSON is containing null. In your code you are checking if the JSON data has the key update in it. This function will always return true if the key exists in the JSON body. You might have the field with null value which is indicating that you are not supposed to show the notification in the system tray.
In that case, you might consider using isNull function. It returns true if this object has no mapping for update or if it has a mapping whose value is null.
// Start the service, keeping the device awake while it is launching.
if (!notificationData.isNull("update")) {
startWakefulService(context, service);
} else {
// Do nothing
}
And yes, please use the data payload from the notification that you get.
Every time you notify the NotificationManager to show a notification, you provide an ID to be used for the notification to edit or cancel that notification later on. If you show a notification by manager.notify(notificationId, notification), you can cancel it with manager.cancel(notificationId).
If you want to remove all the notifications, you can use NotificationManager.cancelAll().
I have an auto reply sms Android application I built and I don't want the auto reply (sent sms) to show in the default messaging app. I have searched and searched and couldn't find an answer. Is there a way to bypass writing the sent sms into the default messaging app?
Here my BroadcastReciever I am using to get the data and send out the message
public class SmsReceiver extends BroadcastReceiver {
ParseUser user = ParseUser.getCurrentUser();
// Auto reply message composed of the current reply and url from that business
String msg = user.getString("myCurrentReply") + " " + user.getString("couponUrlChosen");
List smsFromList = user.getList("smsFrom");
String userName = (String) user.get("username");
#Override
public void onReceive(final Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Object messages[] = (Object[]) bundle.get("pdus");
SmsMessage smsMessage[] = new SmsMessage[messages.length];
for (int n = 0; n < messages.length; n++) {
smsMessage[n] = SmsMessage.createFromPdu((byte[]) messages[n]);
}
final String pno = smsMessage[0].getOriginatingAddress();
user.put("lastSmsFrom", pno);
user.saveInBackground();
// show first message
Toast toast = Toast.makeText(context, "Received SMS: " + smsMessage[0].getMessageBody(), Toast.LENGTH_LONG);
toast.show();
// Check Phone Number from SMS Received against Array in User Row
ParseQuery<ParseObject> query = ParseQuery.getQuery("_User");
Log.d("Username: ", userName);
query.whereEqualTo("username", userName);
query.whereContainedIn("lastSmsFrom", smsFromList);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> smsList, ParseException e) {
if (e == null) {
Log.d("Errors", "none");
if (smsList.size() == 0) {
// Send SMS
sendSms(pno, msg);
// Add Phone number to smsFrom in currentUsers Row
user.addUnique("smsFrom", pno);
// Save Phone Number in Array
user.saveInBackground();
Log.d("List size: ", " " + smsList.size());
}
} else {
Log.d("Error Message: ",
e.getMessage());
}
Log.d("Already sent to this number today. ", " " + smsList.size());
}
});
}
private void sendSms(String phonenumber, String message) {
SmsManager manager = SmsManager.getDefault();
manager.sendTextMessage(phonenumber, null, message, null, null);
}
}
Prior to KitKat, SMS sent using SmsManager require the app sending the message to insert it into the Provider, so it would just be a matter of omitting that.
Starting with KitKat, any app that is not the default SMS app and uses SmsManager to send messages will have the messages automatically written to the Provider for it by the system. There's no way to prevent this, and, furthermore, the app won't be able to delete those messages, either, as it won't have write access to the Provider.*
The app that is the default SMS app is responsible for writing its outgoing messages, so it would be able to omit that step. The system does no automatic writes for the default SMS app.
* There is a security hole in 4.4 only, by which a non-default app can gain write access to the Provider. It is detailed in my answer here, but it will not work in versions after KitKat.
I am developing an app for android using eclipse, what i'm basically trying to do is:
send an notification form my device(1) to another device(2).
I am using user log in with is already configured with a database.
When I press down on user(when i press down on a button that sends the notification).
I want device 1 to send an notification that shows on device 2.
Both devices are logged in with different users, but I can't make the notification part to work.
edit: when I push the button the notification displays on device 1, but iI want it to display on device 2...
This is the code of receiving a notification:
public void NmRecv(String username, String message)
{
FriendInfo friend = FriendController.getFriendInfo(username);
MessageInfo msg = MessageController.checkMessage(username);
if ( msg != null)
{
Intent i = new Intent(TAKE_MESSAGE);
i.putExtra(MessageInfo.USERID, msg.userid);
i.putExtra(MessageInfo.MESSAGETEXT, msg.messagetext);
sendBroadcast(i);
String activeFriend = FriendController.getActiveFriend();
if (activeFriend == null || activeFriend.equals(username) == false)
{
localstoragehandler.insert(username,this.getUsername(), message.toString());
showNotification(username, message);
}
}
}
any ideas?
You can achieve that using Google Cloud Messaging.
Also check this link.
You'll have to register the Android devices' keys in order to be able to send notifications.
In other words. You need to store the devices' keys in the Database when they log in.
And then when device1 wants to send a notification to device 2 you do that using GCM and the device 2 key that's stored in the database.
Here's an example of the code I'm using server side to send a message using GCM:
Sender sender = new Sender (SENDER_API_CODE);
Message message = new Message.Builder ()
.collapseKey ("1")
.timeToLive (2419200)
.delayWhileIdle (false)
.addData ("message", "example message")
.build ();
result = sender.send (message, reGid, sendCount);
Receiving side you have to create a Broadcast Receiver with these actions:
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<action android:name="com.google.android.c2dm.intent.REGISTRATION" />
<action android:name="com.google.android.c2dm.intent.GCM_RECEIVED_ACTION" />
and then when you receive the intent you get the message like this:
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
String messageType = gcm.getMessageType(intent);
if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE.equals(messageType))
{
//Here you process the intent like you normally would
//String parameter = intent.getStringExtra("name of parameter");
//...
//After that you can create a notification like in the link below.
}
creating notifications
public class GCMIntentService extends GCMBaseIntentService {
NotificationManager mNotificationManager;
Context cc;
#Override
protected void onRegistered(Context context, String regId) {
Intent intent = new Intent(Constants1.ACTION_ON_REGISTERED);
intent.putExtra(Constants1.FIELD_REGISTRATION_ID, regId);
context.sendBroadcast(intent);
}
#Override
protected void onUnregistered(Context context, String regId) {
Log.i(Constants1.TAG, "onUnregistered: " + regId);
AlertDialog.Builder alert = new AlertDialog.Builder(
getApplicationContext());
alert.show();
}
#Override
protected void onMessage(Context context, Intent intent) {
/**
* You can get the Extras from TaxMann server
*
* Bundle _bundle = intent.getExtras();
*/
String msg = intent.getStringExtra("payload");
mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
BackgroundAlert bg = new BackgroundAlert(mNotificationManager, msg);
bg.onReceive(getApplicationContext(), intent);
}
#Override
protected void onError(Context context, String errorId) {
}
}
This is my code for gcm i have approx 15000 registered_device_id in my database for notification when i send notification to all register device id then it show 10000 success and 6000 unsuccessful .i want to delete all 6000 registered device id from our database so that it take less time to get notification .
You need not to do anything in android code. GCM is smart enough to handle it. So, once our app is uninstalled, GCM will take care of removing that Registration ID from GCM. However, we have to delete that registration Id from our server database, once we get the response from GCM as "NotRegistered", we have to remove that particular registration ID from our database.
Following are the sequence of events.
The end user uninstalls the application.
The 3rd-party server sends a message to GCM server.
The GCM server sends the message to the device.
The GCM client receives the message and queries Package Manager about whether there are broadcast receivers configured to receive it,
which returns false.
The GCM client informs the GCM server that the application was uninstalled.
The GCM server marks the registration ID for deletion.
The 3rd-party server sends a message to GCM.
The GCM returns a NotRegistered error message to the 3rd-party server.Once, we receive this kinda response from GCM, we have to
delete that particular registration ID from our database.
Follow that link might be use full for you
Google Cloud Messaging registration id expiration