Android getActiveNotifications вызывает исключение SecurityException

У меня есть класс NotificationService, который слушает уведомления. Однако когда я вызываю getActiveNotifications(), он вызывает исключение SecurityException. Да, я проверил разрешение перед вызовом этого метода.

Я использую AsyncTask внутри NotificationService для получения уведомления. Код ниже.

private class AsyncProcessNotification extends AsyncTask<Void, Void, Void> {

        @Override
        protected Void doInBackground(Void... params) {
            int notificationType = MainApplication.settingNotificationType;
            MainApplication.clearNotificationItems();

            if (MainApplication.settingNotificationType == Constants.KEY_NOTIFICATION_TYPE_DISABLED) {
                Log.i(TAG, "Notifications disabled");
                return null;
            }

            if (PermissionHelper.isNotificationPermissionGranted(getApplicationContext())) {
                if (getActiveNotifications() == null || getActiveNotifications().length == 0) {
                    Log.i(TAG, "No notifications found");
                    return null;
                }

                Log.i(TAG, "Getting " + getActiveNotifications().length +" notifications");
                Log.i(TAG, "Notification type  " + notificationType);
                for (StatusBarNotification statusBarNotification : getActiveNotifications()) {
                    // Process notifications
                }
            } else {
                //
            }

            return null;
        }

        @Override
        protected void onPostExecute(Void result) {
            Intent notify = new Intent(Constants.ACTION_NOTIFICATION_LISTENER);
            sendBroadcast(notify);
        }
    }

Странная вещь, согласно Crashlytics, иногда это не удается в if (getActiveNotifications() == null || getActiveNotifications().length == 0) а иногда это не удается в Log.i(TAG, "Getting " + getActiveNotifications().length +" notifications");

Чтобы проверить разрешение, я использую следующий метод.

public static boolean isNotificationPermissionGranted(Context context) {
        Set<String> appList = NotificationManagerCompat.getEnabledListenerPackages(context);
        for (String l:appList) {
            if (l.equals(context.getPackageName())) {
                return true;
            }
        }

        return false;
    }

Трассировки стека:

Fatal Exception: java.lang.RuntimeException: An error occurred while executing doInBackground()
       at android.os.AsyncTask$3.done(AsyncTask.java:309)
       at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:354)
       at java.util.concurrent.FutureTask.setException(FutureTask.java:223)
       at java.util.concurrent.FutureTask.run(FutureTask.java:242)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
       at java.lang.Thread.run(Thread.java:818)
Caused by java.lang.SecurityException: Disallowed call from unknown notification listener: android.service.notification.INotificationListener$Stub$Proxy@3e9880d
       at android.os.Parcel.readException(Parcel.java:1599)
       at android.os.Parcel.readException(Parcel.java:1552)
       at android.app.INotificationManager$Stub$Proxy.getActiveNotificationsFromListener(INotificationManager.java:1046)
       at android.service.notification.NotificationListenerService.getActiveNotifications(NotificationListenerService.java:467)
       at android.service.notification.NotificationListenerService.getActiveNotifications(NotificationListenerService.java:420)
       at com.afd.app.lockscreen.ios11.lib.service.NotificationService$AsyncProcessNotification.doInBackground(NotificationService.java:120)
       at com.afd.app.lockscreen.ios11.lib.service.NotificationService$AsyncProcessNotification.doInBackground(NotificationService.java:97)
       at android.os.AsyncTask$2.call(AsyncTask.java:295)
       at java.util.concurrent.FutureTask.run(FutureTask.java:237)
       at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:234)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1113)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:588)
       at java.lang.Thread.run(Thread.java:818)

Я знаю, что должен делать что-то глупое, но не могу понять, что. Может кто-нибудь помочь, пожалуйста? Спасибо!

2 ответа

Я столкнулся с той же ошибкой в ​​моем сервисе прослушивания уведомлений. Я смог решить эту проблему, подождав, пока служба прослушивателя подключится к диспетчеру уведомлений, прежде чем вызывать любой из методов NotificationListenerService.

@Override
public void onListenerConnected() {
    Log.i(TAG, "Listener connected");
    listenerConnected = true;
}

private class AsyncProcessNotification extends AsyncTask<Void, Void, Void> {
    protected Void doInBackground(Void... params) {
              ...
            // wait until our notification listener service is connected
            // to the notification manager
            Log.i(TAG, "Waiting for listener to be connected...");

            while(!listenerConnected);

            // Call getActiveNotifications after this
            for (StatusBarNotification sbn : getActiveNotifications()) {
                   processNotifications(sbn);
            }
    }

    // rest of the AsyncTask here
}

Как написано @niranjan-nagaraju, вам нужно проверитьsIsConnectedперед отменой уведомления.

https://android.googlesource.com/platform/frameworks/base/+/b408e8ecd22853faa70e97d0596aac9e7dcf5596/services/core/java/com/android/server/notification/NotificationListeners.java#175