Merge Android Notifications Question

Hello, I noticed on android devices each time I send a notification to one of my users it will continue to add to their notification bar… is there any way I can merge/concatenate all the notifications to 1 notification icon?

A quick use case example would be: a user receives likes from multiple users, each like will send him a notification. If the user looks at this notification bar, he’ll have tons of notification icons. Now, is there a way I can convert all those icons to just 1 with it saying 20+ or notifications or something like that?

Anyone have any experience with that? and if so, what push service are you using?

Currently I am using PushWoosh

Android does not automatically consolidate notifications into a single notification like iOS does.  On Android, status bar notifications are managed by the app and not the operating system.  So, the only solution I can think of is for you to remove all notifications and then add then schedule a local notification set to current time.

You can remove all notifications from the status bar by calling system.cancelNotification() without any arguments.

   http://docs.coronalabs.com/daily/api/library/system/cancelNotification.html

You can then call system.scheduleNotification() to create your own consolidated notification in the status bar.

   http://docs.coronalabs.com/daily/api/library/system/scheduleNotification.html

Android does not automatically consolidate notifications into a single notification like iOS does.  On Android, status bar notifications are managed by the app and not the operating system.  So, the only solution I can think of is for you to remove all notifications and then add then schedule a local notification set to current time.

You can remove all notifications from the status bar by calling system.cancelNotification() without any arguments.

   http://docs.coronalabs.com/daily/api/library/system/cancelNotification.html

You can then call system.scheduleNotification() to create your own consolidated notification in the status bar.

   http://docs.coronalabs.com/daily/api/library/system/scheduleNotification.html

@Joshua, thanks for the reply, and sorry for the delay! Now back to this issue… How would I gather the number of notifications that are currently available in Android? with IOS I can call:

native.getProperty("applicationIconBadgeNumber")

I ask this because when I call system.scheduleNotification() I would want to show how many messages are currently available/stacked.

Unfortunatelly, it will need tweaks at lower level then Corona api. As far as I remember from experience, Corona only reads one notification at once (when opems via notification).

However, if it’s enough, you can set parameter ‘collapse_key’ of push notificatio on server side. When user is idle (not receiving notifications) and multiple of them are waiting on google servers then this key is used to collapse them to one by last one received by googlr server.

My solution assumes that your app is sending the badge count back to your server, which I believe you have to do anyways on iOS.  The reason is because iOS makes you set the total badge count with the remote/push notification.  That is, you can’t set the badge number you want to “add” to the total badge count on the local app.  iOS doesn’t work that way.  Apple expects your server to know the total app badge count on the server side.  That said, if you’re using a 3rd party push notification service, then they may be hiding this detail from you to make it easier to use.

@Joshua I see exactly what you’re saying and yes pushWoosh manages ios badge count. However, I can implement the same functionality w/ Parse for Android ( one problem solved! ) except now the ONLY thing still blocking me from doing that, is that once the app is suspended (not closed) corona no longer controls notifications via any listeners… or in other words, the app has to be actively opened/being used for this method to work.

How can i make this functionality work with the app being suspended?

Oh bummer.  Good point.  I can only think of 1 solution which can only be done via Corona Enterprise in Java.
 
You would have to replace our “GoogleCloudMessagingBroadcastReceiver” with your own BroadcastReceiver derived class.  This way, you can intercept Google’s push notifications when your app is in the background or when it’s not even running.  That is, if your app is not running, the Android OS will launch your app in the background and call this BroadcastReceiver.  You can then handle notification first and then pass it to Corona’s notification class to do its default handling.
 
First, create your BroadcastReceiver like this…

