1 /*
2  * Copyright (C) 2019 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 
17 package com.android.systemui.statusbar.notification.collection.coordinator;
18 
19 import static android.app.Notification.VISIBILITY_PUBLIC;
20 import static android.app.Notification.VISIBILITY_SECRET;
21 import static android.app.NotificationManager.IMPORTANCE_HIGH;
22 import static android.app.NotificationManager.IMPORTANCE_MIN;
23 
24 import static com.android.systemui.statusbar.notification.collection.EntryUtilKt.modifyEntry;
25 
26 import static org.junit.Assert.assertFalse;
27 import static org.junit.Assert.assertTrue;
28 import static org.mockito.Mockito.times;
29 import static org.mockito.Mockito.verify;
30 import static org.mockito.Mockito.when;
31 
32 import android.os.Handler;
33 import android.os.UserHandle;
34 import android.testing.AndroidTestingRunner;
35 
36 import androidx.test.filters.SmallTest;
37 
38 import com.android.keyguard.KeyguardUpdateMonitor;
39 import com.android.systemui.SysuiTestCase;
40 import com.android.systemui.broadcast.BroadcastDispatcher;
41 import com.android.systemui.plugins.statusbar.StatusBarStateController;
42 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
43 import com.android.systemui.statusbar.RankingBuilder;
44 import com.android.systemui.statusbar.notification.collection.GroupEntry;
45 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
46 import com.android.systemui.statusbar.notification.collection.NotifPipeline;
47 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
48 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
49 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifFilter;
50 import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider;
51 import com.android.systemui.statusbar.policy.KeyguardStateController;
52 
53 import org.junit.Before;
54 import org.junit.Test;
55 import org.junit.runner.RunWith;
56 import org.mockito.ArgumentCaptor;
57 import org.mockito.Mock;
58 import org.mockito.MockitoAnnotations;
59 
60 @SmallTest
61 @RunWith(AndroidTestingRunner.class)
62 public class KeyguardCoordinatorTest extends SysuiTestCase {
63     private static final int NOTIF_USER_ID = 0;
64     private static final int CURR_USER_ID = 1;
65 
66     @Mock private Handler mMainHandler;
67     @Mock private KeyguardStateController mKeyguardStateController;
68     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
69     @Mock private BroadcastDispatcher mBroadcastDispatcher;
70     @Mock private StatusBarStateController mStatusBarStateController;
71     @Mock private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
72     @Mock private HighPriorityProvider mHighPriorityProvider;
73     @Mock private NotifPipeline mNotifPipeline;
74 
75     private NotificationEntry mEntry;
76     private NotifFilter mKeyguardFilter;
77 
78     @Before
setup()79     public void setup() {
80         MockitoAnnotations.initMocks(this);
81         KeyguardCoordinator keyguardCoordinator = new KeyguardCoordinator(
82                 mContext, mMainHandler, mKeyguardStateController, mLockscreenUserManager,
83                 mBroadcastDispatcher, mStatusBarStateController,
84                 mKeyguardUpdateMonitor, mHighPriorityProvider);
85 
86         mEntry = new NotificationEntryBuilder()
87                 .setUser(new UserHandle(NOTIF_USER_ID))
88                 .build();
89 
90         ArgumentCaptor<NotifFilter> filterCaptor = ArgumentCaptor.forClass(NotifFilter.class);
91         keyguardCoordinator.attach(mNotifPipeline);
92         verify(mNotifPipeline, times(1)).addFinalizeFilter(filterCaptor.capture());
93         mKeyguardFilter = filterCaptor.getValue();
94     }
95 
96     @Test
unfilteredState()97     public void unfilteredState() {
98         // GIVEN an 'unfiltered-keyguard-showing' state
99         setupUnfilteredState(mEntry);
100 
101         // THEN don't filter out the entry
102         assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
103     }
104 
105     @Test
keyguardNotShowing()106     public void keyguardNotShowing() {
107         // GIVEN the lockscreen isn't showing
108         setupUnfilteredState(mEntry);
109         when(mKeyguardStateController.isShowing()).thenReturn(false);
110 
111         // THEN don't filter out the entry
112         assertFalse(mKeyguardFilter.shouldFilterOut(mEntry, 0));
113     }
114 
115     @Test
doNotShowLockscreenNotifications()116     public void doNotShowLockscreenNotifications() {
117         // GIVEN an 'unfiltered-keyguard-showing' state
118         setupUnfilteredState(mEntry);
119 
120         // WHEN we shouldn't show any lockscreen notifications
121         when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(false);
122 
123         // THEN filter out the entry
124         assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
125     }
126 
127     @Test
lockdown()128     public void lockdown() {
129         // GIVEN an 'unfiltered-keyguard-showing' state
130         setupUnfilteredState(mEntry);
131 
132         // WHEN the notification's user is in lockdown:
133         when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(true);
134 
135         // THEN filter out the entry
136         assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
137     }
138 
139     @Test
publicMode_settingsDisallow()140     public void publicMode_settingsDisallow() {
141         // GIVEN an 'unfiltered-keyguard-showing' state
142         setupUnfilteredState(mEntry);
143 
144         // WHEN the notification's user is in public mode and settings are configured to disallow
145         // notifications in public mode
146         when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(true);
147         when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
148                 .thenReturn(false);
149 
150         // THEN filter out the entry
151         assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
152     }
153 
154     @Test
publicMode_notifDisallowed()155     public void publicMode_notifDisallowed() {
156         // GIVEN an 'unfiltered-keyguard-showing' state
157         setupUnfilteredState(mEntry);
158 
159         // WHEN the notification's user is in public mode and settings are configured to disallow
160         // notifications in public mode
161         when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(true);
162         mEntry.setRanking(new RankingBuilder()
163                 .setKey(mEntry.getKey())
164                 .setVisibilityOverride(VISIBILITY_SECRET).build());
165 
166         // THEN filter out the entry
167         assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
168     }
169 
170     @Test
doesNotExceedThresholdToShow()171     public void doesNotExceedThresholdToShow() {
172         // GIVEN an 'unfiltered-keyguard-showing' state
173         setupUnfilteredState(mEntry);
174 
175         // WHEN the notification doesn't exceed the threshold to show on the lockscreen
176         mEntry.setRanking(new RankingBuilder()
177                 .setKey(mEntry.getKey())
178                 .setImportance(IMPORTANCE_MIN)
179                 .build());
180         when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(false);
181 
182         // THEN filter out the entry
183         assertTrue(mKeyguardFilter.shouldFilterOut(mEntry, 0));
184     }
185 
186     @Test
summaryExceedsThresholdToShow()187     public void summaryExceedsThresholdToShow() {
188         // GIVEN the notification doesn't exceed the threshold to show on the lockscreen
189         // but it's part of a group (has a parent)
190         final NotificationEntry entryWithParent = new NotificationEntryBuilder()
191                 .setUser(new UserHandle(NOTIF_USER_ID))
192                 .build();
193 
194         final GroupEntry parent = new GroupEntryBuilder()
195                 .setKey("test_group_key")
196                 .setSummary(new NotificationEntryBuilder()
197                         .setImportance(IMPORTANCE_HIGH)
198                         .build())
199                 .addChild(entryWithParent)
200                 .build();
201 
202         setupUnfilteredState(entryWithParent);
203         entryWithParent.setRanking(new RankingBuilder()
204                 .setKey(entryWithParent.getKey())
205                 .setImportance(IMPORTANCE_MIN)
206                 .build());
207 
208         // WHEN its parent does exceed threshold tot show on the lockscreen
209         when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(true);
210 
211         // THEN don't filter out the entry
212         assertFalse(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
213 
214         // WHEN its parent doesn't exceed threshold to show on lockscreen
215         when(mHighPriorityProvider.isHighPriority(parent)).thenReturn(false);
216         modifyEntry(parent.getSummary(), builder -> builder
217                 .setImportance(IMPORTANCE_MIN)
218                 .done());
219 
220         // THEN filter out the entry
221         assertTrue(mKeyguardFilter.shouldFilterOut(entryWithParent, 0));
222     }
223 
224     /**
225      * setup a state where the notification will not be filtered by the
226      * KeyguardNotificationCoordinator when the keyguard is showing.
227      */
setupUnfilteredState(NotificationEntry entry)228     private void setupUnfilteredState(NotificationEntry entry) {
229         // keyguard is showing
230         when(mKeyguardStateController.isShowing()).thenReturn(true);
231 
232         // show notifications on the lockscreen
233         when(mLockscreenUserManager.shouldShowLockscreenNotifications()).thenReturn(true);
234 
235         // neither the current user nor the notification's user is in lockdown
236         when(mLockscreenUserManager.getCurrentUserId()).thenReturn(CURR_USER_ID);
237         when(mKeyguardUpdateMonitor.isUserInLockdown(NOTIF_USER_ID)).thenReturn(false);
238         when(mKeyguardUpdateMonitor.isUserInLockdown(CURR_USER_ID)).thenReturn(false);
239 
240         // not in public mode
241         when(mLockscreenUserManager.isLockscreenPublicMode(CURR_USER_ID)).thenReturn(false);
242         when(mLockscreenUserManager.isLockscreenPublicMode(NOTIF_USER_ID)).thenReturn(false);
243 
244         // entry's ranking - should show on all lockscreens
245         // + priority of the notification exceeds the threshold to be shown on the lockscreen
246         entry.setRanking(new RankingBuilder()
247                 .setKey(mEntry.getKey())
248                 .setVisibilityOverride(VISIBILITY_PUBLIC)
249                 .setImportance(IMPORTANCE_HIGH)
250                 .build());
251 
252         // settings allows notifications in public mode
253         when(mLockscreenUserManager.userAllowsNotificationsInPublic(CURR_USER_ID)).thenReturn(true);
254         when(mLockscreenUserManager.userAllowsNotificationsInPublic(NOTIF_USER_ID))
255                 .thenReturn(true);
256 
257         // notification doesn't have a summary
258 
259         // notification is high priority, so it shouldn't be filtered
260         when(mHighPriorityProvider.isHighPriority(mEntry)).thenReturn(true);
261     }
262 }
263