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.app.NotificationChannel;
18 import android.content.ComponentName;
19 import android.content.Context;
20 import android.os.RemoteException;
21 import android.os.UserHandle;
22 import android.service.notification.NotificationListenerService;
23 import android.service.notification.StatusBarNotification;
24 
25 import com.android.systemui.plugins.NotificationListenerController;
26 import com.android.systemui.plugins.NotificationListenerController.NotificationProvider;
27 import com.android.systemui.plugins.PluginListener;
28 import com.android.systemui.plugins.PluginManager;
29 
30 import java.util.ArrayList;
31 
32 import javax.inject.Inject;
33 
34 /**
35  * A version of NotificationListenerService that passes all info to
36  * any plugins connected. Also allows those plugins the chance to cancel
37  * any incoming callbacks or to trigger new ones.
38  */
39 public class NotificationListenerWithPlugins extends NotificationListenerService implements
40         PluginListener<NotificationListenerController> {
41 
42     private ArrayList<NotificationListenerController> mPlugins = new ArrayList<>();
43     private boolean mConnected;
44     private PluginManager mPluginManager;
45 
46     @Inject
NotificationListenerWithPlugins(PluginManager pluginManager)47     public NotificationListenerWithPlugins(PluginManager pluginManager) {
48         super();
49         mPluginManager = pluginManager;
50     }
51 
52     @Override
registerAsSystemService(Context context, ComponentName componentName, int currentUser)53     public void registerAsSystemService(Context context, ComponentName componentName,
54             int currentUser) throws RemoteException {
55         super.registerAsSystemService(context, componentName, currentUser);
56         mPluginManager.addPluginListener(this, NotificationListenerController.class);
57     }
58 
59     @Override
unregisterAsSystemService()60     public void unregisterAsSystemService() throws RemoteException {
61         super.unregisterAsSystemService();
62         mPluginManager.removePluginListener(this);
63     }
64 
65     @Override
getActiveNotifications()66     public StatusBarNotification[] getActiveNotifications() {
67         StatusBarNotification[] activeNotifications = super.getActiveNotifications();
68         for (NotificationListenerController plugin : mPlugins) {
69             activeNotifications = plugin.getActiveNotifications(activeNotifications);
70         }
71         return activeNotifications;
72     }
73 
74     @Override
getCurrentRanking()75     public RankingMap getCurrentRanking() {
76         return onPluginRankingUpdate(super.getCurrentRanking());
77     }
78 
onPluginConnected()79     public void onPluginConnected() {
80         mConnected = true;
81         mPlugins.forEach(p -> p.onListenerConnected(getProvider()));
82     }
83 
84     /**
85      * Called when listener receives a onNotificationPosted.
86      * Returns true if there's a plugin determining to skip the default callbacks.
87      */
onPluginNotificationPosted(StatusBarNotification sbn, final RankingMap rankingMap)88     public boolean onPluginNotificationPosted(StatusBarNotification sbn,
89             final RankingMap rankingMap) {
90         for (NotificationListenerController plugin : mPlugins) {
91             if (plugin.onNotificationPosted(sbn, rankingMap)) {
92                 return true;
93             }
94         }
95         return false;
96     }
97 
98     /**
99      * Called when listener receives a onNotificationRemoved.
100      * Returns true if there's a plugin determining to skip the default callbacks.
101      */
onPluginNotificationRemoved(StatusBarNotification sbn, final RankingMap rankingMap)102     public boolean onPluginNotificationRemoved(StatusBarNotification sbn,
103             final RankingMap rankingMap) {
104         for (NotificationListenerController plugin : mPlugins) {
105             if (plugin.onNotificationRemoved(sbn, rankingMap)) {
106                 return true;
107             }
108         }
109         return false;
110     }
111 
112     /**
113      * Called when listener receives a onNotificationChannelModified.
114      * Returns true if there's a plugin determining to skip the default callbacks.
115      */
onPluginNotificationChannelModified( String pkgName, UserHandle user, NotificationChannel channel, int modificationType)116     public boolean onPluginNotificationChannelModified(
117             String pkgName, UserHandle user, NotificationChannel channel, int modificationType) {
118         for (NotificationListenerController plugin : mPlugins) {
119             if (plugin.onNotificationChannelModified(pkgName, user, channel, modificationType)) {
120                 return true;
121             }
122         }
123         return false;
124     }
125 
onPluginRankingUpdate(RankingMap rankingMap)126     protected RankingMap onPluginRankingUpdate(RankingMap rankingMap) {
127         for (NotificationListenerController plugin : mPlugins) {
128             rankingMap = plugin.getCurrentRanking(rankingMap);
129         }
130         return rankingMap;
131     }
132 
133     @Override
onPluginConnected(NotificationListenerController plugin, Context pluginContext)134     public void onPluginConnected(NotificationListenerController plugin, Context pluginContext) {
135         mPlugins.add(plugin);
136         if (mConnected) {
137             plugin.onListenerConnected(getProvider());
138         }
139     }
140 
141     @Override
onPluginDisconnected(NotificationListenerController plugin)142     public void onPluginDisconnected(NotificationListenerController plugin) {
143         mPlugins.remove(plugin);
144     }
145 
getProvider()146     private NotificationProvider getProvider() {
147         return new NotificationProvider() {
148             @Override
149             public StatusBarNotification[] getActiveNotifications() {
150                 return NotificationListenerWithPlugins.super.getActiveNotifications();
151             }
152 
153             @Override
154             public RankingMap getRankingMap() {
155                 return NotificationListenerWithPlugins.super.getCurrentRanking();
156             }
157 
158             @Override
159             public void addNotification(StatusBarNotification sbn) {
160                 onNotificationPosted(sbn, getRankingMap());
161             }
162 
163             @Override
164             public void removeNotification(StatusBarNotification sbn) {
165                 onNotificationRemoved(sbn, getRankingMap());
166             }
167 
168             @Override
169             public void updateRanking() {
170                 onNotificationRankingUpdate(getRankingMap());
171             }
172         };
173     }
174 }
175