6

I created an app and added a java class that extend `NotificationListenerService'. Everything should work fine, but I just can't get to permission BIND_NOTIFICATION_LISTENER_SERVICE. I added it on the manifest, but when I check for the permission with:

        if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE)
            != PackageManager.PERMISSION_GRANTED)
    {
        Log.d(TAG, "permission denied");
    }
    else
        Log.d(TAG, "permission granted");

but I keep getting permission denied. I know that this permission isn't a "dangerous permission" so I don't have to ask for it from the user. In the manifest I declared this:

        <service android:name=".PcNotification"
        android:label="PCNotificationService"
        android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
        <intent-filter>
            <action android:name="android.service.notification.NotificationListenerService" />
        </intent-filter>
    </service>

and it still doesn't work. I also implemented the function onListenerConnected but it never called, so it means that my service never gets connected to the notification manager, probably because I don't have the permission BIND_NOTIFICATION_LISTENER_SERVICE

I just want to know how to grant this permission to my app.

Eldar Azulay
  • 271
  • 1
  • 3
  • 17

3 Answers3

5

I just can't get to permission BIND_NOTIFICATION_LISTENER_SERVICE

You do not need to request that permission. You need to defend your service with that permission. You are doing that in the <service> element via the android:permission attribute.

I know that this permission isn't a "dangerous permission" so I don't have to ask for it from the user.

Then get rid of the code that is requesting it from the user. It is unnecessary, and it will not work.

CommonsWare
  • 986,068
  • 189
  • 2,389
  • 2,491
  • It still doesn't work. I deleted this permission from the manifest. – Eldar Azulay Jun 16 '17 at 21:27
  • @EldarAzulay: Please explain, **in detail**, what "It still doesn't work" means. You should **keep** the `android:permission` attribute on the `` element. You should **delete** the `checkSelfPermission()` stuff. – CommonsWare Jun 16 '17 at 21:55
  • I deleted the `checkSelfPermission()` and the `uses-permission` from the manifest. I am using the `android:permission` as you can see in the main question. It doesn't work after I've done everything you told me. I used the function `onListenerConnected()` on the `NotificationListenerService`, but this function never get called because the Listener never gets connected to the notification manager. Maybe the problem is with about how I start the service? I am starting it like this: `Intent intent = new Intent(this, NotificationListener.class); startService(intent);` – Eldar Azulay Jun 16 '17 at 23:07
  • @EldarAzulay: Check LogCat for messages from the system, about issues in connecting to your service. Also see [this question and its answers](https://stackoverflow.com/q/40448505/115145). – CommonsWare Jun 16 '17 at 23:13
  • @EldarAzulay: AFAIK, *you* do not start the service. The user enables it in Settings. – CommonsWare Jun 16 '17 at 23:13
  • how do the user know where to go to enable it? The service start automatically? – Eldar Azulay Jun 17 '17 at 10:23
  • I tried to rename the service but it didn't work. I can't find where is the notification access in settings. – Eldar Azulay Jun 17 '17 at 10:36
  • 2
    @EldarAzulay: That will depend on your Android OS version. On Android 7.1, try Settings > Apps > (gear icon) > Special access > Notification access. – CommonsWare Jun 17 '17 at 10:44
  • 1
    It worked! But now I have another problem. the user shouldn't know where to go to do that. It would be simpler if I refer him to that page in settings, so I made an intent to open this page for him. The intent goes like that: `Intent intent = new Intent(); intent.setAction(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS); Uri uri = Uri.fromParts("package", getPackageName(), null); intent.setData(uri); startActivity(intent);` but I get `android.content.ActivityNotFoundException: No Activity found to handle Intent` – Eldar Azulay Jun 17 '17 at 11:01
  • @EldarAzulay: First, that `Intent` does not take a `Uri`, so get rid of yours. Second, as [the documentation states](https://developer.android.com/reference/android/provider/Settings.html#ACTION_NOTIFICATION_LISTENER_SETTINGS): "In some cases, a matching Activity may not exist, so ensure you safeguard against this." – CommonsWare Jun 17 '17 at 11:10
3

This should be the literal answer to the original question. Nevertheless, if you need the method below, you misunderstood the use of such services (as did I). You should not launch your notification listener yourself, you should simply test if your service is running, and if not, then you already know that the permission was not granted, and you can point the user to the preferences panel at android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS.

Add this method to your NotificationListenerClass, and it will return true if the permission is granted, false if not:

public Boolean VerifyNotificationPermission() {
    String theList = android.provider.Settings.Secure.getString(getContentResolver(), "enabled_notification_listeners");
    String[] theListList = theList.split(":");
    String me = (new ComponentName(this, YourNotificationListenerClass.class)).flattenToString();
    for ( String next : theListList ) {
        if ( me.equals(next) ) return true;
    }
    return false;
}

The string "enabled_notification_listeners" seems to be defined under the hood in Settings.Secure.ENABLED_NOTIFICATION_LISTENERS, but I cannot resolve that, so I use the perhaps not so well maintainable literal string. If anyone knows how to get it by its reference, please add it / edit!

wessel
  • 534
  • 5
  • 15
2

This specific permission must be granted manually by the user in android Settings, after that your service will be executed as you bound the permission to your service in AndroidManifest.xml with this:

<service android:name=".PcNotification"
    android:label="PCNotificationService"
    android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
    <intent-filter>
        <action android:name="android.service.notification.NotificationListenerService" />
    </intent-filter>
</service>

The problem is that most users won't know where to grant this permission (e.g inside android Settings), so you can open it for them with this:

startActivity(new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS"));

You can run this when the user interacts with your app - e.g clicking a button - and ideally you explain why you need this permission.

I find particularly nice to have a card with the explanation and a button to open the settings so the user can enable.

Alisson Reinaldo Silva
  • 10,009
  • 5
  • 65
  • 83