androidnotificationsgoogle-cloud-messaginggcmlistenerservice

Push notifications not opening correct screens


I have an app where I get GCM push notifications in a GcmListenerService(as given in the gcm android sample). Whenever I get the notification, I get some JSON with data related to showing the notification.

Now suppose I get a notification that "someone bookmarked me", for that I get the pk(identifier) of that user and when I click on the notification, it uses the pk received in the push notification to display that user's profile.

The issue : If I get 2 notifications of above mentioned kind, then no matter which notification I click, I always go the profile of the person whose notification I received most recently.

Does getting a notification on top of other, overrides the values of the previous notifications so that only the most recent one is valid? Does that mean I can show only one push notification from an app? I can post the code if that is needed.

Relevant code:

@Override
    public void onMessageReceived(String from, Bundle data) {
        tinyDB = new TinyDB(this);
        if (tinyDB.getBoolean(AppConstants.LOGIN_STATE, false)) {
            try {
                Log.i("NOTIF", data.toString());
                String screen = data.getString("screen");
                String dataJson = data.getString("data");
                String displayJson = data.getString("display");
                String notification_id = data.getString("notif_id");
                String priority = data.getString("priority");
                String style = data.getString("style");

                Gson gson = new GsonBuilder().disableHtmlEscaping().create();
                NotificationVal notificationVal = gson.fromJson(displayJson, NotificationVal.class);

                String title = notificationVal.getTitle();
                String text = notificationVal.getText();
                String largeText = notificationVal.getLargeText();
                String smallIcon = notificationVal.getSmallIcon();
                String largeIcon = notificationVal.getLargeIcon();

                Bitmap smallImage = null;
                Bitmap largeImage = null;

                if (!TextUtils.isEmpty(smallIcon)) {
                    smallImage = getBitmapFromURL(smallIcon);
                }

                if ("big_picture".equalsIgnoreCase(style) && (largeImage != null)) {
                    NotificationCompat.BigPictureStyle notificationStyle = new NotificationCompat.BigPictureStyle();
                    notificationStyle.setBigContentTitle(title);
                    notificationStyle.setSummaryText(text);
                    notificationStyle.bigPicture(largeImage);

                    Intent intent = NotificationIntentBuilder.get(this, dataJson, screen, smallIcon, largeIcon, notification_id);

                    TaskStackBuilder stackBuilder = NotificationStackBuilder.get(this, screen, dataJson);
                    stackBuilder.addNextIntent(intent);

                    PendingIntent resultPendingIntent =
                            stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

                    NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this);

                    mBuilder.setSmallIcon(R.drawable.white_square);
                    mBuilder.setAutoCancel(true);
                    mBuilder.setColor(Color.parseColor("#fac80a"));
                    mBuilder.setLargeIcon(largeImage);
                    mBuilder.setContentTitle(title);
                    mBuilder.setContentText(text);
                    mBuilder.setContentIntent(resultPendingIntent);
                    mBuilder.setDefaults(NotificationCompat.DEFAULT_VIBRATE);
                    mBuilder.setDefaults(NotificationCompat.DEFAULT_SOUND);
                    mBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
                    mBuilder.setStyle(notificationStyle);

                    mBuilder.setContentIntent(resultPendingIntent);

                    NotificationManager mNotificationManager =
                            (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
                    if (notification_id != null) {
                        mNotificationManager.cancel(Integer.parseInt(notification_id));
                        mNotificationManager.notify(Integer.parseInt(notification_id), mBuilder.build());
                    }
                } else {
                    Log.i("GCM", "Dummy Notification");
                }
            } catch (Exception e) {
                Log.i("NOTIF", "An exception occurred");
            }
        }
    }

Other internal codes:

public class NotificationStackBuilder {
    public static TaskStackBuilder get(Context context, String screen, String data) {
        if ("IMAGE".equalsIgnoreCase(screen)) {
            TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
            stackBuilder.addParentStack(ImageActivity.class);
            return stackBuilder;
        } else {
            TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
            stackBuilder.addParentStack(NewHomeActivity.class);
            return stackBuilder;
        }
    }
}

public class NotificationIntentBuilder {
    public static Intent get(Context context, String data, String screen, String smallIcon, String largeIcon, String notificationId) {
        if ("IMAGE".equalsIgnoreCase(screen)) {
            String pk = "";
            JSONObject jsonObject = null;
            try {
                jsonObject = new JSONObject(data);
                if (jsonObject.has("pk")) {
                    pk = jsonObject.getString("pk");
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            Intent intent = new Intent(context, ImageActivity.class);
            intent.putExtra("ID", pk);
            intent.putExtra("notificationId", notificationId);
            return intent;
        } else if ("GALLERY".equalsIgnoreCase(screen)) {
            String pk = "";
            JSONObject jsonObject = null;
            try {
                jsonObject = new JSONObject(data);
                if (jsonObject.has("pk")) {
                    pk = jsonObject.getString("pk");
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
            Intent intent = new Intent(context, GalleryActivity.class);
            intent.putExtra("ID", pk);
            intent.putExtra("notificationId", notificationId);
            return intent;
        } else {
            return new Intent(context, NewHomeActivity.class);
        }
    }
}

Edit This issue is not happening with two notifications of different type(opening different activities), it is only happening with notifications opening the same screen.

Edit 1 Here is the value received in the push notification:

Bundle[{google.sent_time=1469254984538, priority=0, screen=IMAGE, data={"pk":650}, style=big_picture, google.message_id=0:1469254984541527%e07f0e28f9fd7ecd, notif_id=4267, display={"large_icon":"https:\/\/d2r0rrogy5uf19.cloudfront.net\/photos\/971c03f8-6a5d-30a3-9e49-0ab416cb8fa0.jpg","small_icon":"","text":"Random hi5'd your photo to 'Diwali'","title":"random","large_text":""}, collapse_key=do_not_collapse}]

This one has notificationId as 4267, now suppose I get another notification for same screen, with notificationId say, 4268, then when I log the notificationId received in the Image screen, I get 4268 on opening both the notifications.

Edit 2 I guess the issue is related to PendingIntent.FLAG_UPDATE_CURRENT. Here is what is written in the documentation:

Flag indicating that if the described PendingIntent already exists, then keep it but replace its extra data with what is in this new Intent.

This is what was happening. The contents of intent extras were getting over-written by the latest notification's intent extras. So, I tried using FLAG_ONE_SHOT, but with that I am able to open the old intent but noting opens when I click the latest intent.

I want both notifications to be on the push notification list and that both of them should the respective screens with different values of intent extras.


Solution

  • You need to have unique request code for each notification or else it will be replaced with new one.

    An excerpt from PendingIntent documentation :

    The last intent in the array represents the key for the PendingIntent. In other words, it is the significant element for matching (as done with the single intent given to getActivity(Context, int, Intent, int), its content will be the subject of replacement by send(Context, int, Intent) and FLAG_UPDATE_CURRENT, etc. This is because it is the most specific of the supplied intents, and the UI the user actually sees when the intents are started.

    So replace the below line:

    PendingIntent resultPendingIntent = stackBuilder. getPendingIntent(0,
                                            PendingIntent.FLAG_UPDATE_CURRENT);
    

    Assuming notification_id is unique integer, just replace it like below:

    PendingIntent resultPendingIntent =
              stackBuilder.getPendingIntent(Integer.parseInt(notification_id)
                  , PendingIntent.FLAG_UPDATE_CURRENT);