Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 98bf8ba3 authored by Jason Monk's avatar Jason Monk
Browse files

Add notification listener plugin hook

Allows plugin control over notifications right at the entrance
to sysui and gives them the opportunity to mess with them how
they see fit.

Test: manual
Change-Id: I569bf37138da66d0524acecfa36ceb409f98fbb4
parent 38568aff
Loading
Loading
Loading
Loading
+62 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.android.systemui.plugins;

import android.service.notification.NotificationListenerService.RankingMap;
import android.service.notification.StatusBarNotification;

import com.android.systemui.plugins.NotificationListenerController.NotificationProvider;
import com.android.systemui.plugins.annotations.DependsOn;
import com.android.systemui.plugins.annotations.ProvidesInterface;

@ProvidesInterface(action = NotificationListenerController.ACTION,
        version = NotificationListenerController.VERSION)
@DependsOn(target = NotificationProvider.class)
public interface NotificationListenerController extends Plugin {
    String ACTION = "com.android.systemui.action.PLUGIN_NOTIFICATION_ASSISTANT";
    int VERSION = 1;

    void onListenerConnected(NotificationProvider provider);

    default boolean onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
        return false;
    }
    default boolean onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap) {
        return false;
    }

    default StatusBarNotification[] getActiveNotifications(
            StatusBarNotification[] activeNotifications) {
        return activeNotifications;
    }

    default RankingMap getCurrentRanking(RankingMap currentRanking) {
        return currentRanking;
    }

    @ProvidesInterface(version = NotificationProvider.VERSION)
    interface NotificationProvider {
        int VERSION = 1;

        // Methods to get info about current notifications
        StatusBarNotification[] getActiveNotifications();
        RankingMap getRankingMap();

        // Methods to notify sysui of changes to notification list.
        void addNotification(StatusBarNotification sbn);
        void removeNotification(StatusBarNotification sbn);
        void updateRanking();
    }
}
+152 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2017 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the
 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

package com.android.systemui.statusbar.phone;

import android.content.ComponentName;
import android.content.Context;
import android.os.RemoteException;
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;

import com.android.systemui.Dependency;
import com.android.systemui.plugins.NotificationListenerController;
import com.android.systemui.plugins.NotificationListenerController.NotificationProvider;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.PluginManager;

import java.util.ArrayList;

/**
 * A version of NotificationListenerService that passes all info to
 * any plugins connected. Also allows those plugins the chance to cancel
 * any incoming callbacks or to trigger new ones.
 */
