I have an app where the user can receive multiple notifications for things they need to do. The user has a choice of making some of these notifications persistent (which I achieve by calling NotificationCompat.Builder.setOngoing). At least on my version of Android which is Nougat, when more than three notifications are posted by my app they get bundled together into one notification, which makes all of them dismissible to the user in one swipe. This makes the previously persistent notifications no longer persistent. Is there a way to programmatically instruct Android not to bundle my notifications?
This is the code I use to build the notification and display it:
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(eventName + " " + notificationText)
.setDefaults(Notification.DEFAULT_ALL)
.setOnlyAlertOnce(true)
.setContentIntent(eventListPendingIntent);
if (goalInfo.goal.persistNotification) {
builder.setOngoing(true);
} else {
builder.setAutoCancel(true);
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(eventType.value(), builder.build());
Thanks, Nir
As per Google docs, notifications from the same app would be bundled automatically -
Note: If the same app sends four or more notifications and does not
specify a grouping, the system automatically groups them together.
So in your case, what you can do is , instead of system applying the default grouping, you can separate your notifications into two groups using a separate group key for the persistent notifications and one for the non-persistent ones.
Check the Google docs. The method Builder.setGroup() on NotificationBuilderCompat takes a string parameter which is the key.
There is a related method Builder.setGroupSummary which you should call on your Builder
Hope this is clear.
Related
As of now, I am using Firebase Cloud Messaging as my app's notification system. From my understanding, even the largest companies use GCM, which is now being replaced with FCM. I am stuck, however, with the limitations imposed by sending things as a "notification" pay load.
Firebase recieves data messages in OnMessageRecieved, and I am able to get my exact desired behavior through using this. However, for the past three months I noticed that my app's notifications were simply not working because data payloads aren't received when the app is in the background/ inactive. This is very frustrating as the only workaround I have found to actually send notifications that alert users is through sending notification payloads.
I don't know how to get my desired behavior with the notification payload as I have been with data payload, but I realize that having notifications display perfectly when the app is in the foreground is pointless if they don't display at all when the app is in the background.
What I'm wondering, and what I'd really appreciate guidance on, is if somebody could recommend a way to display notifications with my desired style rather than the default Firebase notification style. Just to elaborate, I currently have a fully functional system of allowing users to respond to messages through the notification and without opening the app, but only through the data payload.
I know there is a way to somehow send notifications in a customized fashion (adding intents, buttons, etc) when the app is in the background or not running because this is done by Facebook, WhatsApp, and many other apps on the market. I am aware of something called AlarmManagers, but unsure of how I could use them to get my desired behavior, or if this is what people use anyways.
Thank you, and please let me know if there is a way to customize the payload when the app is in the background or inactive, through onMessagesRecieved or any other methods. As of now, the only other solution would be to somehow send the message's contents to a service, but I've faced issues where services could not display notifications in the background without crashing the app and without being very hacky.
The only way I came up with is to send the data payload only, which should be delivered to the onMessageReceived callback despite the app's status (foreground/background).
Then you put all required fields to the data payload and build a notification from it. Here the map "data" is from remoteMessage.getData()
private void sendNotification(Map<String, String> data) {
String body = Optional.ofNullable(data.get("body")).orElse("");
if (body.isEmpty()) {
return;
}
Intent intent = new Intent(this, MainActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent resultPendingIntent = PendingIntent.getActivity(this, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);
Uri sound = getSoundUri(Optional.ofNullable(data.get("sound")).orElse(""));
String defaultChannel = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
? NotificationChannel.DEFAULT_CHANNEL_ID
: DEFAULT_CHANNEL_ID;
String channel = Optional.ofNullable(data.get("android_channel_id")).orElse(defaultChannel);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, channel)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle(getString(R.string.app_name))
.setContentText(body)
.setAutoCancel(true)
.setWhen(System.currentTimeMillis())
.setShowWhen(true)
.setContentIntent(resultPendingIntent);
if (sound != null)
notificationBuilder.setSound(sound);
NotificationManager notificationManager =
(NotificationManager) getSystemService(NOTIFICATION_SERVICE);
if (notificationManager != null)
notificationManager.notify(0, notificationBuilder.build());
}
So I have a timer using AlarmManager and once it hits 0 I want it to send a notification with various attributes depending on what the user chooses (vibrate or not, play sound or not, show text or not, show... rectangle thingy in the drop-down tray whatever it's called, etc).
I am not sure what the expected class to use here is since it's immediate, i.e. it's after the alarm manager has already hit 0 and I am now in the onReceive() method of my broadcast receiver, so I don't think I need to use a PendingIntent at this point.
Do I use NotificationCompat.Builder? Will it do everything I need? And if so do I use the support v4 or v7 version?
Trying this:
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(c)
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(c.getResources(), R.mipmap.ic_launcher))
.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION))
.setContentText("This text should be in notification drawer!");
NotificationManager notificationManager = (NotificationManager) c.getSystemService(NOTIFICATION_SERVICE);
notificationManager.notify(1, notificationBuilder.build());
Toast.makeText(c, "Toast text!", Toast.LENGTH_LONG).show();
As per discussion in the comments -
Yes NotificationCompat.Builder will do all of the above things you need.
.build is enough to send notification instantly. And if you want to set a specific time you can use .setWhen as well. You can find all methods related to action that you need to do here - Notification Developer Guide
I feel like this should be trivial but I can't seem to make a notification show up on the phone's screen - it only shows up in the status bar at the top.
For an example of what I want to do, here's how Facebook Messenger shows up on the screen when you receive a message.
Whenever I send a notification, all it does is show the little icon in the status bar - even if I set the priority to PRIORITY_MAX. Is there another setting I need to do to make it show on screen instead of just status bar?
The Notification display code:
PendingIntent contentIntent = PendingIntent.getActivity(context, nextId++, intent, PendingIntent.FLAG_CANCEL_CURRENT);
Notification.Builder builder = new Notification.Builder(context)
.setContentTitle(title)
.setContentText(description)
.setContentIntent(contentIntent)
.setSmallIcon(R.drawable.ic_stat_notification)
.setLargeIcon(largeIcon)
.setPriority(Notification.PRIORITY_DEFAULT)
.setAutoCancel(true)
.setDefaults(Notification.DEFAULT_ALL);
if (android.os.Build.VERSION.SDK_INT >= 21) {
builder.setColor(context.getResources().getColor(R.color.orange_500))
.setVisibility(Notification.VISIBILITY_PUBLIC);
}
Notification notification = builder.build();
notificationManager.notify(id, notification);
All things considered, it's a really good idea to use NotificationCompat.Builder over Notification.Builder, let alone creating a Notification manually. It gives you nice backwards compatibility with graceful degradation (all the way back to API Level 4, otherwise known as "gadzooks, that's old"). AFAIK, it's the only way to get some of the Android Wear stuff going, when used in concert with NotificationManagerCompat. And, in this case, it seems to be happier with the newer Android 5.0+ features.
In this case, setPriority(NotificationCompat.PRIORITY_HIGH) on a NotificationCompat.Builder, used with NotificationManagerCompat, will give you the heads-up notification on Android 5.0+.
Another point, make sure the 'importance' of the notification channel you have set up for your notification is set to NotificationManager.IMPORTANCE_HIGH.
This configures how visually intrusive notifications posted to this channel are and 'high' will allow it to peek. If you have this set to NotificationManager.IMPORTANCE_DEFAULT then it won't!
Bear in mind when configuring a notification channel, once the code has ran on your device, you won't be able to alter this again. So if you need to change the importance you will need to uninstall the app and then re-run and you should see the notification on your screen!
If I create an Notification I can add three Actions. Each action can also be invoked on a watch. Is it possible to make some of this actions not available on an Android Wear Watch?
Whenever you use addAction() in NotificationCompat.WearableExtender, you are not actually extending the actions (despite the name), but rather separating them into two lists, one for the phone, and one for the wearable.
The actions added on the original NotificationCompat.Builder are shown on the handheld.
The actions added on the WearableExtender are shown on the Android Wear device.
See Specifying Wearable-only Actions:
If you want the actions available on the wearable to be different from
those on the handheld, then use WearableExtender.addAction(). Once you
add an action with this method, the wearable does not display any
other actions added with NotificationCompat.Builder.addAction(). That
is, only the actions added with WearableExtender.addAction() appear on
the wearable and they do not appear on the handheld.
Therefore, to have handheld-only actions, add them before creating the extender. And To have wearable-only actions, add them on the extender. If you use an extender and you want to have repeated actions in both devices, you must add them in both (though maybe there is an option to copy them?).
For example:
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("The title")
.setContentText("This is the text")
.setContentIntent(pendingIntent);
// Handheld-only actions.
notificationBuilder.addAction(drawable1, "In Both", pendingIntent);
notificationBuilder.addAction(drawable2, "Only in phone", pendingIntent);
// Wearable-only actions.
NotificationCompat.WearableExtender wearableExtender = new NotificationCompat.WearableExtender();
wearableExtender.addAction(new NotificationCompat.Action.Builder(drawable2, "In Both", pendingIntent).build());
wearableExtender.addAction(new NotificationCompat.Action.Builder(drawable3, "Only in wearable", pendingIntent).build());
notificationBuilder.extend(wearableExtender);
// Build and show notification.
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
notificationManager.notify(notificationId, notificationBuilder.build());
Also
If you create a WearableExtender but don't add any actions into it, then the actions from the original notification are used.
The "content intent" from the handheld seems to always be present on the watch, with the "Open on Phone" text. I haven't found a way to disable this for the watch only.
I'm trying to put my notification on top of notification area.
A solution is to set the parameter "when" to my notification object with a future time like:
notification.when = System.currentTimeMills()*2;
The code that I'm using in this:
long timeNotification = System.currentTimeMillis()*2;
Notification notification = new Notification(statusIcon,c.getResources().getString(R.string.app_name),timeNotification);
notification.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR;
notification.when = timeNotification;
notification.priority = Notification.PRIORITY_MAX;
but some apps (like Facebook) are able to put a simple notification with their current time over mine.
If I refresh my notification it remains under these ones.
What parameters I have to set to put my Notification to the top of the notifications area?
You should do this. Other answers seem outdated.
NotificationCompat.Builder mBuilder =
(NotificationCompat.Builder) new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.some_small_icon)
.setContentTitle("Title")
.setContentText("This is a test notification with MAX priority")
.setPriority(Notification.PRIORITY_MAX);
setPriority(Notification.PRIORITY_MAX) is important. It can also be replaced with any of the following as per requirement.
Different Priority Levels Info:
PRIORITY_MAX --
Use for critical and urgent notifications that alert the user to a condition that is time-critical or needs to be resolved before they can continue with a particular task.
PRIORITY_HIGH --
Use primarily for important communication, such as message or chat events with content that is particularly interesting for the user. High-priority notifications trigger the heads-up notification display.
PRIORITY_DEFAULT --
Use for all notifications that don't fall into any of the other priorities described here.
PRIORITY_LOW --
Use for notifications that you want the user to be informed about, but that are less urgent. Low-priority notifications tend to show up at the bottom of the list, which makes them a good choice for things like public or undirected social updates: The user has asked to be notified about them, but these notifications should never take precedence over urgent or direct communication.
PRIORITY_MIN --
Use for contextual or background information such as weather information or contextual location information. Minimum-priority notifications do not appear in the status bar. The user discovers them on expanding the notification shade.
For more details check the following link:
http://developer.android.com/design/patterns/notifications.html#correctly_set_and_manage_notification_priority
You can make your notification Ongoing, when it will appear higher then other usual notification. But in this case user would not be able to clear it manually.
In order to do this set flags to your Notification object:
notif.flags = Notification.FLAG_ONGOING_EVENT | Notification.FLAG_NO_CLEAR
Try setting priority of the notification to high
documentation > Notification Priority
Also check this question may it could help you Pin Notification to top of notification area
Please note that if you want a "heads-up" notification i.e., one that displays over the top of the current user window you must have the following set in your builder:
setDefaults(NotificationCompat.DEFAULT_VIBRATE)
The reference is in the javadoc:
A notification that vibrates is more likely to be presented as a heads-up notification, on some platforms.
Complete example for a heads-up notification:
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(context)
.setSmallIcon(R.drawable.some_small_icon)
.setContentTitle("Title")
.setContentText("This is a test notification with MAX priority")
.setPriority(Notification.PRIORITY_MAX)
.setDefaults(NotificationCompat.DEFAULT_VIBRATE);