1 /*
2  * Copyright (C) 2018 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package android.app.stubs;
17 
18 import android.content.ComponentName;
19 import android.os.ConditionVariable;
20 import android.service.notification.NotificationListenerService;
21 import android.service.notification.StatusBarNotification;
22 
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.Map;
26 
27 public class TestNotificationListener extends NotificationListenerService {
28     public static final String TAG = "TestNotificationListener";
29     public static final String PKG = "android.app.stubs";
30     private static final long CONNECTION_TIMEOUT_MS = 1000;
31 
32     private ArrayList<String> mTestPackages = new ArrayList<>();
33 
34     public ArrayList<StatusBarNotification> mPosted = new ArrayList<>();
35     public Map<String, Integer> mRemoved = new HashMap<>();
36     public RankingMap mRankingMap;
37 
38     /**
39      * This controls whether there is a listener connected or not. Depending on the method, if the
40      * caller tries to use a listener after it has disconnected, NMS can throw a SecurityException.
41      *
42      * There is no race between onListenerConnected() and onListenerDisconnected() because they are
43      * called in the same thread. The value that getInstance() sees is guaranteed to be the value
44      * that was set by onListenerConnected() because of the happens-before established by the
45      * condition variable.
46      */
47     private static final ConditionVariable INSTANCE_AVAILABLE = new ConditionVariable(false);
48     private static TestNotificationListener sNotificationListenerInstance = null;
49     boolean isConnected;
50 
getId()51     public static String getId() {
52         return String.format("%s/%s", TestNotificationListener.class.getPackage().getName(),
53                 TestNotificationListener.class.getName());
54     }
55 
getComponentName()56     public static ComponentName getComponentName() {
57         return new ComponentName(TestNotificationListener.class.getPackage().getName(),
58                 TestNotificationListener.class.getName());
59     }
60 
61     @Override
onCreate()62     public void onCreate() {
63         super.onCreate();
64         mTestPackages.add(PKG);
65     }
66 
67     @Override
onListenerConnected()68     public void onListenerConnected() {
69         super.onListenerConnected();
70         sNotificationListenerInstance = this;
71         INSTANCE_AVAILABLE.open();
72         isConnected = true;
73     }
74 
75     @Override
onListenerDisconnected()76     public void onListenerDisconnected() {
77         INSTANCE_AVAILABLE.close();
78         sNotificationListenerInstance = null;
79         isConnected = false;
80     }
81 
getInstance()82     public static TestNotificationListener getInstance() {
83         if (INSTANCE_AVAILABLE.block(CONNECTION_TIMEOUT_MS)) {
84             return sNotificationListenerInstance;
85         }
86         return null;
87     }
88 
resetData()89     public void resetData() {
90         mPosted.clear();
91         mRemoved.clear();
92     }
93 
addTestPackage(String packageName)94     public void addTestPackage(String packageName) {
95         mTestPackages.add(packageName);
96     }
97 
removeTestPackage(String packageName)98     public void removeTestPackage(String packageName) {
99         mTestPackages.remove(packageName);
100     }
101 
102     @Override
onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap)103     public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
104         if (sbn == null || !mTestPackages.contains(sbn.getPackageName())) { return; }
105         mRankingMap = rankingMap;
106         mPosted.add(sbn);
107     }
108 
109     @Override
onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap, int reason)110     public void onNotificationRemoved(StatusBarNotification sbn, RankingMap rankingMap,
111             int reason) {
112         if (sbn == null || !mTestPackages.contains(sbn.getPackageName())) { return; }
113         mRankingMap = rankingMap;
114         mRemoved.put(sbn.getKey(), reason);
115     }
116 
117     @Override
onNotificationRankingUpdate(RankingMap rankingMap)118     public void onNotificationRankingUpdate(RankingMap rankingMap) {
119         mRankingMap = rankingMap;
120     }
121 }
122