blob: d3c3746761aadf790f999ea4222ab5219ddc999a [file] [log] [blame]
Maurice Lam132710e2017-03-03 19:13:42 -08001/*
2 * Copyright (C) 2017 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
17package com.android.systemui.statusbar;
18
Julia Reynoldsfc640012018-02-21 12:25:27 -050019import static android.app.AppOpsManager.OP_ACCEPT_HANDOVER;
20import static android.app.AppOpsManager.OP_CAMERA;
21
22import static junit.framework.Assert.assertEquals;
23
Maurice Lam132710e2017-03-03 19:13:42 -080024import static org.junit.Assert.assertFalse;
25import static org.junit.Assert.assertTrue;
Julia Reynoldsfc640012018-02-21 12:25:27 -050026import static org.mockito.ArgumentMatchers.any;
27import static org.mockito.ArgumentMatchers.anyInt;
28import static org.mockito.ArgumentMatchers.anyString;
Maurice Lam132710e2017-03-03 19:13:42 -080029import static org.mockito.Matchers.eq;
30import static org.mockito.Mockito.mock;
31import static org.mockito.Mockito.when;
32
33import android.Manifest;
34import android.app.Notification;
Selim Cinek608a57a2017-04-28 16:50:41 -070035import android.app.NotificationChannel;
Maurice Lam132710e2017-03-03 19:13:42 -080036import android.content.pm.IPackageManager;
37import android.content.pm.PackageManager;
Julia Reynolds5bbb6da2018-03-28 10:48:37 -040038import android.media.session.MediaSession;
Maurice Lam132710e2017-03-03 19:13:42 -080039import android.os.Bundle;
Selim Cinek608a57a2017-04-28 16:50:41 -070040import android.service.notification.NotificationListenerService;
Maurice Lam132710e2017-03-03 19:13:42 -080041import android.service.notification.StatusBarNotification;
42import android.support.test.annotation.UiThreadTest;
43import android.support.test.filters.SmallTest;
44import android.support.test.runner.AndroidJUnit4;
Julia Reynoldsfc640012018-02-21 12:25:27 -050045import android.util.ArraySet;
Maurice Lam132710e2017-03-03 19:13:42 -080046
Julia Reynoldsfc640012018-02-21 12:25:27 -050047import com.android.systemui.ForegroundServiceController;
Maurice Lam132710e2017-03-03 19:13:42 -080048import com.android.systemui.SysuiTestCase;
Selim Cinek608a57a2017-04-28 16:50:41 -070049import com.android.systemui.statusbar.phone.NotificationGroupManager;
Maurice Lam132710e2017-03-03 19:13:42 -080050
Selim Cinek608a57a2017-04-28 16:50:41 -070051import org.junit.Assert;
Maurice Lam132710e2017-03-03 19:13:42 -080052import org.junit.Before;
53import org.junit.Test;
54import org.junit.runner.RunWith;
Julia Reynoldsfc640012018-02-21 12:25:27 -050055import org.mockito.Mock;
56import org.mockito.MockitoAnnotations;
Maurice Lam132710e2017-03-03 19:13:42 -080057
58@SmallTest
59@RunWith(AndroidJUnit4.class)
60public class NotificationDataTest extends SysuiTestCase {
61
62 private static final int UID_NORMAL = 123;
63 private static final int UID_ALLOW_DURING_SETUP = 456;
Beverly5a20a5e2018-03-06 15:02:44 -050064 private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
Julia Reynolds5bbb6da2018-03-28 10:48:37 -040065 private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt";
Maurice Lam132710e2017-03-03 19:13:42 -080066
67 private final StatusBarNotification mMockStatusBarNotification =
68 mock(StatusBarNotification.class);
Julia Reynoldsfc640012018-02-21 12:25:27 -050069 @Mock
70 ForegroundServiceController mFsc;
71 @Mock
72 NotificationData.Environment mEnvironment;
Maurice Lam132710e2017-03-03 19:13:42 -080073
74 private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
Selim Cinek608a57a2017-04-28 16:50:41 -070075 private NotificationData mNotificationData;
76 private ExpandableNotificationRow mRow;
Maurice Lam132710e2017-03-03 19:13:42 -080077
78 @Before
79 public void setUp() throws Exception {
Julia Reynoldsfc640012018-02-21 12:25:27 -050080 MockitoAnnotations.initMocks(this);
Maurice Lam132710e2017-03-03 19:13:42 -080081 when(mMockStatusBarNotification.getUid()).thenReturn(UID_NORMAL);
82
83 when(mMockPackageManager.checkUidPermission(
84 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
85 eq(UID_NORMAL)))
86 .thenReturn(PackageManager.PERMISSION_DENIED);
87 when(mMockPackageManager.checkUidPermission(
88 eq(Manifest.permission.NOTIFICATION_DURING_SETUP),
89 eq(UID_ALLOW_DURING_SETUP)))
90 .thenReturn(PackageManager.PERMISSION_GRANTED);
Selim Cinek608a57a2017-04-28 16:50:41 -070091
Julia Reynoldsfc640012018-02-21 12:25:27 -050092 mDependency.injectTestDependency(ForegroundServiceController.class, mFsc);
93 when(mEnvironment.getGroupManager()).thenReturn(new NotificationGroupManager());
94 when(mEnvironment.isDeviceProvisioned()).thenReturn(true);
95 when(mEnvironment.isNotificationForCurrentProfiles(any())).thenReturn(true);
96 mNotificationData = new TestableNotificationData(mEnvironment);
Selim Cinek608a57a2017-04-28 16:50:41 -070097 mNotificationData.updateRanking(mock(NotificationListenerService.RankingMap.class));
98 mRow = new NotificationTestHelper(getContext()).createRow();
Maurice Lam132710e2017-03-03 19:13:42 -080099 }
100
101 @Test
102 @UiThreadTest
103 public void testShowNotificationEvenIfUnprovisioned_FalseIfNoExtra() {
104 initStatusBarNotification(false);
105 when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP);
106
107 assertFalse(
108 NotificationData.showNotificationEvenIfUnprovisioned(
109 mMockPackageManager,
110 mMockStatusBarNotification));
111 }
112
113 @Test
114 @UiThreadTest
115 public void testShowNotificationEvenIfUnprovisioned_FalseIfNoPermission() {
116 initStatusBarNotification(true);
117
118 assertFalse(
119 NotificationData.showNotificationEvenIfUnprovisioned(
120 mMockPackageManager,
121 mMockStatusBarNotification));
122 }
123
124 @Test
125 @UiThreadTest
126 public void testShowNotificationEvenIfUnprovisioned_TrueIfHasPermissionAndExtra() {
127 initStatusBarNotification(true);
128 when(mMockStatusBarNotification.getUid()).thenReturn(UID_ALLOW_DURING_SETUP);
129
130 assertTrue(
131 NotificationData.showNotificationEvenIfUnprovisioned(
132 mMockPackageManager,
133 mMockStatusBarNotification));
134 }
135
Selim Cinek608a57a2017-04-28 16:50:41 -0700136 @Test
137 public void testChannelSetWhenAdded() {
138 mNotificationData.add(mRow.getEntry());
139 Assert.assertTrue(mRow.getEntry().channel != null);
140 }
141
Julia Reynoldsfc640012018-02-21 12:25:27 -0500142
Julia Reynoldsfc640012018-02-21 12:25:27 -0500143
144 @Test
145 public void testAllRelevantNotisTaggedWithAppOps() throws Exception {
146 mNotificationData.add(mRow.getEntry());
147 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
148 mNotificationData.add(row2.getEntry());
149 ExpandableNotificationRow diffPkg =
150 new NotificationTestHelper(getContext()).createRow("pkg", 4000);
151 mNotificationData.add(diffPkg.getEntry());
152
153 ArraySet<Integer> expectedOps = new ArraySet<>();
154 expectedOps.add(OP_CAMERA);
155 expectedOps.add(OP_ACCEPT_HANDOVER);
156
157 for (int op : expectedOps) {
158 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400159 NotificationTestHelper.PKG, mRow.getEntry().key, true);
160 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
161 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500162 }
163 for (int op : expectedOps) {
164 assertTrue(mRow.getEntry().key + " doesn't have op " + op,
165 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(op));
166 assertTrue(row2.getEntry().key + " doesn't have op " + op,
167 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(op));
168 assertFalse(diffPkg.getEntry().key + " has op " + op,
169 mNotificationData.get(diffPkg.getEntry().key).mActiveAppOps.contains(op));
170 }
171 }
172
173 @Test
174 public void testAppOpsRemoval() throws Exception {
175 mNotificationData.add(mRow.getEntry());
176 ExpandableNotificationRow row2 = new NotificationTestHelper(getContext()).createRow();
177 mNotificationData.add(row2.getEntry());
178
179 ArraySet<Integer> expectedOps = new ArraySet<>();
180 expectedOps.add(OP_CAMERA);
181 expectedOps.add(OP_ACCEPT_HANDOVER);
182
183 for (int op : expectedOps) {
184 mNotificationData.updateAppOp(op, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400185 NotificationTestHelper.PKG, row2.getEntry().key, true);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500186 }
187
188 expectedOps.remove(OP_ACCEPT_HANDOVER);
189 mNotificationData.updateAppOp(OP_ACCEPT_HANDOVER, NotificationTestHelper.UID,
Julia Reynolds91590062018-04-02 16:24:11 -0400190 NotificationTestHelper.PKG, row2.getEntry().key, false);
Julia Reynoldsfc640012018-02-21 12:25:27 -0500191
192 assertTrue(mRow.getEntry().key + " doesn't have op " + OP_CAMERA,
193 mNotificationData.get(mRow.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
194 assertTrue(row2.getEntry().key + " doesn't have op " + OP_CAMERA,
195 mNotificationData.get(row2.getEntry().key).mActiveAppOps.contains(OP_CAMERA));
196 assertFalse(mRow.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
197 mNotificationData.get(mRow.getEntry().key)
198 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
199 assertFalse(row2.getEntry().key + " has op " + OP_ACCEPT_HANDOVER,
200 mNotificationData.get(row2.getEntry().key)
201 .mActiveAppOps.contains(OP_ACCEPT_HANDOVER));
202 }
203
204 @Test
205 public void testSuppressSystemAlertNotification() {
206 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
207 when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
Julia Reynolds3c7de112018-03-28 09:33:13 -0400208 StatusBarNotification sbn = mRow.getEntry().notification;
209 Bundle bundle = new Bundle();
210 bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {"something"});
211 sbn.getNotification().extras = bundle;
Julia Reynoldsfc640012018-02-21 12:25:27 -0500212
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400213 assertTrue(mNotificationData.shouldFilterOut(mRow.getEntry()));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500214 }
215
216 @Test
217 public void testDoNotSuppressSystemAlertNotification() {
Julia Reynolds3c7de112018-03-28 09:33:13 -0400218 StatusBarNotification sbn = mRow.getEntry().notification;
219 Bundle bundle = new Bundle();
220 bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {"something"});
221 sbn.getNotification().extras = bundle;
222
Julia Reynoldsfc640012018-02-21 12:25:27 -0500223 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
224 when(mFsc.isSystemAlertNotification(any())).thenReturn(true);
225
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400226 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry()));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500227
228 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
229 when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
230
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400231 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry()));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500232
233 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
234 when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
235
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400236 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry()));
Julia Reynoldsfc640012018-02-21 12:25:27 -0500237 }
238
Beverly5a20a5e2018-03-06 15:02:44 -0500239 @Test
Julia Reynolds3c7de112018-03-28 09:33:13 -0400240 public void testDoNotSuppressMalformedSystemAlertNotification() {
241 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(true);
242
243 // missing extra
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400244 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry()));
Julia Reynolds3c7de112018-03-28 09:33:13 -0400245
246 StatusBarNotification sbn = mRow.getEntry().notification;
247 Bundle bundle = new Bundle();
248 bundle.putStringArray(Notification.EXTRA_FOREGROUND_APPS, new String[] {});
249 sbn.getNotification().extras = bundle;
250
251 // extra missing values
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400252 assertFalse(mNotificationData.shouldFilterOut(mRow.getEntry()));
Julia Reynolds3c7de112018-03-28 09:33:13 -0400253 }
254
255 @Test
Beverly5a20a5e2018-03-06 15:02:44 -0500256 public void testShouldFilterHiddenNotifications() {
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400257 initStatusBarNotification(false);
Beverly5a20a5e2018-03-06 15:02:44 -0500258 // setup
259 when(mFsc.isSystemAlertWarningNeeded(anyInt(), anyString())).thenReturn(false);
260 when(mFsc.isSystemAlertNotification(any())).thenReturn(false);
261
262 // test should filter out hidden notifications:
263 // hidden
264 when(mMockStatusBarNotification.getKey()).thenReturn(TEST_HIDDEN_NOTIFICATION_KEY);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400265 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
266 assertTrue(mNotificationData.shouldFilterOut(entry));
Beverly5a20a5e2018-03-06 15:02:44 -0500267
268 // not hidden
269 when(mMockStatusBarNotification.getKey()).thenReturn("not hidden");
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400270 entry = new NotificationData.Entry(mMockStatusBarNotification);
271 assertFalse(mNotificationData.shouldFilterOut(entry));
Beverly5a20a5e2018-03-06 15:02:44 -0500272 }
273
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400274 @Test
275 public void testIsExemptFromDndVisualSuppression_foreground() {
276 initStatusBarNotification(false);
277 when(mMockStatusBarNotification.getKey()).thenReturn(
278 TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
279 Notification n = mMockStatusBarNotification.getNotification();
280 n.flags = Notification.FLAG_FOREGROUND_SERVICE;
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400281 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400282
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400283 assertTrue(mNotificationData.isExemptFromDndVisualSuppression(entry));
284 assertFalse(mNotificationData.shouldSuppressAmbient(entry));
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400285 }
286
287 @Test
288 public void testIsExemptFromDndVisualSuppression_media() {
289 initStatusBarNotification(false);
290 when(mMockStatusBarNotification.getKey()).thenReturn(
291 TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
292 Notification n = mMockStatusBarNotification.getNotification();
293 Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
294 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
295 n = nb.build();
296 when(mMockStatusBarNotification.getNotification()).thenReturn(n);
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400297 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400298
Julia Reynoldsaa96cf32018-04-17 09:09:04 -0400299 assertTrue(mNotificationData.isExemptFromDndVisualSuppression(entry));
300 assertFalse(mNotificationData.shouldSuppressAmbient(entry));
301 }
302
303 @Test
304 public void testIsExemptFromDndVisualSuppression_system() {
305 initStatusBarNotification(false);
306 when(mMockStatusBarNotification.getKey()).thenReturn(
307 TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
308 NotificationData.Entry entry = new NotificationData.Entry(mMockStatusBarNotification);
309 entry.mIsSystemNotification = true;
310
311 assertTrue(mNotificationData.isExemptFromDndVisualSuppression(entry));
312 assertFalse(mNotificationData.shouldSuppressAmbient(entry));
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400313 }
314
Maurice Lam132710e2017-03-03 19:13:42 -0800315 private void initStatusBarNotification(boolean allowDuringSetup) {
316 Bundle bundle = new Bundle();
317 bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
318 Notification notification = new Notification.Builder(mContext, "test")
319 .addExtras(bundle)
320 .build();
321 when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
322 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700323
324 private class TestableNotificationData extends NotificationData {
325 public TestableNotificationData(Environment environment) {
326 super(environment);
327 }
328
329 @Override
330 public NotificationChannel getChannel(String key) {
331 return new NotificationChannel(null, null, 0);
332 }
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900333
334 @Override
335 protected boolean getRanking(String key, NotificationListenerService.Ranking outRanking) {
336 super.getRanking(key, outRanking);
Beverly5a20a5e2018-03-06 15:02:44 -0500337 if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) {
338 outRanking.populate(key, outRanking.getRank(),
339 outRanking.matchesInterruptionFilter(),
340 outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
341 outRanking.getImportance(), outRanking.getImportanceExplanation(),
342 outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
343 outRanking.canShowBadge(), outRanking.getUserSentiment(), true);
Julia Reynolds5bbb6da2018-03-28 10:48:37 -0400344 } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
345 outRanking.populate(key, outRanking.getRank(),
346 outRanking.matchesInterruptionFilter(),
347 outRanking.getVisibilityOverride(), 255,
348 outRanking.getImportance(), outRanking.getImportanceExplanation(),
349 outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
350 outRanking.canShowBadge(), outRanking.getUserSentiment(), true);
Beverly5a20a5e2018-03-06 15:02:44 -0500351 } else {
352 outRanking.populate(key, outRanking.getRank(),
353 outRanking.matchesInterruptionFilter(),
354 outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
355 outRanking.getImportance(), outRanking.getImportanceExplanation(),
356 outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
357 outRanking.canShowBadge(), outRanking.getUserSentiment(), false);
358 }
Kensuke Matsuiefa1a742017-08-03 12:12:36 +0900359 return true;
360 }
Selim Cinek608a57a2017-04-28 16:50:41 -0700361 }
Maurice Lam132710e2017-03-03 19:13:42 -0800362}