public class NotificationListenerWithPlugins extends NotificationListenerService implements
        PluginListener<NotificationListenerController> {

    private ArrayList<NotificationListenerController> mPlugins = new ArrayList<>();
    private boolean mConnected;

    @Override
    public void registerAsSystemService(Context context, ComponentName componentName,
            int currentUser) throws RemoteException {
        super.registerAsSystemService(context, componentName, currentUser);
        Dependency.get(PluginManager.class).addPluginListener(this,
                NotificationListenerController.class);
    }

    @Override
    public void unregisterAsSystemService() throws RemoteException {
        super.unregisterAsSystemService();
        Dependency.get(PluginManager.class).removePluginListener(this);
    }

    @Override
    public StatusBarNotification[] getActiveNotifications() {
        StatusBarNotification[] activeNotifications = super.getActiveNotifications();
        for (NotificationListenerController plugin : mPlugins) {
            activeNotifications = plugin.getActiveNotifications(activeNotifications);
        }
        return activeNotifications;
    }

    @Override
    public RankingMap getCurrentRanking() {
        RankingMap currentRanking = super.getCurrentRanking();
        for (NotificationListenerController plugin : mPlugins) {
            currentRanking = plugin.getCurrentRanking(currentRanking);
        }
        return currentRanking;
    }

    public void onPluginConnected() {
        mConnected = true;
        mPlugins.forEach(p -> p.onListenerConnected(getProvider()));
    }

    /**
     * Called when listener receives a onNotificationPosted.
     * Returns true to indicate this callback should be skipped.
     */
    public boolean onPluginNotificationPosted(StatusBarNotification sbn,
            final RankingMap rankingMap) {
        for (NotificationListenerController plugin : mPlugins) {
            if (plugin.onNotificationPosted(sbn, rankingMap)) {
                return true;
            }
        }
        return false;
    }

    /**
     * Called when listener receives a onNotificationRemoved.
     * Returns true to indicate this callback should be skipped.
     */
    public boolean onPluginNotificationRemoved(StatusBarNotification sbn,
            final RankingMap rankingMap) {
        for (NotificationListenerController plugin : mPlugins) {
            if (plugin.onNotificationRemoved(sbn, rankingMap)) {
                return true;
            }
        }
        return false;
    }

    public RankingMap onPluginRankingUpdate(RankingMap rankingMap) {
        return getCurrentRanking();
    }

    @Override
    public void onPluginConnected(NotificationListenerController plugin, Context pluginContext) {
        mPlugins.add(plugin);
        if (mConnected) {
            plugin.onListenerConnected(getProvider());
        }
    }

    @Override
    public void onPluginDisconnected(NotificationListenerController plugin) {
        mPlugins.remove(plugin);
    }

    private NotificationProvider getProvider() {
        return new NotificationProvider() {
            @Override
            public StatusBarNotification[] getActiveNotifications() {
                return NotificationListenerWithPlugins.super.getActiveNotifications();
            }

            @Override
            public RankingMap getRankingMap() {
                return NotificationListenerWithPlugins.super.getCurrentRanking();
            }

            @Override
            public void addNotification(StatusBarNotification sbn) {
                onNotificationPosted(sbn, getRankingMap());
            }

            @Override
            public void removeNotification(StatusBarNotification sbn) {
                onNotificationRemoved(sbn, getRankingMap());
            }

            @Override
            public void updateRanking() {
                onNotificationRankingUpdate(getRankingMap());
            }
        };
    }
}
+10 −17
Original line number Diff line number Diff line
@@ -5754,11 +5754,12 @@ public class StatusBar extends SystemUI implements DemoMode,
        }
    };

    private final NotificationListenerService mNotificationListener =
            new NotificationListenerService() {
    private final NotificationListenerWithPlugins mNotificationListener =
            new NotificationListenerWithPlugins() {
        @Override
        public void onListenerConnected() {
            if (DEBUG) Log.d(TAG, "onListenerConnected");
            onPluginConnected();
            final StatusBarNotification[] notifications = getActiveNotifications();
            if (notifications == null) {
                Log.w(TAG, "onListenerConnected unable to get active notifications.");
@@ -5783,7 +5784,7 @@ public class StatusBar extends SystemUI implements DemoMode,
        public void onNotificationPosted(final StatusBarNotification sbn,
                final RankingMap rankingMap) {
            if (DEBUG) Log.d(TAG, "onNotificationPosted: " + sbn);
            if (sbn != null) {
            if (sbn != null && !onPluginNotificationPosted(sbn, rankingMap)) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
@@ -5827,14 +5828,9 @@ public class StatusBar extends SystemUI implements DemoMode,
        public void onNotificationRemoved(StatusBarNotification sbn,
                final RankingMap rankingMap) {
            if (DEBUG) Log.d(TAG, "onNotificationRemoved: " + sbn);
            if (sbn != null) {
            if (sbn != null && !onPluginNotificationRemoved(sbn, rankingMap)) {
                final String key = sbn.getKey();
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        removeNotification(key, rankingMap);
                    }
                });
                mHandler.post(() -> removeNotification(key, rankingMap));
            }
        }

@@ -5842,13 +5838,10 @@ public class StatusBar extends SystemUI implements DemoMode,
        public void onNotificationRankingUpdate(final RankingMap rankingMap) {
            if (DEBUG) Log.d(TAG, "onRankingUpdate");
            if (rankingMap != null) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    updateNotificationRanking(rankingMap);
                RankingMap r = onPluginRankingUpdate(rankingMap);
                mHandler.post(() -> updateNotificationRanking(r));
            }
        }
            });
        }                            }

    };