1 /*
2  * Copyright (C) 2018 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 static android.view.Display.DEFAULT_DISPLAY;
18 
19 import static org.junit.Assert.assertFalse;
20 import static org.junit.Assert.assertTrue;
21 import static org.mockito.Mockito.mock;
22 import static org.mockito.Mockito.verify;
23 import static org.mockito.Mockito.when;
24 
25 import android.app.Notification;
26 import android.app.PendingIntent;
27 import android.app.StatusBarManager;
28 import android.testing.AndroidTestingRunner;
29 import android.testing.TestableLooper;
30 import android.testing.TestableLooper.RunWithLooper;
31 
32 import androidx.test.filters.SmallTest;
33 
34 import com.android.internal.logging.testing.FakeMetricsLogger;
35 import com.android.systemui.InitController;
36 import com.android.systemui.SysuiTestCase;
37 import com.android.systemui.plugins.ActivityStarter;
38 import com.android.systemui.plugins.statusbar.StatusBarStateController;
39 import com.android.systemui.power.domain.interactor.PowerInteractor;
40 import com.android.systemui.settings.FakeDisplayTracker;
41 import com.android.systemui.shade.NotificationShadeWindowView;
42 import com.android.systemui.shade.QuickSettingsController;
43 import com.android.systemui.shade.ShadeController;
44 import com.android.systemui.shade.ShadeViewController;
45 import com.android.systemui.statusbar.CommandQueue;
46 import com.android.systemui.statusbar.LockscreenShadeTransitionController;
47 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
48 import com.android.systemui.statusbar.NotificationMediaManager;
49 import com.android.systemui.statusbar.NotificationRemoteInputManager;
50 import com.android.systemui.statusbar.NotificationShadeWindowController;
51 import com.android.systemui.statusbar.SysuiStatusBarStateController;
52 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
53 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
54 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
55 import com.android.systemui.statusbar.notification.collection.render.NotifShadeEventSource;
56 import com.android.systemui.statusbar.notification.domain.interactor.NotificationsInteractor;
57 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptStateProvider;
58 import com.android.systemui.statusbar.notification.interruption.NotificationInterruptSuppressor;
59 import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
60 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
61 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
62 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
63 import com.android.systemui.statusbar.policy.KeyguardStateController;
64 
65 import org.junit.Before;
66 import org.junit.Test;
67 import org.junit.runner.RunWith;
68 import org.mockito.ArgumentCaptor;
69 
70 @SmallTest
71 @RunWith(AndroidTestingRunner.class)
72 @RunWithLooper()
73 public class StatusBarNotificationPresenterTest extends SysuiTestCase {
74     private StatusBarNotificationPresenter mStatusBarNotificationPresenter;
75     private final NotificationInterruptStateProvider mNotificationInterruptStateProvider =
76             mock(NotificationInterruptStateProvider.class);
77     private NotificationInterruptSuppressor mInterruptSuppressor;
78     private CommandQueue mCommandQueue;
79     private FakeMetricsLogger mMetricsLogger;
80     private final ShadeController mShadeController = mock(ShadeController.class);
81     private final NotificationsInteractor mNotificationsInteractor =
82             mock(NotificationsInteractor.class);
83     private final KeyguardStateController mKeyguardStateController =
84             mock(KeyguardStateController.class);
85     private final InitController mInitController = new InitController();
86 
87     @Before
setup()88     public void setup() {
89         mMetricsLogger = new FakeMetricsLogger();
90         mCommandQueue = new CommandQueue(mContext, new FakeDisplayTracker(mContext));
91         mDependency.injectTestDependency(StatusBarStateController.class,
92                 mock(SysuiStatusBarStateController.class));
93         mDependency.injectTestDependency(ShadeController.class, mShadeController);
94         mDependency.injectMockDependency(NotificationRemoteInputManager.Callback.class);
95         mDependency.injectMockDependency(NotificationShadeWindowController.class);
96 
97         NotificationShadeWindowView notificationShadeWindowView =
98                 mock(NotificationShadeWindowView.class);
99         NotificationStackScrollLayoutController stackScrollLayoutController =
100                 mock(NotificationStackScrollLayoutController.class);
101         when(stackScrollLayoutController.getView()).thenReturn(
102                 mock(NotificationStackScrollLayout.class));
103         when(notificationShadeWindowView.getResources()).thenReturn(mContext.getResources());
104 
105         ShadeViewController shadeViewController = mock(ShadeViewController.class);
106         mStatusBarNotificationPresenter = new StatusBarNotificationPresenter(
107                 mContext,
108                 shadeViewController,
109                 mock(QuickSettingsController.class),
110                 mock(HeadsUpManagerPhone.class),
111                 notificationShadeWindowView,
112                 mock(ActivityStarter.class),
113                 stackScrollLayoutController,
114                 mock(DozeScrimController.class),
115                 mock(NotificationShadeWindowController.class),
116                 mock(DynamicPrivacyController.class),
117                 mKeyguardStateController,
118                 mNotificationsInteractor,
119                 mock(LockscreenShadeTransitionController.class),
120                 mock(PowerInteractor.class),
121                 mCommandQueue,
122                 mock(NotificationLockscreenUserManager.class),
123                 mock(SysuiStatusBarStateController.class),
124                 mock(NotifShadeEventSource.class),
125                 mock(NotificationMediaManager.class),
126                 mock(NotificationGutsManager.class),
127                 mInitController,
128                 mNotificationInterruptStateProvider,
129                 mock(NotificationRemoteInputManager.class),
130                 mock(NotificationRemoteInputManager.Callback.class),
131                 mock(NotificationListContainer.class));
132         mInitController.executePostInitTasks();
133         ArgumentCaptor<NotificationInterruptSuppressor> suppressorCaptor =
134                 ArgumentCaptor.forClass(NotificationInterruptSuppressor.class);
135         verify(mNotificationInterruptStateProvider).addSuppressor(suppressorCaptor.capture());
136         mInterruptSuppressor = suppressorCaptor.getValue();
137     }
138 
139     @Test
testNoSuppressHeadsUp_default()140     public void testNoSuppressHeadsUp_default() {
141         Notification n = new Notification.Builder(getContext(), "a").build();
142         NotificationEntry entry = new NotificationEntryBuilder()
143                 .setPkg("a")
144                 .setOpPkg("a")
145                 .setTag("a")
146                 .setNotification(n)
147                 .build();
148 
149         assertFalse(mInterruptSuppressor.suppressAwakeHeadsUp(entry));
150     }
151 
152     @Test
testSuppressHeadsUp_disabledStatusBar()153     public void testSuppressHeadsUp_disabledStatusBar() {
154         Notification n = new Notification.Builder(getContext(), "a").build();
155         NotificationEntry entry = new NotificationEntryBuilder()
156                 .setPkg("a")
157                 .setOpPkg("a")
158                 .setTag("a")
159                 .setNotification(n)
160                 .build();
161         mCommandQueue.disable(DEFAULT_DISPLAY, StatusBarManager.DISABLE_EXPAND, 0,
162                 false /* animate */);
163         TestableLooper.get(this).processAllMessages();
164 
165         assertTrue("The panel should suppress heads up while disabled",
166                 mInterruptSuppressor.suppressAwakeHeadsUp(entry));
167     }
168 
169     @Test
testSuppressHeadsUp_disabledNotificationShade()170     public void testSuppressHeadsUp_disabledNotificationShade() {
171         Notification n = new Notification.Builder(getContext(), "a").build();
172         NotificationEntry entry = new NotificationEntryBuilder()
173                 .setPkg("a")
174                 .setOpPkg("a")
175                 .setTag("a")
176                 .setNotification(n)
177                 .build();
178         mCommandQueue.disable(DEFAULT_DISPLAY, 0, StatusBarManager.DISABLE2_NOTIFICATION_SHADE,
179                 false /* animate */);
180         TestableLooper.get(this).processAllMessages();
181 
182         assertTrue("The panel should suppress interruptions while notification shade "
183                         + "disabled",
184                 mInterruptSuppressor.suppressAwakeHeadsUp(entry));
185     }
186 
187     @Test
testNoSuppressHeadsUp_FSI_nonOccludedKeyguard()188     public void testNoSuppressHeadsUp_FSI_nonOccludedKeyguard() {
189         Notification n = new Notification.Builder(getContext(), "a")
190                 .setFullScreenIntent(mock(PendingIntent.class), true)
191                 .build();
192         NotificationEntry entry = new NotificationEntryBuilder()
193                 .setPkg("a")
194                 .setOpPkg("a")
195                 .setTag("a")
196                 .setNotification(n)
197                 .build();
198 
199         when(mKeyguardStateController.isShowing()).thenReturn(true);
200         when(mKeyguardStateController.isOccluded()).thenReturn(false);
201         assertFalse(mInterruptSuppressor.suppressAwakeHeadsUp(entry));
202     }
203 
204     @Test
testSuppressInterruptions_vrMode()205     public void testSuppressInterruptions_vrMode() {
206         Notification n = new Notification.Builder(getContext(), "a").build();
207         NotificationEntry entry = new NotificationEntryBuilder()
208                 .setPkg("a")
209                 .setOpPkg("a")
210                 .setTag("a")
211                 .setNotification(n)
212                 .build();
213         mStatusBarNotificationPresenter.mVrMode = true;
214 
215         assertTrue("Vr mode should suppress interruptions",
216                 mInterruptSuppressor.suppressAwakeInterruptions(entry));
217     }
218 
219     @Test
testSuppressInterruptions_statusBarAlertsDisabled()220     public void testSuppressInterruptions_statusBarAlertsDisabled() {
221         Notification n = new Notification.Builder(getContext(), "a").build();
222         NotificationEntry entry = new NotificationEntryBuilder()
223                 .setPkg("a")
224                 .setOpPkg("a")
225                 .setTag("a")
226                 .setNotification(n)
227                 .build();
228         when(mNotificationsInteractor.areNotificationAlertsEnabled()).thenReturn(false);
229 
230         assertTrue("When alerts aren't enabled, interruptions are suppressed",
231                 mInterruptSuppressor.suppressInterruptions(entry));
232     }
233 }
234