18

I'm testing the stackable notifications (Stacking Notifications article).

I detected that in some cases the notifications are not shown after the notify() call in devices running android 4.X KitKat.

To simply the problem I created this code that simulates a notification (button1) and a second notification with a summary (button2)

private final static int NOTIFICATION_ID_A=6;
private final static int NOTIFICATION_ID_B = 7;
private final static int NOTIFICATION_ID_SUMMARY = 8;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showNotif(NOTIFICATION_ID_A,false);
        }
    });
    findViewById(R.id.button2).setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            showNotif(NOTIFICATION_ID_B,false);
            showNotif(NOTIFICATION_ID_SUMMARY,true);
        }
    });
}

private void showNotif(int notificationId,boolean groupSummary) {
    CharSequence title="Title "+notificationId;
    CharSequence message="Message "+notificationId;
    NotificationCompat.Builder notifBuilder = new NotificationCompat.Builder(this);
    notifBuilder.setSmallIcon(R.drawable.icon_notifications);
    notifBuilder.setContentTitle(title);
    notifBuilder.setContentText(message);
    notifBuilder.setGroupSummary(groupSummary);
    notifBuilder.setContentIntent(PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), PendingIntent.FLAG_UPDATE_CURRENT));
    notifBuilder.setGroup("group_" + 1);
    NotificationManagerCompat.from(this).notify(notificationId, notifBuilder.build());
}

The idea is first to press the button1 and then the button2. It works great in android 5.0+ showing the first notif first and the summary when the second button is clicked, but in Android 4.X the button1 does not show anything.

Where is the error?

Thanks

Addev
  • 31,819
  • 51
  • 183
  • 302
  • Hi @Addev I'm getting same issue. How did you solve this? Any idea? Thanks in advance. – sourcerebels Nov 05 '15 at 10:13
  • Same thing here. First individual notification is not shown, and the group notification is shown only with the second individual notification. Broken on KitKat and below, works fine on Lollipop and above. Due to time constraints I just had to disable notification grouping for API < 21. This has to either be a bug in the NotificationManagerCompat for pre-Lollipop APIs, or we're missing some occult argument/method call somewhere to make this work correctly. Either way, I'm adding a bounty here to draw some attention to this. – Matej Jan 20 '16 at 11:17
  • what have you set as your current min and target sdk versions? – Viral Patel Jan 20 '16 at 11:40
  • In my case, min is 14, target is 23. Also AppCompat 23.1.1, which is is the latest AFAIK. – Matej Jan 20 '16 at 11:56
  • Maybe this link could help you : http://stackoverflow.com/questions/26487846/stack-notifications-in-kitkat-api-19-using-setgroup-not-working – Pipiks Jan 22 '16 at 10:05

2 Answers2

16

The short answer to this is that it appears showing a stacked notification on a KitKat device is not automatically supported by the support library.

Since you asked for an enlightenment here are my findings based on testing with two devices running Android 4.4.2. I am also using AppCompat 23.1.1.

When you dig into the source code of the library you will find that when a notification is shown it will either use something called the SideChannel or the NotificationManager directly to show the notification. Below is the NotificationManagerCompat.notify method for reference showing this:

public void notify(String tag, int id, Notification notification) {
    // MY COMMENT: true when the notification has the extra 
    // NotificationCompatJellybean.EXTRA_USE_SIDE_CHANNEL set to true.
    if (useSideChannelForNotification(notification)) {
        pushSideChannelQueue(new NotifyTask(mContext.getPackageName(), id, tag, notification));
        // Cancel this notification in notification manager if it just transitioned to being
        // side channelled.
        IMPL.cancelNotification(mNotificationManager, tag, id);
    } else {
        // MY COMMENT: this calls notificationManager.notify(id, notification); in the base implementation
        IMPL.postNotification(mNotificationManager, tag, id, notification);
    }
}

Now when you show a notification without setting a group the notification is shown using the notification manager which works, but if a group is set it will attempt to use the side channel to send the notification and cancel any notification shown using the notification manager as seen in the above method.

Proof that the side channel is used when a group is set is found in NotificationCompatKitKat.Builder where you will see the following code:

if (groupKey != null) {
    mExtras.putString(NotificationCompatJellybean.EXTRA_GROUP_KEY, groupKey);
    if (groupSummary) {
        mExtras.putBoolean(NotificationCompatJellybean.EXTRA_GROUP_SUMMARY, true);
    } else {
        mExtras.putBoolean(NotificationCompatJellybean.EXTRA_USE_SIDE_CHANNEL, true);
    }
}

This all does not seem like a big deal until you look at what the pushSideChannelQueue(...) method does when showing a notification using the SideChannel.

It ends up looking for a service that can handle the action android.support.BIND_NOTIFICATION_SIDE_CHANNEL of which there is not one by default so the method simply returns. This is what is causing the notification to never be shown.

There is a NotificationCompatSideChannelService abstract class in the compatibility library that you can implement according to the documentation if you want to write your own SideChannelService but it seems like you are better off just not using grouped notifications in KitKat and prior devices.

George Mulligan
  • 11,813
  • 6
  • 37
  • 50
  • 1
    Thank you very much for this detailed answer, it's really helpful despite not actually giving a solution to the problem. I'm on the road now, so I'll review it a bit deeper when I'm back! – Matej Jan 23 '16 at 10:42
  • You got the bounty, you deserve it. I think I'll stick with not using grouped notifications on KitKat and earlier versions of Android. But on the bright side, this question is far from the dead end it used to be, so thank you for that! If only the OP would see the update and consider accepting the answer. – Matej Jan 26 '16 at 21:42
  • @Matej Thanks. I must say I myself was disappointed after discovering this but at least as you said there is some closure. It sure would have been nice for them to mention this in the documentation in the first place! – George Mulligan Jan 26 '16 at 22:01
  • 1
    For backwards compatibility you could use something like `if (Build.VERSION.SDK_INT > Build.VERSION_CODES.KITKAT) builder.setGroup(GROUP_KEY);` to fall back to a less ideal but still functional implementation. – Hugh Jeffner Feb 26 '16 at 17:18
  • Actually, I did some more testing and you will additionally need to conditionally create individual notifications or use a summary depending on the number of notifications you are trying to add. – Hugh Jeffner Feb 26 '16 at 17:32
2

The solution of George is technically right but is not user-friendly because is based on a NotificationListener that has to be enabled manually from phone security setting by user.

I find this working method, set setGroupSummary(true) also to which ones that represent single notification and notify everyone with same id that specify the category of the notification (e.g. messages instead single conversation). If no particular grouping style is applied, the notification is posted as a normal non-grouped one. If a grouped one is posted, it will replace any single notification because have all the same id.

Telegram for Android apply this technique to group notifications also on KitKat and lower.