How do some apps block/replace heads-up notifications? - android

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.

Related

What can be the reason behind the failure of setShowBadge(false)?

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)

Strange allow/deny question on Huawei 5.1 phone when showing notification

So it turns out that Huawei phones with 5.1 can't display MediaStyle notifications so while fixing that, I made a very simple notification test and I get a strange question asking Allow App Name to push messages to the notification panel.
I don't use push in any way, in fact the screenshot below is for an app that all it does is show a sample notification, nothing else.
How can I make it not show that?
This is the code:
Notification notification = new Notification.Builder(getApplicationContext())
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("Track title")
.setContentText("Artist - Album")
.setOngoing(true)
.addAction(R.drawable.ic_add_black_24dp, "fwd", pi)
.addAction(R.drawable.ic_android_black_24dp, "fwd", pi)
.addAction(R.drawable.ic_archive_black_24dp, "fwd", pi)
.addAction(R.drawable.ic_arrow_back_black_24dp, "fwd", pi)
.addAction(R.drawable.ic_aspect_ratio_black_24dp, "fwd", pi)
.addAction(R.drawable.ic_fast_forward_black_24dp, "fwd", pi)
.setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.vectors_525058875))
.setAutoCancel(false)
.build();
notificationManager.notify(300, notification);
This is the screenshot.
What am I doing wrong? I tried taking out all the actions, that didn't help. Took out title and context, that didn't help. Took out large icon, auto cancel, ongoing, etc, didn't help.
Please note that I am not using Push in any way and this doesn't seem to be related to that. Also I a using the support compat libraries to make my notification but on this example I didn't just to make sure that wasn't the issue.
Huawei's version of the Android OS has a custom feature that tries to spot apps doing annoying numbers of notifications.
Don't focus on the word "push". It doesn't mean "push notifications" in the technical sense of coming from the internet. It just is a verb, they could have said "allow app to create notifications" or "allow app to cause notifications" it's the same meaning.
Anyway, this is an OS feature, there is nothing you can do to avoid it except make sure you aren't spammy with your notifications. Unfortunately during development and testing you will often be triggering a lot of notifications, and the OS will detect your app is spammy. Don't worry about it. As long as your app works well for normal users it shouldn't happen.
It's Huawei customized Android OS feature. Long story short, you can't disable it.
I saw it a lot when I test my app. Huawei OS thinks your notification might annoy the end user(yourself, in this case) because it happened a lot.
You don't have to concern it😀
Your use deprecated constructor. Your must specify channel. Like this:
Notification.Builder builder = new NotificationCompat.Builder(context,"MyPerfectApplication")
Otherwise you use unknown chanel, possible you try to push in system channel.
it's indeed a custom check of EMUI, which enables the user to decide whether or not to have these custom notifications being pushed into the default notification channel, before a single one of these notifications had ever been displayed, when the first push is being attempted. it generally controls the notification settings of your app on Huawei devices, from within that notification panel. system & vendor applications are permitted to push notifications by default and therefore it won't ever ask the user for a double confirmation there. this has nothing to do with excessive notifications, because it is a precondition to even have these notifications pushed, no matter the amount.

Is it possible to put a foreground service notification in a notification channel with IMPORTANCE_MIN?

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.

Message center in Android

The Android app I'm developing interacts with a remote machine that may returns errors or have problems.
Currently I'm showing ugly popups at every warning or blocking error, but I wanted some sort of centralized notification center. I don't want to use normal Android notifications since the user has to leave the application.
I wanted some sort of badge indicating the number or warnings/errors that have happened until now and something that can resume what happened (like a listview with all the errors happened).
I'm wondering if that's the best approach to deal with this type of problem and/or if there are any public library out there that might solve my problem.
I've seen that Snackbar might be helpful for non blocking errors, and there are a lot of badge libraries, but still nothing for the "notification center".
If you are intending to "notify" users about progress, issues and other important messages. The logical place to do so would be using a Notification. You can also provide buttons in the notification that directs the user to conflict resolution.
Documentation about Notifications.
Official Documentation for creating Notifications.
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setSmallIcon(R.drawable.notification_icon)
.setContentTitle("My notification")
.setContentText("Hello World!");
Make sure that you are certain that your user actually cares about these messages (errors). Provide them a way to ignore them. Usually in the App settings.

Does NotificationCompat and NotificationManagerCompat have to be used for notifications to appear on a wearable?

I'm a bit confused by the documentation for wearable notifications.
If I have an existing app that is using Notification.Builder and NotificationManager.notify() will the notifications automatically also display on a paired wearable or does the app need to change to use NotificationCompat.Builder and NotificationManagerCompat.notify()?
If its not necessary to use the XXXCompat classes for notifications to appear on the wearable then is there any benefit/use in using them instead of the non Compat variants?
NotificationManagerCompat is required for all Wear specific functionality (anything added via a WearableExtender, a part of NotificationCompat.Builder) per delivering notifications:
If you use the framework's NotificationManager, some features from NotificationCompat.WearableExtender do not work, so make sure to use NotificationCompat.
However, basic notifications sent via NotificationManager will indeed be mirrored over the Android Wear devices without issues.
As CommonsWare alluded to in his comment, it is much, much easier to write Notifications that look good on all API versions by using NotificationCompat. This will become even more important when Android L comes out (where there are numerous Android L notification changes) which, unless you are targeting Android L+ devices only, you'll need to use NotificationCompat to access.

Categories

Resources