package your.package.name; import com.ansca.corona.notifications; public class MyBroadcastReceiver extends android.content.BroadcastReceiver { @Override public void onReceive(android.content.Context context, android.content.Intent intent) { // Fetch the action name from the intent. String actionName = intent.getAction(); if ((actionName == null) || (actionName.length() \<= 0)) { return; } // You might want to send the notification to Corona first to do its default handling. // Note: This Corona API is not public, which is why it must be called via reflection. // Since it's not public, we may change it in the future. com.ansca.corona.notifications.GoogleCloudMessagingServices gcmServices; gcmServices = new GoogleCloudMessagingServices(context); try { // Find a private method named process() in Corona's GCM class. // As an optimization, you should only fetch this method once. java.lang.reflect.Method[] methods = gcmServices.getClass().getDeclaredMethods(); for (java.lang.reflect.Method method : methods) { if (method.getName().equals("process")) { method.invoke(gcmServices, new Object[] { intent }); } } } catch (Exception ex) { } // Now it's your turn to handle the received notification. if (actionName.equals("com.google.android.c2dm.intent.RECEIVE")) { String messageTypeName = intent.getStringExtra("message\_type"); if ((messageTypeName != null) && (messageTypeName.length() \> 0)) { // This is not your push notification. It is a special message from Google. if (messageTypeName.equals("deleted\_messages")) { // Google Cloud Messaging has deleted all of your notifications. } else { // Some other special message was received from Google. } } else { // This is your push notification message. } } } }

 
Next, you need to modify your AndroidManifest.xml file and replace our GoogleCloudMessagingBroadcastReceiver with the one you created, like the class up above.  This way, the operating system will call your receiver instead of ours.
 
Anyways, I hope this helps.
Just note that I haven’t tried compiling the above code.  So, hopefully I didn’t make any stupid mistakes.  :slight_smile:

Joshua, thank you so much for your help and this head start! I am going to try to implement this tonight! I’ll keep you posted, again, thanks! <3

eja, I forgot to show you how to remove notifications from the status bar while your app is in the background… because our Lua API is not accessible while the app is suspended.  You’ll need to use some more of our private Corona APIs to remove the notification if you want to consolidate them into one group.

// Create the interface to Corona's notification system. // Note that all of this object's methods are thread safe. com.ansca.corona.notifications.NotificationServices notificationServices; notificationServices = new com.ansca.corona.notifications.NotificationServices(context); // This method removes all local and remote notifications. // This even removes scheduled notifications that are not in the status bar yet. notificationServices.removeAll(); // If you don't want to remove scheduled notifications and notifications posted in // the status bar, then you need to do the following instead. for (com.ansca.corona.notifications.StatusBarNotificationSettings settings : notificationServices.fetchStatusBarNotifications()) { notificationServices.removeById(settings.getid()); }

Just be warned that the above is Corona’s private APIs and may change in the future… but odds are we won’t because we’re pretty satisfied with how it works.  Also, if there is enough demand for it, we can work on making our Java notification classes/APIs public in the future.  We coded it with that in mind since Android’s notification framework is quite extensible compared to iOS.

Oh, and another warning.  If you post your own notification to the status bar via Google’s Android APIs, then you should know that Android will forget everything that was posted when restarting your application process or rebooting your device.  It’s up to the app developer to restore notifications in the status bar.  Typically by saving that information to file.  Corona does this automatically with the notifications it posts, but only supports simple status bar notifications.  Nothing is ever easy in the Android world, eh?

Anyways, I hope the above helps you out.
 

@Joshua, thanks for the reply, and sorry for the delay! Now back to this issue… How would I gather the number of notifications that are currently available in Android? with IOS I can call:

native.getProperty("applicationIconBadgeNumber")

I ask this because when I call system.scheduleNotification() I would want to show how many messages are currently available/stacked.

Unfortunatelly, it will need tweaks at lower level then Corona api. As far as I remember from experience, Corona only reads one notification at once (when opems via notification).

However, if it’s enough, you can set parameter ‘collapse_key’ of push notificatio on server side. When user is idle (not receiving notifications) and multiple of them are waiting on google servers then this key is used to collapse them to one by last one received by googlr server.

My solution assumes that your app is sending the badge count back to your server, which I believe you have to do anyways on iOS.  The reason is because iOS makes you set the total badge count with the remote/push notification.  That is, you can’t set the badge number you want to “add” to the total badge count on the local app.  iOS doesn’t work that way.  Apple expects your server to know the total app badge count on the server side.  That said, if you’re using a 3rd party push notification service, then they may be hiding this detail from you to make it easier to use.

@Joshua I see exactly what you’re saying and yes pushWoosh manages ios badge count. However, I can implement the same functionality w/ Parse for Android ( one problem solved! ) except now the ONLY thing still blocking me from doing that, is that once the app is suspended (not closed) corona no longer controls notifications via any listeners… or in other words, the app has to be actively opened/being used for this method to work.

How can i make this functionality work with the app being suspended?

Oh bummer.  Good point.  I can only think of 1 solution which can only be done via Corona Enterprise in Java.
 
You would have to replace our “GoogleCloudMessagingBroadcastReceiver” with your own BroadcastReceiver derived class.  This way, you can intercept Google’s push notifications when your app is in the background or when it’s not even running.  That is, if your app is not running, the Android OS will launch your app in the background and call this BroadcastReceiver.  You can then handle notification first and then pass it to Corona’s notification class to do its default handling.
 
First, create your BroadcastReceiver like this…

package your.package.name; import com.ansca.corona.notifications; public class MyBroadcastReceiver extends android.content.BroadcastReceiver { @Override public void onReceive(android.content.Context context, android.content.Intent intent) { // Fetch the action name from the intent. String actionName = intent.getAction(); if ((actionName == null) || (actionName.length() \<= 0)) { return; } // You might want to send the notification to Corona first to do its default handling. // Note: This Corona API is not public, which is why it must be called via reflection. // Since it's not public, we may change it in the future. com.ansca.corona.notifications.GoogleCloudMessagingServices gcmServices; gcmServices = new GoogleCloudMessagingServices(context); try { // Find a private method named process() in Corona's GCM class. // As an optimization, you should only fetch this method once. java.lang.reflect.Method[] methods = gcmServices.getClass().getDeclaredMethods(); for (java.lang.reflect.Method method : methods) { if (method.getName().equals("process")) { method.invoke(gcmServices, new Object[] { intent }); } } } catch (Exception ex) { } // Now it's your turn to handle the received notification. if (actionName.equals("com.google.android.c2dm.intent.RECEIVE")) { String messageTypeName = intent.getStringExtra("message\_type"); if ((messageTypeName != null) && (messageTypeName.length() \> 0)) { // This is not your push notification. It is a special message from Google. if (messageTypeName.equals("deleted\_messages")) { // Google Cloud Messaging has deleted all of your notifications. } else { // Some other special message was received from Google. } } else { // This is your push notification message. } } } }

 
Next, you need to modify your AndroidManifest.xml file and replace our GoogleCloudMessagingBroadcastReceiver with the one you created, like the class up above.  This way, the operating system will call your receiver instead of ours.
 
Anyways, I hope this helps.
Just note that I haven’t tried compiling the above code.  So, hopefully I didn’t make any stupid mistakes.  :slight_smile:

Joshua, thank you so much for your help and this head start! I am going to try to implement this tonight! I’ll keep you posted, again, thanks! <3

eja, I forgot to show you how to remove notifications from the status bar while your app is in the background… because our Lua API is not accessible while the app is suspended.  You’ll need to use some more of our private Corona APIs to remove the notification if you want to consolidate them into one group.

// Create the interface to Corona's notification system. // Note that all of this object's methods are thread safe. com.ansca.corona.notifications.NotificationServices notificationServices; notificationServices = new com.ansca.corona.notifications.NotificationServices(context); // This method removes all local and remote notifications. // This even removes scheduled notifications that are not in the status bar yet. notificationServices.removeAll(); // If you don't want to remove scheduled notifications and notifications posted in // the status bar, then you need to do the following instead. for (com.ansca.corona.notifications.StatusBarNotificationSettings settings : notificationServices.fetchStatusBarNotifications()) { notificationServices.removeById(settings.getid()); }

Just be warned that the above is Corona’s private APIs and may change in the future… but odds are we won’t because we’re pretty satisfied with how it works.  Also, if there is enough demand for it, we can work on making our Java notification classes/APIs public in the future.  We coded it with that in mind since Android’s notification framework is quite extensible compared to iOS.

Oh, and another warning.  If you post your own notification to the status bar via Google’s Android APIs, then you should know that Android will forget everything that was posted when restarting your application process or rebooting your device.  It’s up to the app developer to restore notifications in the status bar.  Typically by saving that information to file.  Corona does this automatically with the notifications it posts, but only supports simple status bar notifications.  Nothing is ever easy in the Android world, eh?

Anyways, I hope the above helps you out.