How to intercept Stacked notifications in Android - android

I am well familiar with the concept of stacked notification .
The mobile doesn't show non-summary notifications if there is a corresponding summary notification. But if there is no summary notification, non-summary notifications are displayed
I am listening to every notification posted by NotificationListenerService introduced in Kitkat. I intercept and display every notification text as they arrive.
Problem is when stacked notifications arrive, I get callbacks for both groupSummary and non-summary notifications. If I have to decide if a non-summary should be displayed, I have to check every other notification for a summary.
How do I replicate the behaviour of mobile without going through the list of all present notifications repeatedly, that is, in less than O(n^2) complexity? Or does Android source code also do it the same complex way?

I devised a method myself with complexity < O(n^2). Guess I didn't think about using better data structures. Here's the function . Feel free to point out mistakes if any.
private ArrayList<StatusBarNotification> cleanseNonSummary(ArrayList<StatusBarNotification> notifications) throws Exception{
Set<String> groupSet = new HashSet<>();
//first run : add all summary notification keys to unique set
for(StatusBarNotification sbn : notifications){
if(NotificationCompat.isGroupSummary(sbn.getNotification()))
groupSet.add(NotificationCompat.getGroup(sbn.getNotification()));
}
//second run : remove all non summary notifications whose key matches with set elements
for(int i=0; i<notifications.size(); i++) {
StatusBarNotification sbn = notifications.get(i);
if (!NotificationCompat.isGroupSummary(sbn.getNotification())) {
String groupId = NotificationCompat.getGroup(sbn.getNotification());
if (groupId != null && groupSet.contains(groupId))
notifications.remove(i--);
//decrement counter if an element is removed
}
}
return notifications;
}

Related

Retrieve message from a notification push

This push notification is used to notify when a new chat message is available. I want to do like Instagram, that is to say, the message into this notification is updated at each new income message received, until the user open the chat.
So, how can I retrieve the message for this specific notification? Is it possible, or I have to save (in cache) the latest messages... ?
Thank you very much
I suggest saving messages in the database, and then in the function that sends notifications, get messages (probably recent unread ones - I don't know what your logic looks like in this case).
If there are more than one, use InboxStyle():
val otherMessagesToShow = getMostRecentUnreadMessages()
if(otherMessagesToShow.size > 1) {
val style = NotificationCompat.InboxStyle()
otherMessagesToShow.forEach { style.addLine(it) }
builder.setStyle(style)
builder.setNumber(otherMessagesToShow.size)
}
Finally, update the existing one (passing the same notificationID):
notificationManager.notify(notificationId, builder.build())

Android notification append content on update

I have made an android app (Android Studio / Java) that checks a website for content and stores it in an sqlite DB. If new content is fetched that is not stored in DB, it shows a notification with the new content for user to notice.
That's working fine, although if user does not read/open/dismiss that notification, the next notification will update current one and replace its content with new data. This is wanted behavior, because I don't want the user to receive many notifications for the same thing, so I'm using the same notification id.
This introduces a problem though, if user checks the notification now, he will see the second fetched data, but won't be aware of the existence of the first fetched data.
So, what I'm trying to do is to append to the notification's content, so that both first and second fetched data are shown.
I tried the "inboxStyle" notifications that allow for new lines to be added, but it seems to be working only for setting many lines at the time notification is created and not for appending lines to an existing notifications.
I know that I can do that by storing what user has seen and what not, whether a notification was opened, etc, but this seems too much hassle for a simple thing, there must be an easier way to achieve it.
The expected behavior would be to either be able to append the message of existing notifications, or be able to fetch the message of an existing notification (by id) and then manually append to it and push the updated notification.
If that's not clear enough, the expected outcome is:
Issue the first notification with message "Test message 1"
Issue second notification using the same notification-id with message "Test message 2" that would NOT overwrite "Test message 1" but rather keep that message and append to it, so that the notification's message would now be "Test message 1 {newline-here} Test message 2" (or even better reversed so that the last message is shown on top).
Thank you in advance!
I was looking for a solution myself. I managed to do something that works but I'm quite sure there are other elegant solutions : I'm checking whether or not similar notification has been displayed. If so, I get the previous content and append it to the new notification content before publishing.
First, make sure that the notifications you want to assemble have the same uniqueID
This way, when you receive your 2nd, 3rd notification, you can easily match the one you are creating with the ones already displayed.
Note : This code works only on API 23 and higher.
String message = null;
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
StatusBarNotification[] notifications = mNotificationManager.getActiveNotifications();
for (StatusBarNotification notification: notifications) {
if (notification.getId() == uniqueID) {
// You have a match
Bundle extras = notification.getNotification().extras;
message = extras.getCharSequence(Notification.EXTRA_TEXT).toString();
break;
}
}
}
The easy part : Now that you have the previous notification text, you have to append it to the new notification text before publishing
String newMessage = message + remoteMessage.getData.get("text");
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(getApplicationContext(),
channelID)
.setStyle(new NotificationCompat.BigTextStyle().bigText(newMessage))
.setContentTitle("Title")
.setContentText(notification.getMessage())
.setAutoCancel(true);

FCM from multiple senders but within the same app

