I am posting a notification for a background task and bring it to foreground with startForeground with a visible ongoing notification. When it completes, I replace it with a cancellable notification using the same notification id and the same channel I created with setShowBadge(false).
The scenario works correctly: It does not show badge for the ongoing task and it is successfully replaced with the non-ongoing version. Except, setShowBadge(false) does not work when I use it for the cancellable notification.
I checked the official sample and many examples and I also checked my code, I could not find any problems. So, there has to be an exceptional situation here. What can be the problem? What am I possibly missing here?
It depends on default launcher in use. Stock launcher will work as expected but some launchers have their own implementation of Notification badges and they've been using it since way before badges were supported officially. For those launchers, this flag won't work.
Even if the launchers use notification badges from channels, they might not care about this flag (like in your case). I would say try calling setNumber(0) and hope that it works.
mNotificationBuilder.setNumber(0)
Related
I am currently working on transitioning an application to Android O, and I am currently working on notification channels.
I have made different channels with different importance levels and since the application has a foreground service that has to run at all times until we transition to a new architecture (more push oriented), I thought about putting that notification in a channel that has its importance set as IMPORTANCE_MIN, so that it is there, but it doesn't bother the user, and doesn't place an icon in the status bar.
However, when I do that, and I put my application in the background (with Home or Back buttons), I get an Android System notification telling me that my app is running in the background, like so:
If I change my channel and make it use IMPORTANCE_LOW, the problem goes away, however, the notification is more prominent.
So, my question is - is it possible to do what I am trying at all? I get that the system would not allow the developers to do this, because if you have a foreground service, it should be visible to the user, but that's just a guess, and I found no documentation regarding this, and that's why I'm posting this question.
My second question is - prior to O, if you set the priority of your notification to PRIORITY_MIN, can you bind that notification to a service to make it a foreground service, or was that a no-go since always?
Edit: Confirmed that the Android System shows the notification for channels with importance IMPORTANCE_MIN (thanks, M66B), so the question that remains now is why? Does anyone know the reasoning behind this, or can find any documentation anywhere? Is this maybe a bug that should be reported to the tracker?
This behavior is now documented: https://developer.android.com/reference/android/app/NotificationManager.html#IMPORTANCE_MIN
Min notification importance: only shows in the shade, below the fold.
This should not be used with Service.startForeground since a
foreground service is supposed to be something the user cares about so
it does not make semantic sense to mark its notification as minimum
importance. If you do this as of Android version O, the system will
show a higher-priority notification about your app running in the
background.
And also here: https://material.io/guidelines/patterns/notifications.html#notifications-settings
In Android O, a channel’s default importance level for foreground
service notifications must be at least IMPORTANCE_LOW so that it shows
an icon in the status bar.
Channels using the less-prominent IMPORTANCE_MIN level will trigger an
extra notification from Android at IMPORTANCE_LOW, stating that the
app is using battery.
Sidenote:
This is a real pain for us, since prior to O we used to dynamically switch between PRIORITY_DEFAULT and PRIORITY_MIN when our foreground notification had no interesting information to present. With channels we can't change the IMPORTANCE dynamically anymore, and had to remove that feature.
Background
Ever since heads-up notifications appeared on Android, some people liked it for its quick handling, yet some hated it for showing on top of apps (especially games).
In order to show heads-up notifications, developers can use something like that:
final NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setContentTitle("aa").setContentText("bb").setTicker("cc")
.setColor(0xffff0000).setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher))
.setPriority(Notification.PRIORITY_HIGH);
if (Build.VERSION.SDK_INT >= 21)
builder.setVibrate(new long[0]);
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(1, builder.build());
Because of this, some apps came up with the idea to show ticker-text notifications that replace them somehow, just as it used to be before heads-up notifications:
https://play.google.com/store/apps/details?id=com.jamworks.noheadsup&hl=en
There are various scenarios where this could be useful. It could be, for example, useful in case of games, where full screen is used. That's because if the user is about to press the top area, and the heads-up notifications are shown, we would like to avoid accidental click on this notification.
The problem
Not only I can't find a way of how people did it, but it seems it doesn't work anymore on new versions of Android (tested on Android 7).
The only app I've found that blocks notification is this:
https://play.google.com/store/apps/details?id=com.aboutmycode.NotificationsOff&hl=en
yet it doesn't convert the heads-up notifications to "normal" ones. Instead, it just blocks them all. Plus it requires root, and seems to just change the settings of the notifications to "blocked" .
The question
Is it possible to temporarily block the heads up notifications (and yet convert them to ones without heads-up notifications ) ? If so, how?
Which restrictions does it have? Can it work without root? If it's possible with root, how? How does the "NotificationsOff" work?
Maybe this ability was possible before, but now it is not?
On Android 18+ there is a NotificationListenerService. This service gets notified when new notifications are shown. Then, I understand there are three ways to act:
Intercepting the notifications so they don't get displayed (not completely sure this can be done) Checked: if the NotificationListenerService doesn't call super.xxx when receiving a notification, the notification is also showed. So this method seems to not work.
Clearing notifications as they get posted. For this, you can use NotificationManager to either clear a given notification or clearAllNotifications Checked: it partially works to clear the notifications, but you still see the notification showing up and then it's not in the notification area (it's weird effect).
In API 21+ Lollipop it seems that you can override NotificationListenerService#getCurrentInterruptionFilter(). This method could return NotificationListenerService#INTERRUPTION_FILTER_NONE (or any other of the constants), (haven't tested, should be verified). Checked: NotificationListenerService#getCurrentInterruptionFilter() is final, so it cannot be overridden.
In API 23+ you can use both NotificationManager#setNotificationPolicy() and NotificationManager#setInterruptionFilter() (in that specific order) to control which notifications are shown to the user. Permissions are required for those APIs. Notice that this methods seem to be a convenience to be able to access the functionality, but skip implementing a complete NotificationListenerService. That's the only option that can work in a satisfying way
About NotificationListenerService, you can see the following samples in GitHub kpbird/NotificationListenerService-Example and in this post.
About NotificationManager, see additional information in this post in StackOverflow (specially interesting the highlighted comment) and in this post.
Example, tests and additional notes
I've uploaded the following repository to GitHub with an example based on kpbird's, to test all the assumptions and provide final conclusions.
Notice that the following steps to enable the permission for the app to be able to access the notifications must be followed in order for the app to function properly. This answer also provides a way to open System Settings in the correct section.
Also, for completeness, the following answer provides a way to check whether the permission is already granted or not.
Additional note: apparently first versions of Marshmallow have a bug where NotificationManager#setInterruptionFilter() doesn't work. See here and here.
Background
Android Lollipop (API 21) introduced a way to show notifications outside of the status bar (AKA "notifications bar"), so that the user can handle them right away. It's called "Heads-up notifications".
The trigger for showing them may vary between devices/roms/manufacturers.
The problem
Sometimes, showing such notifications can annoy users, and most of the times there are no settings for those cases.
If the user dismisses heads-up notifications, they won't show as a normal notification. There is no way to hide them and continue with what's on the screen. You can only wait (and it's quite a long time of waiting too).
In fact, there are multiple Google-Group issues that were opened about it, just because it can annoy people (link here and here).
What I've found
Starting with API 18, it is possible to listen to notifications events and even read them, by using "NotificationListenerService" and "StatusBarNotification" , and maybe other classes.
However, other than dismissing notifications (of other apps), I can't find any other action that can be done to them.
The question
Is it possible that in the lifetime of my app, I will be able to listen to notifications that are shown as heads-up, and put them back as a status-bar notifications?
Maybe even set a different timeout for them? or choose to convert them to normal status-bar notifications when they get dismissed?
Maybe before even doing those operations, I should ask: how can I know if a notification that I've found (of other apps) is showing as a heads-up notification ?
I don't know how to do implement this. But answering the "Is it possible that...?" question, yes, there are apps like this one that block/only show notifications in the notification bar.
I am writing an application where I am pushing notifications to the client from the server. If server pushes many notification messages to the user, I see that there are multiple app notification icons in the notification bar(where there are other icons such as battery, connectivity etc) are displayed.
I want to limit it one but I still want to retain notifications in the notification drawer(in pull down pane).
I tried canceling notificationManager.cancel(int id), but it removes notification from the the notification drawer along with notification bar. Is there any extra flag or any api to get around this?
Thanks
You can update the notification content. Here are the docs to do it http://developer.android.com/guide/topics/ui/notifiers/notifications.html#Updating
This is what the SMS/Whatsapp/gmail does. If there's only one message, they display it's content, otherwise they would display the amount of unread messages and or the number of people who wrote them. The point is that they only have one notification on the status bar, and they keep using the same one until the user goes in the app.
As has been pointed out, this is strictly speaking against the android design guidelines. However guidelines are not always right in every situation, and it seems to me that may be possible to do this, at least for some versions of Android.
In 4.4 and 6.0 (I didn't test other versions) some testing seems to indicate that if the notification priority is set to PRIORITY_MIN then the icon will not appear in the notification bar but it will appear in the drawer.
I do not know whether this behaviour is guaranteed though and the docs seem a bit vague. There is also an annoying consequence that the position of the notification in the drawer is affected by this, so this answer is not at all ideal.
I wish there were a better solution for people who actively choose to not follow the guidelines because of specific design requirements.
I am trying to make my Service running in foreground. I tried to use this example (please look for the section "Running a Service in the Foreground"), but startForeground() does not actually show my notification. And no exceptions is thrown. To make it shown, I need to use NotificationManager like here explained. With NotificationManager my notification works, but i'm not sure that my Service is foreground after this "silent" call to startForeground().
What can be wrong?
EDIT: I just tested this sample project that should demonstrate startForeground(), but it does not work! I use API v7.0, I tested it both on emulator and real device (SE Xperia Neo). Notification does not appear.
EDIT2: if i try to call setForeground() then i got a warning setForeground: ignoring old API call.
I also tried to use startForegroundCompat() as described here, but effect is absolutelly the same. I check if my service is foreground using ActivityManager.RunningServiceInfo as described here, and I see that my service is not foreground.
I just noticed that startForeground() doesn't show the notification icon if the id parameter is set to 0...
startForeground(0, notification); // Doesn't work...
startForeground(1, notification); // Works!!!
I hope that it could help someone stuck on this.
in addition to the best answer.
you should also check that have you called setSmallIcon.
On my android phone, I cannot get what I expected without calling setSmallIcon
Is your service a started service or a bound service? I had the same issue with a bound service, but starting the service before binding it allowed me to call startForeground(int, notification) with and have the notification show up.
This might be an old thread, but I'd like to add what I just learned which is not mentioned yet:
It is possible that a Service is still alive after stopSelf() is called because there are Activity that have bound to the Service. As a matter of fact, the startForeground() is just not going to show the notification nor giving any exception in this circumstance.
in my case there was no notification after startForeground(...) invoke because I used only .setSubText(...) for setting the message of it (because it is rendered with smaller font on most of devices). But some of devices Xiaomi Redmi Note 4 won't show any notification if You not set message by using .setContentText(...).
Hope that will help someone
DMitry. I have just suffered your problem and found the cause.
If your app is changing state of a COMPONENT PackageManager.setComponentEnabledSetting()) Android removes the service from foregraound and its notification icon.
Bug reported at Nov, 2011