1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
5  * except in compliance with the License. You may obtain a copy of the License at
6  *
7  *      http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software distributed under the
10  * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
11  * KIND, either express or implied. See the License for the specific language governing
12  * permissions and limitations under the License.
13  */
14 
15 package com.android.systemui.statusbar.phone;
16 
17 import android.content.ComponentName;
18 import android.content.Context;
19 import android.os.RemoteException;
20 import android.service.notification.NotificationListenerService;
21 import android.service.notification.StatusBarNotification;
22 
23 import com.android.systemui.Dependency;
24 import com.android.systemui.plugins.NotificationListenerController;
25 import com.android.systemui.plugins.NotificationListenerController.NotificationProvider;
26 import com.android.systemui.plugins.PluginListener;
27 import com.android.systemui.shared.plugins.PluginManager;
28 
29 import java.util.ArrayList;
30 
31 /**
32  * A version of NotificationListenerService that passes all info to
33  * any plugins connected. Also allows those plugins the chance to cancel
34  * any incoming callbacks or to trigger new ones.
35  */
36 public class NotificationListenerWithPlugins extends NotificationListenerService implements
37         PluginListener<NotificationListenerController> {
38 
39     private ArrayList<NotificationListenerController> mPlugins = new ArrayList<>();
40     private boolean mConnected;
41 
42     @Override
registerAsSystemService(Context context, ComponentName componentName, int currentUser)43     public void registerAsSystemService(Context context, ComponentName componentName,
44             int currentUser) throws RemoteException {
45         super.registerAsSystemService(context, componentName, currentUser);
46         Dependency.get(PluginManager.class).addPluginListener(this,
47                 NotificationListenerController.class);
48     }
49 
50     @Override
unregisterAsSystemService()51     public void unregisterAsSystemService() throws RemoteException {
52         super.unregisterAsSystemService();
53         Dependency.get(PluginManager.class).removePluginListener(this);
54     }
55 
56     @Override
getActiveNotifications()57     public StatusBarNotification[] getActiveNotifications() {
58         StatusBarNotification[] activeNotifications = super.getActiveNotifications();
59         for (NotificationListenerController plugin : mPlugins) {
60             activeNotifications = plugin.getActiveNotifications(activeNotifications);
61         }
62         return activeNotifications;
63     }
64 
65     @Override
getCurrentRanking()66     public RankingMap getCurrentRanking() {
67         RankingMap currentRanking = super.getCurrentRanking();
68         for (NotificationListenerController plugin : mPlugins) {
69             currentRanking = plugin.getCurrentRanking(currentRanking);
70         }
71         return currentRanking;
72     }
73 
onPluginConnected()74     public void onPluginConnected() {
75         mConnected = true;
76         mPlugins.forEach(p -> p.onListenerConnected(getProvider()));
77     }
78 
79     /**
80      * Called when listener receives a onNotificationPosted.
81      * Returns true to indicate this callback should be skipped.
82      */
onPluginNotificationPosted(StatusBarNotification sbn, final RankingMap rankingMap)83     public boolean onPluginNotificationPosted(StatusBarNotification sbn,
84             final RankingMap rankingMap) {
85         for (NotificationListenerController plugin : mPlugins) {
86             if (plugin.onNotificationPosted(sbn, rankingMap)) {
87                 return true;
88             }
89         }
90         return false;
91     }
92 
93     /**
94      * Called when listener receives a onNotificationRemoved.
95      * Returns true to indicate this callback should be skipped.
96      */
onPluginNotificationRemoved(StatusBarNotification sbn, final RankingMap rankingMap)97     public boolean onPluginNotificationRemoved(StatusBarNotification sbn,
98             final RankingMap rankingMap) {
99         for (NotificationListenerController plugin : mPlugins) {
100             if (plugin.onNotificationRemoved(sbn, rankingMap)) {
101                 return true;
102             }
103         }
104         return false;
105     }
106 
onPluginRankingUpdate(RankingMap rankingMap)107     public RankingMap onPluginRankingUpdate(RankingMap rankingMap) {
108         return getCurrentRanking();
109     }
110 
111     @Override
onPluginConnected(NotificationListenerController plugin, Context pluginContext)112     public void onPluginConnected(NotificationListenerController plugin, Context pluginContext) {
113         mPlugins.add(plugin);
114         if (mConnected) {
115             plugin.onListenerConnected(getProvider());
116         }
117     }
118 
119     @Override
onPluginDisconnected(NotificationListenerController plugin)120     public void onPluginDisconnected(NotificationListenerController plugin) {
121         mPlugins.remove(plugin);
122     }
123 
getProvider()124     private NotificationProvider getProvider() {
125         return new NotificationProvider() {
126             @Override
127             public StatusBarNotification[] getActiveNotifications() {
128                 return NotificationListenerWithPlugins.super.getActiveNotifications();
129             }
130 
131             @Override
132             public RankingMap getRankingMap() {
133                 return NotificationListenerWithPlugins.super.getCurrentRanking();
134             }
135 
136             @Override
137             public void addNotification(StatusBarNotification sbn) {
138                 onNotificationPosted(sbn, getRankingMap());
139             }
140 
141             @Override
142             public void removeNotification(StatusBarNotification sbn) {
143                 onNotificationRemoved(sbn, getRankingMap());
144             }
145 
146             @Override
147             public void updateRanking() {
148                 onNotificationRankingUpdate(getRankingMap());
149             }
150         };
151     }
152 }
153