17

I'm fighting against the NotificationListenerService without much luck. I tried a lot of recipes found here and there, especially on so... But it works quite inconsistently.

A first look at the code :

Manifest :

<service
    android:name=".services.NLService"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE" >
    <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>

Then the service itself :

public class NLService extends NotificationListenerService {

    private String TAG = "NLService";

    // bind and unbind seems to make it work with Android 6...
    // but is never called with Android 4.4... 
    @Override
    public IBinder onBind(Intent mIntent) {
        IBinder mIBinder = super.onBind(mIntent);
        Log.i(TAG, "onBind");
        return mIBinder;
    }

    @Override
    public boolean onUnbind(Intent mIntent) {
        boolean mOnUnbind = super.onUnbind(mIntent);
        Log.i(TAG, "onUnbind");
        isNotificationAccessEnabled = false;
        try {
        } catch (Exception e) {
            Log.e(TAG, "Error during unbind", e);
        }
        return mOnUnbind;
    }

    // onCreate is called with Android 4.4 
    // because the service is explicitly started from the MainActivity.
    // Not on Android 6 where the system binds this service itself...

    @Override
    public void onCreate() {
        super.onCreate();
        Log.i(TAG, "**********  onCreate");

    @Override
    public void onNotificationPosted(StatusBarNotification sbn) {

        Log.i(TAG, "**********  onNotificationPosted");
        Log.i(TAG, "ID :" + sbn.getId() + "\t" + sbn.getNotification().tickerText + "\t" + sbn.getPackageName());
    }

    @Override
    public void onNotificationRemoved(StatusBarNotification sbn) {
        Log.i(TAG, "********** onNOtificationRemoved");
        Log.i(TAG, "ID :" + sbn.getId() + "\t" + sbn.getNotification().tickerText + "\t" + sbn.getPackageName());
    }
}

And in the main Activity the service is started or we ask the user to enable the setting if needed :

if (!Utilities.hasNotificationAccess(this)) 
{
     Intent intent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
     startActivity(intent);
     Log.i(TAG,"hasNotificationAccess NO");
}
else
{
    Log.i(TAG,"hasNotificationAccess YES");

    // without this startService, it never works with Android 4.4...
    // but this is not needed in Android 6... 
    Intent mServiceIntent = new Intent(this, NLService.class);
    startService(mServiceIntent);
}

Obviously, the secure setting access for notifications is enabled...

On Android 6 :

On the NLService itself, the addition of the onBind and onUnbind methods make it work, I can se the onBind log, and the onNotificationPosted is triggered nicely. But it lasts until the next launch of the app, then no more binding, no more onNotificationPosted, just nothing happens until I go back to security settings to uncheck-recheck the notifications access: repeating this each time the App is started is not something possible in a production environment.

On Android 4.4 :

In contrast to Android 6, in the MainActivity I need to explicitly start the NLService otherwise it never stats by itself. But once again it works for the first launch and never works again until uncheck-recheck the security setting...

Did I miss something obvious ?

JBA
  • 2,889
  • 1
  • 21
  • 38
  • Hello, do you find root cause? I met the same issue and have no idea how to solve. – Caxton Mar 04 '16 at 16:41
  • 2
    I found that the cause is recompiling the app on the device : first compilation, allow setting, it works. Second compilation : not working unless you re-check it or reboot the phone. However this is a testing environment issue, it looks like there is no such issue when you simply restart the app without recompilation, the setting stays alive... I dunno why it is lost upon recompilation... Hope his can help you ! – JBA Mar 04 '16 at 22:38
  • @JBA I am facing same issue in oreo device can you help me to solve this issue – Raj Gohel Feb 14 '20 at 11:05

1 Answers1

32

There is a problem with Android caching. When you upload app on the device, OS connects your service to Notification Manager. If you ran your app before, Android founds this service in cache so it's not reconnected.

Workaround: before pushing the app on your device, rename your service (refactor option in Android Studio works well) - Android will recognize this service as new one and connect to Notification Manager.

https://developer.android.com/reference/android/service/notification/NotificationListenerService.html#onListenerConnected() - this method will be invoked after connecting to Notification Manager so you can check if your service is connected or not.

Konrad Sikorski
  • 399
  • 5
  • 11
  • 1
    This is a nice workaround and explanation of the issue ! Did you manage to make some kind of "automatic" service dynamic random name, or do you do this manually for each iteration? – JBA Nov 27 '16 at 09:08
  • 1
    Nope, I do it manually each time. I also found a piece of code that should reload this service but it didn't work for me -> https://gist.github.com/xinghui/b2ddd8cffe55c4b62f5d8846d5545bf9 – Konrad Sikorski Nov 27 '16 at 13:17
  • I use Nexus 5 with Android 7.0, compiling with minSdkVersion 18 and compileSdkVersion 24 – Konrad Sikorski Nov 27 '16 at 13:19
  • 1
    Does this workaround works when i upload on playstore? – EngineSense Dec 07 '16 at 08:26
  • 2
    I haven't tried yet. When I was looking for this solution some people said that updates via Play store don't cause this issue. Following this info, applying this workaround shouldn't be necessary (but I can't find links to prove it). – Konrad Sikorski Dec 11 '16 at 04:28
  • What is your workaround if you update the App in the PlayStore? Are you forcing the user to re-check the Notification Access for your App or isn't this necessary? – joshi737 Dec 03 '17 at 12:55
  • I am having the same problem. How can I Refactor? Sorry, I see the Refactor menu in Android Studio, but I don't know what to do. – Ton Apr 05 '18 at 13:02
  • I have run into a problem with this. My app stopped receiving notifications. I checked and the permission was turned off (not sure why). BUT... the code to check if I had permission still returned true! In other words, the following code returns true, when it should not as far as I can tell: NotificationManagerCompat.getEnabledListenerPackages(ctx),contains(getPackageName()); – John Moore Feb 13 '19 at 00:31
  • I finally gave up, set my minimumSDK to 27, and now check for the class notification perms directly with: aNotificationManager.isNotificationListenerAccessGranted – John Moore Feb 13 '19 at 01:42
  • What if I don't rename service, will reboot device clear the notification cache? – Robert Jun 03 '19 at 03:26
  • Reply to myself according to this https://issuetracker.google.com/issues/36984668, reboot device might work! – Robert Jun 04 '19 at 09:26
  • I might be late on the party. But ran into this issue today. And found that toggling notification access on each app reload made the app to reconnect with the service. So it stopped me from renaming service with each debug. – asasamar Mar 26 '20 at 12:24
  • Sure, but if you'd like to run your app immediately after clicking "Debug", quick refactor could be a lot quicker than going to settings and toggling notification access (and going back to your app). – Konrad Sikorski Apr 01 '20 at 17:01