How do some apps block/replace heads-up notifications?
Asked Answered
D

1

9

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?

Dope answered 25/9, 2016 at 10:28 Comment(0)
C
9

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.

Child answered 11/10, 2016 at 20:10 Comment(14)
Interesting. Can you please demonstrate it? Will those work on Android N too? Do you think the apps that do block heads-up notifications use these APIs ?Dope
I've not used this APIs, so I'm afraid that I do not have an example to share. That said, from what I saw I think the third method is the way to go for Marshmallow and Nougat, and I don't think it will pose additional problems on Nougat.Child
But I wonder if there is something for Lollipop too, as it started there.Dope
From what I see, the functionality seems to be already in Lollipop by overriding NotificationListenerService#getCurrentInterruptionFilter(). From what I understand this method could return NotificationListenerService#INTERRUPTION_FILTER_NONE (or any other of the constants), but I'm not sure when is it called. I just can guess it will be called for each notification. It looks like methods in API 23+ like NotificationManager#setInterruptionFilter() are a convenience to be able to access the functionality but skip implementing a complete NotificationListenerService. I'll update my answer.Child
I haven't tried. I was trying to compile one of the examples this morning to update it with this, but run out of time. I'll try it later and upload to GitHub.Child
OK thank you. You get the bounty because you are the only one who answered well and because it is about to expire. Still, I would like to see it works. Would really appreciate it.Dope
I've updated the answer with my tests. I'll later clean up my example a little bit and upload to GitHub so you can reproduce my results.Child
Thank you so much. Can you please explain how you found all this information too? I want to read more about it.Dope
This information comes from testing the assumptions by using the example I originally posted. I've updated the answer and added some extra clarifications, links and a reference to the example I created (based on previous one). Hope you find it useful!Child
I've tested the sample. Creating the notification on your sample didn't show heads-up notification as I've asked for. Adding "setPriority(Notification.PRIORITY_MAX).setVibrate(new long[0]) ", it did show. However, the service that's supposed to hide it actually dismiss the notification, and not only that, it does it after the heads-up notification appears, which is something I wanted to avoid. How can I hide the heads up notification, yet not dismiss the notification itself?Dope
I've updated the example and the answer. As I previously said, the only way (without rooting the phone) seems to be in API 23+.Child
What if I do have a rooted device? What would you do in this case? Also, how does the app I've mentioned work (hides heads-up notifications) on Lollipop (and maybe M too) ?Dope
About rooted devices, I don't know, I just work with regular ones. About the app, from what I can see in the permissions the app has the permission "draw over other apps". After some checks, my best bet is that it is canceling the notification and then faking it afterwards, or something similar. I cannot explain the exact mechanism but it looks like is something like this. So, all in all will mean lots of work implementing the feature.Child
Too bad. I wish I had the ability to do so nicely, even with root.Dope

© 2022 - 2024 — McMap. All rights reserved.