send multiple notifications using FCM, but within the same server side, saying that there is multiple notification types, probably with different data payloads and different notification titles, i want the the notification manager to be able to differentiate between each notification on the client side and send them to different Notification Channels?
EDIT
I tried setting notification_id and it does not work.
EDIT:
I can add a Data payload and restrict the notification in one of my classes and add a switch statement which will divide according to my Notification but i need to handle the data in the background and not foreground.
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
notificationSwitch(remoteMessage);
}
private void notificationSwitch(RemoteMessage remoteMessage) {
RemoteMessage.Notification notification = remoteMessage.getNotification();
if (notification.getTitle().equals("TypeOne")){
TypeOneSendNotification(remoteMessage);
}
else{
TypeTwosendNotification(remoteMessage);
}
}
//Ofcourse we are able to switch based on the title, or different data payloads
EDIT:
I converted into a data payload and edited the notification title to be able to switch the above edit
Create the notification_key, which identifies the device group by mapping a particular group (typically a user) to all of the group's associated registration tokens. You can create notification keys on the app server or on Android client apps.
please check this link
https://firebase.google.com/docs/cloud-messaging/android/device-group
I got this working by implementing a switch statement on the title is merely a hack but it definetly works
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
notificationSwitch(remoteMessage);
}
and in my notification switch function as i already have remoteMessage as an argument i will just implement my senders.
private void notificationSwitch(RemoteMessage remoteMessage) {
RemoteMessage.Notification notification = remoteMessage.getNotification();
if(notification.getTitle() != null){
switch (notification.getTitle()) {
case "SenderOne":
SenderOneSendNotification(remoteMessage);
break;
case "SenderTwo":
SenderTwoSendNotification(remoteMessage);
break;
case "SenderThree":
SenderThreeSendNotification(remoteMessage);
break;
case "SenderFour":
SenderFourSendNotificaation(remoteMessage);
break;
default:
DefaultSender(remoteMessage);
break;
}
}
Answering the question in the title: FCM from multiple senders but within the same app
If sender == Firebase Project then I don't think it is possible.
If sender == a client inside the same Firebase Project (like an iOS app, multiple servers, another Android app), then you need to create those apps inside your Firebase Project (for iOS and Android apps) and use the server key (for the servers)
If sender == function (like "Update Entity A", "show notification for promotion", etc), then you can use the data field inside the notification. We usually add an action field inside the data field. Both the receiver (iOS or Android app) and the sender (usually a server, but can also be a mobile app) know the list of possible actions. Receivers know what to do when they receive them (if app receives "Update Entity A", then it starts the EntityAUpdateService).

Is it possible to cancel all notifications that have a certain tag?

I'm making an android app and I would like to cancel all notifications that have a certain tag.
Right now it only seems possible to cancel notifications by their id (int id) or by both their ids and tags.
mNotificationManager.cancel(int id);
or
mNotificationManager.cancel(String tag, int id);
I want to be able to cancel all notifications of String tag regardless of int id.
Is this possible?
No, it isn't. The way Notification is set up, id is the primary key. You can add a subkey with tag, and cancel an individual (tag, id) pair that way, but you can't cancel based on tag alone. Really I'm not sure why they added a tag parameter, as it seems rather redundnt, except that possibly a string parameter makes for easier debugging.
Seems possible if you use notification groups. Cancelling the group summary notification seems to cancel the entire group.
On Android using API >= 23 you can do something like this to remove a group of notifications:
for (StatusBarNotification statusBarNotification : mNotificationManager.getActiveNotifications()) {
if (KEY_MESSAGE_GROUP.equals(statusBarNotification.getGroupKey())) {
mNotificationManager.cancel(statusBarNotification.getId());
}
}
Yes , it is possible
Get all active notification build by your app using mNotificationManager.getActiveNotifications()
Filter Notification based on TAG.
Cancel those notifications.
Try below code
void cancelGivenTagNotification(String tag){
StatusBarNotification notiList[] = notificationManager.getActiveNotifications();
for(int i=0;i<notiList.length;i++){
if(notiList[i].getTag().equals(tag)){
int notiId = notiList[i].getId();
notificationManager.cancel(tag,notiId);
}
}
}

Update Inbox style Notification Like gmail

I want to use inbox style notification, and once notification is still showing in notification status bar then it should append to the existing notification like gmail.
But I don't know how to detect that notification is showing in the status bar, Is there any way to get the notification id
Is ther any way to know that notification generated by my application is already displayed and just update it with +1 more(Inbox style)
What I thought :-
I thought I can store the notification id in shared prefrences and I will pass the pending intent which will start a intent service which will clear the notification is stored in shared prefrences and during notification posting I will check the notification id in prefrences If it is not cleared then I will update it
Does any one have any better idea ?
Do not save it in the preferences. Just use a constant value as the Notification ID.
static final int MY_NOTIFICATION_ID = 1;
As the ID's are unique per application you can use the number you want. Then use it when notifying the NotifiactionManager. Use the same code to update your notifiaction.
NotificationManager.notify(MY_NOTIFICATION_ID , notification);
I think you should have everything on this link: http://developer.android.com/training/notify-user/managing.html
It like you said, you need to know the notification id in order to update it. Using Shared Preferences is an easy way to do it since it only a few lines of code to do everything,
Your idea good, clear the preferences file when the user clicks on the notification.
you can use the static variables to keep the track of notification ID and for appending the notification i mean for stacked notification also you can keep a number in static variables...
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(this).setSmallIcon(R.drawable.ic_launcher)
.setContentTitle(notificationTitle).setContentText(contentText);
NotificationCompat.InboxStyle inboxStyle = new NotificationCompat.InboxStyle();
inboxStyle.setBigContentTitle(notificationTitle + " Details");
// Moves events into the big view
for (int i = 0; i < extrasList.size(); i++) {
inboxStyle.addLine(extrasList.get(i).getString(mString));
}
if (number >= 8) {
inboxStyle.setSummaryText("+" + (number - 7) + " more reply(s)");
} else {
inboxStyle.setSummaryText(contentText);
}
mBuilder.setStyle(inboxStyle);
mBuilder.setNumber(number);
mBuilder.setContentIntent(contentIntent);
mBuilder.setAutoCancel(true);
mNotificationManager.notify(Integer.parseInt(type), mBuilder.build());

Categories

Resources