Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep track of notifications to know when to show a summary notification

I want to emulate Gmail's app behavior regarding notification bar notifications, which complies with the recommended Android pattern: http://developer.android.com/design/patterns/notifications.html

When the app is in background and I get a new e-mail I get a notification in the notification bar like this:

Line 1 : Jane Smith
Line 2 : Hi John, this is a sample message...

That is, a notification that is specific for a single message, and tapping it leads to a screen showing that specific e-mail. If I clear the notification either by swiping it or with "Clear all", then when I get a new message I will get another single message specific notification. But if I don't clear it and I get another e-mail then the notification will turn into a summary notification saying "2 New messages", and tapping it leads to the inbox.

I know how to update a notification, the question is how do I figure out which notifications are still there in the notification bar, if any. The answer is not that simple because the notification will not reflect how many unread messages I have, it must reflect which messages are still not acknowledged by the user either by tapping the notification, or clearing it.

Should I keep track of notifications by keeping a list of notifications that we launched, the ones that were tapped (content intent) and the ones cleared (delete intents)? I don't think that approach is fail safe enough... for example: What happens if notifications get cleared because I boot my phone? Where am I supposed to keep track of notifications still showing? Shared preferences?

How do you usually solve this?

like image 604
fekke Avatar asked Apr 24 '14 15:04

fekke


1 Answers

I just had the same issue and I also looked at Gmail for the appropriate behaviour. I first studied the following scenarios:

Assuming a user is actively using the Gmail app (disregard any interaction with the browser version), and then navigates away from it:

  1. From that point on, if the user receives a new email, it will get a notification.
  2. If the notification is still there and the user receives a new email, the notification will be updated to a summary containing the title of the N most recent emails since the user last used the app.
  3. If the user dismisses the notification and another email arrives, another summary notification is issued.
  4. If the user navigates back into the app (either by clicking the notification or not), any existing notifications are dismissed.

In API 18, Android added support to retrieve active notifications using NotificationListenerService, however that's too recent for the app I'm working on (min API 14), not to mention you can't rely on that to get the existing notification information if it has already been dismissed by the user.

So the solution I found was to persist information about the notifications already issued locally, use that information to create either a single notification or a summary, and clear everything when the user opens the app again.

To persist the notification information, I created a simple model similar to the following:

public class NotificationBundle {
    private String mText;
    // Add any other relevant information about your notification here, 
    // particularly what you used to create your notification intent 
    // i.e. an item/message id to highlight, maybe?

    public String getText() {
        return mText;
    }

    public void setText(final String text) {
        mText = text;
    }
}

The idea is to create an instance of those for each notification you issue.

Then you have to have in place a way to persist your list of NotificationBundle objects. I used SharedPreferences to do that, but you could use whatever else suits you better (like a DB table). To persist a List<NotificationBundle> in SharedPreferences I used Gson to serialize the array into json, and then saved that as a string. Assuming you can use SharedPreferences, you can find how to do the serialization in this answer.

With that structure in place, basically what's left for you to do is:

  • When you have to issue a notification:

    1. Create a new NotificationBundle with the information you want to notify.
    2. Retrieve your existing List<NotificationBundle> from SharedPreferences
    3. If your list of bundles is empty, you will issue a single notification. If it's not, you will issue a summary - in this case you can use your list of bundles to construct the content of your summary. A good article on summary notifications is [Using Big View Styles].
    4. Add your new NotificationBundle (from 1) into your existing List<NotificationBundle> (from 2) and save it to SharedPreferences.
    5. Issue your notification using NotificationManager.notify(). If you always use the same notification id here, it will create a new notification if none from your app are currently visible, or it will just update it if a previous notification is visible.
  • On your onResume() method of your main Activity, make sure to dismiss all notifications with NotificationManager.cancelAll(). Also make sure to remove from your SharedPreferences your existing List<NotificationBundle>.

And that should do the trick.

like image 113
Rafael Slobodian Avatar answered Oct 29 '22 19:10

Rafael Slobodian