2 * Copyright (C) 2016 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.server.notification;
19 import static android.app.NotificationManager.IMPORTANCE_LOW;
20 import static android.app.NotificationManager.IMPORTANCE_NONE;
22 import static junit.framework.Assert.assertEquals;
23 import static junit.framework.Assert.assertFalse;
24 import static junit.framework.Assert.assertTrue;
25 import static junit.framework.Assert.fail;
27 import static org.mockito.Matchers.anyBoolean;
28 import static org.mockito.Matchers.anyLong;
29 import static org.mockito.Matchers.anyString;
30 import static org.mockito.Matchers.eq;
31 import static org.mockito.Mockito.any;
32 import static org.mockito.Mockito.anyInt;
33 import static org.mockito.Mockito.mock;
34 import static org.mockito.Mockito.never;
35 import static org.mockito.Mockito.reset;
36 import static org.mockito.Mockito.times;
37 import static org.mockito.Mockito.verify;
38 import static org.mockito.Mockito.when;
40 import android.app.INotificationManager;
41 import android.app.Notification;
42 import android.app.NotificationChannel;
43 import android.app.NotificationChannelGroup;
44 import android.app.NotificationManager;
45 import android.companion.ICompanionDeviceManager;
46 import android.content.ComponentName;
47 import android.content.Context;
48 import android.content.pm.ApplicationInfo;
49 import android.content.pm.IPackageManager;
50 import android.content.pm.PackageManager;
51 import android.content.pm.ParceledListSlice;
52 import android.graphics.Color;
53 import android.os.Binder;
54 import android.os.Process;
55 import android.os.UserHandle;
56 import android.provider.Settings.Secure;
57 import android.service.notification.NotificationListenerService;
58 import android.service.notification.StatusBarNotification;
59 import android.test.suitebuilder.annotation.SmallTest;
60 import android.testing.AndroidTestingRunner;
61 import android.testing.TestableLooper;
62 import android.testing.TestableLooper.RunWithLooper;
64 import java.util.ArrayList;
65 import java.util.Arrays;
66 import java.util.List;
68 import org.junit.Before;
69 import org.junit.Test;
70 import org.junit.runner.RunWith;
71 import org.mockito.Mock;
72 import org.mockito.MockitoAnnotations;
74 import com.android.server.lights.Light;
75 import com.android.server.lights.LightsManager;
78 @RunWith(AndroidTestingRunner.class)
80 public class NotificationManagerServiceTest extends NotificationTestCase {
81 private static final long WAIT_FOR_IDLE_TIMEOUT = 2;
82 private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId";
83 private final int uid = Binder.getCallingUid();
84 private NotificationManagerService mNotificationManagerService;
85 private INotificationManager mBinderService;
86 private NotificationManagerInternal mInternalService;
88 private IPackageManager mPackageManager;
90 private PackageManager mPackageManagerClient;
91 private Context mContext = getContext();
92 private final String PKG = mContext.getPackageName();
93 private TestableLooper mTestableLooper;
95 private RankingHelper mRankingHelper;
97 private NotificationUsageStats mUsageStats;
98 private NotificationChannel mTestNotificationChannel = new NotificationChannel(
99 TEST_CHANNEL_ID, TEST_CHANNEL_ID, NotificationManager.IMPORTANCE_DEFAULT);
101 private NotificationManagerService.NotificationListeners mNotificationListeners;
102 private ManagedServices.ManagedServiceInfo mListener;
103 @Mock private ICompanionDeviceManager mCompanionMgr;
104 @Mock SnoozeHelper mSnoozeHelper;
106 // Use a Testable subclass so we can simulate calls from the system without failing.
107 private static class TestableNotificationManagerService extends NotificationManagerService {
108 public TestableNotificationManagerService(Context context) { super(context); }
111 protected boolean isCallingUidSystem() {
116 protected boolean isCallerSystemOrPhone() {
121 protected ICompanionDeviceManager getCompanionManager() {
127 public void setUp() throws Exception {
128 MockitoAnnotations.initMocks(this);
130 // most tests assume badging is enabled
131 Secure.putIntForUser(getContext().getContentResolver(),
132 Secure.NOTIFICATION_BADGING, 1,
133 UserHandle.getUserHandleForUid(uid).getIdentifier());
135 mNotificationManagerService = new TestableNotificationManagerService(mContext);
137 // MockPackageManager - default returns ApplicationInfo with matching calling UID
138 final ApplicationInfo applicationInfo = new ApplicationInfo();
139 applicationInfo.uid = uid;
140 when(mPackageManager.getApplicationInfo(anyString(), anyInt(), anyInt()))
141 .thenReturn(applicationInfo);
142 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
143 .thenReturn(applicationInfo);
144 final LightsManager mockLightsManager = mock(LightsManager.class);
145 when(mockLightsManager.getLight(anyInt())).thenReturn(mock(Light.class));
146 // Use this testable looper.
147 mTestableLooper = TestableLooper.get(this);
149 mListener = mNotificationListeners.new ManagedServiceInfo(
150 null, new ComponentName(PKG, "test_class"), uid, true, null, 0);
151 when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
152 mNotificationManagerService.init(mTestableLooper.getLooper(), mPackageManager,
153 mPackageManagerClient, mockLightsManager, mNotificationListeners, mCompanionMgr,
154 mSnoozeHelper, mUsageStats);
156 // Tests call directly into the Binder.
157 mBinderService = mNotificationManagerService.getBinderService();
158 mInternalService = mNotificationManagerService.getInternalService();
160 mBinderService.createNotificationChannels(
161 PKG, new ParceledListSlice(Arrays.asList(mTestNotificationChannel)));
164 public void waitForIdle() throws Exception {
165 mTestableLooper.processAllMessages();
168 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id,
169 String groupKey, boolean isSummary) {
170 Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
171 .setContentTitle("foo")
172 .setSmallIcon(android.R.drawable.sym_def_app_icon)
174 .setGroupSummary(isSummary);
176 StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, id, "tag", uid, 0,
177 nb.build(), new UserHandle(uid), null, 0);
178 return new NotificationRecord(mContext, sbn, channel);
180 private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
181 return generateNotificationRecord(channel, null);
184 private NotificationRecord generateNotificationRecord(NotificationChannel channel,
185 Notification.TvExtender extender) {
186 if (channel == null) {
187 channel = mTestNotificationChannel;
189 Notification.Builder nb = new Notification.Builder(mContext, channel.getId())
190 .setContentTitle("foo")
191 .setSmallIcon(android.R.drawable.sym_def_app_icon);
192 if (extender != null) {
195 StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, "tag", uid, 0,
196 nb.build(), new UserHandle(uid), null, 0);
197 return new NotificationRecord(mContext, sbn, channel);
201 public void testCreateNotificationChannels_SingleChannel() throws Exception {
202 final NotificationChannel channel =
203 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
204 mBinderService.createNotificationChannels("test_pkg",
205 new ParceledListSlice(Arrays.asList(channel)));
206 final NotificationChannel createdChannel =
207 mBinderService.getNotificationChannel("test_pkg", "id");
208 assertTrue(createdChannel != null);
212 public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception {
214 mBinderService.createNotificationChannels("test_pkg",
215 new ParceledListSlice(Arrays.asList(null)));
216 fail("Exception should be thrown immediately.");
217 } catch (NullPointerException e) {
223 public void testCreateNotificationChannels_TwoChannels() throws Exception {
224 final NotificationChannel channel1 =
225 new NotificationChannel("id1", "name", NotificationManager.IMPORTANCE_DEFAULT);
226 final NotificationChannel channel2 =
227 new NotificationChannel("id2", "name", NotificationManager.IMPORTANCE_DEFAULT);
228 mBinderService.createNotificationChannels("test_pkg",
229 new ParceledListSlice(Arrays.asList(channel1, channel2)));
230 assertTrue(mBinderService.getNotificationChannel("test_pkg", "id1") != null);
231 assertTrue(mBinderService.getNotificationChannel("test_pkg", "id2") != null);
235 public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()
237 final NotificationChannel channel =
238 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
239 mBinderService.createNotificationChannels("test_pkg",
240 new ParceledListSlice(Arrays.asList(channel)));
242 // Recreating the channel doesn't throw, but ignores importance.
243 final NotificationChannel dupeChannel =
244 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
245 mBinderService.createNotificationChannels("test_pkg",
246 new ParceledListSlice(Arrays.asList(dupeChannel)));
247 final NotificationChannel createdChannel =
248 mBinderService.getNotificationChannel("test_pkg", "id");
249 assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance());
253 public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()
255 final NotificationChannel channel1 =
256 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
257 final NotificationChannel channel2 =
258 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
259 mBinderService.createNotificationChannels("test_pkg",
260 new ParceledListSlice(Arrays.asList(channel1, channel2)));
261 final NotificationChannel createdChannel =
262 mBinderService.getNotificationChannel("test_pkg", "id");
263 assertEquals(NotificationManager.IMPORTANCE_DEFAULT, createdChannel.getImportance());
267 public void testBlockedNotifications_suspended() throws Exception {
268 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
270 NotificationChannel channel = new NotificationChannel("id", "name",
271 NotificationManager.IMPORTANCE_HIGH);
272 NotificationRecord r = generateNotificationRecord(channel);
273 assertTrue(mNotificationManagerService.isBlocked(r, mUsageStats));
274 verify(mUsageStats, times(1)).registerSuspendedByAdmin(eq(r));
278 public void testBlockedNotifications_blockedChannel() throws Exception {
279 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
281 NotificationChannel channel = new NotificationChannel("id", "name",
282 NotificationManager.IMPORTANCE_HIGH);
283 channel.setImportance(NotificationManager.IMPORTANCE_NONE);
284 NotificationRecord r = generateNotificationRecord(channel);
285 assertTrue(mNotificationManagerService.isBlocked(r, mUsageStats));
286 verify(mUsageStats, times(1)).registerBlocked(eq(r));
290 public void testEnqueuedBlockedNotifications_blockedApp() throws Exception {
291 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
293 mBinderService.setNotificationsEnabledForPackage(PKG, uid, false);
295 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
296 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
297 sbn.getId(), sbn.getNotification(), sbn.getUserId());
299 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
303 public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
304 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
305 generateNotificationRecord(null).getNotification(), 0);
307 StatusBarNotification[] notifs =
308 mBinderService.getActiveNotifications(PKG);
309 assertEquals(1, notifs.length);
313 public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception {
314 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
315 generateNotificationRecord(null).getNotification(), 0);
316 mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
318 StatusBarNotification[] notifs =
319 mBinderService.getActiveNotifications(PKG);
320 assertEquals(0, notifs.length);
324 public void testCancelNotificationWhilePostedAndEnqueued() throws Exception {
325 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
326 generateNotificationRecord(null).getNotification(), 0);
328 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
329 generateNotificationRecord(null).getNotification(), 0);
330 mBinderService.cancelNotificationWithTag(PKG, "tag", 0, 0);
332 StatusBarNotification[] notifs =
333 mBinderService.getActiveNotifications(PKG);
334 assertEquals(0, notifs.length);
338 public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception {
339 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
340 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
341 sbn.getId(), sbn.getNotification(), sbn.getUserId());
342 mBinderService.cancelNotificationsFromListener(null, null);
344 StatusBarNotification[] notifs =
345 mBinderService.getActiveNotifications(sbn.getPackageName());
346 assertEquals(0, notifs.length);
350 public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception {
351 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
352 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
353 sbn.getId(), sbn.getNotification(), sbn.getUserId());
354 mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
356 StatusBarNotification[] notifs =
357 mBinderService.getActiveNotifications(sbn.getPackageName());
358 assertEquals(0, notifs.length);
362 public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception {
363 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
364 for (int i = 0; i < 10; i++) {
365 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
366 sbn.getId(), sbn.getNotification(), sbn.getUserId());
368 mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
373 public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception {
374 final NotificationRecord parent = generateNotificationRecord(
375 mTestNotificationChannel, 1, "group1", true);
376 final NotificationRecord parentAsChild = generateNotificationRecord(
377 mTestNotificationChannel, 1, "group1", false);
378 final NotificationRecord child = generateNotificationRecord(
379 mTestNotificationChannel, 2, "group1", false);
381 // fully post parent notification
382 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
383 parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
386 // enqueue the child several times
387 for (int i = 0; i < 10; i++) {
388 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
389 child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
391 // make the parent a child, which will cancel the child notification
392 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
393 parentAsChild.sbn.getId(), parentAsChild.sbn.getNotification(),
394 parentAsChild.sbn.getUserId());
399 public void testCancelAllNotifications_IgnoreForegroundService() throws Exception {
400 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
401 sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
402 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
403 sbn.getId(), sbn.getNotification(), sbn.getUserId());
404 mBinderService.cancelAllNotifications(PKG, sbn.getUserId());
406 StatusBarNotification[] notifs =
407 mBinderService.getActiveNotifications(sbn.getPackageName());
408 assertEquals(1, notifs.length);
412 public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception {
413 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
414 sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
415 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
416 sbn.getId(), sbn.getNotification(), sbn.getUserId());
417 mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId());
419 StatusBarNotification[] notifs =
420 mBinderService.getActiveNotifications(sbn.getPackageName());
421 assertEquals(1, notifs.length);
425 public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception {
426 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
427 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
428 sbn.getId(), sbn.getNotification(), sbn.getUserId());
429 mBinderService.cancelAllNotifications(null, sbn.getUserId());
431 StatusBarNotification[] notifs =
432 mBinderService.getActiveNotifications(sbn.getPackageName());
433 assertEquals(0, notifs.length);
437 public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception {
438 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
439 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
440 sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL);
441 // Null pkg is how we signal a user switch.
442 mBinderService.cancelAllNotifications(null, sbn.getUserId());
444 StatusBarNotification[] notifs =
445 mBinderService.getActiveNotifications(sbn.getPackageName());
446 assertEquals(1, notifs.length);
450 public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception {
451 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
452 sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
453 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
454 sbn.getId(), sbn.getNotification(), sbn.getUserId());
455 mInternalService.removeForegroundServiceFlagFromNotification(PKG, sbn.getId(),
458 StatusBarNotification[] notifs =
459 mBinderService.getActiveNotifications(sbn.getPackageName());
460 assertEquals(0, notifs[0].getNotification().flags & Notification.FLAG_FOREGROUND_SERVICE);
464 public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception {
465 final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
466 sbn.getNotification().flags =
467 Notification.FLAG_ONGOING_EVENT | Notification.FLAG_FOREGROUND_SERVICE;
468 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
469 sbn.getId(), sbn.getNotification(), sbn.getUserId());
470 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT;
471 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
472 sbn.getId(), sbn.getNotification(), sbn.getUserId());
473 mBinderService.cancelNotificationWithTag(PKG, "tag", sbn.getId(), sbn.getUserId());
475 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
479 public void testFindGroupNotificationsLocked() throws Exception {
480 // make sure the same notification can be found in both lists and returned
481 final NotificationRecord group1 = generateNotificationRecord(
482 mTestNotificationChannel, 1, "group1", true);
483 mNotificationManagerService.addEnqueuedNotification(group1);
484 mNotificationManagerService.addNotification(group1);
486 // should not be returned
487 final NotificationRecord group2 = generateNotificationRecord(
488 mTestNotificationChannel, 2, "group2", true);
489 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
490 group2.sbn.getId(), group2.sbn.getNotification(), group2.sbn.getUserId());
493 // should not be returned
494 final NotificationRecord nonGroup = generateNotificationRecord(
495 mTestNotificationChannel, 3, null, false);
496 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
497 nonGroup.sbn.getId(), nonGroup.sbn.getNotification(), nonGroup.sbn.getUserId());
500 // same group, child, should be returned
501 final NotificationRecord group1Child = generateNotificationRecord(
502 mTestNotificationChannel, 4, "group1", false);
503 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null, group1Child.sbn.getId(),
504 group1Child.sbn.getNotification(), group1Child.sbn.getUserId());
507 List<NotificationRecord> inGroup1 =
508 mNotificationManagerService.findGroupNotificationsLocked(PKG, group1.getGroupKey(),
509 group1.sbn.getUserId());
510 assertEquals(3, inGroup1.size());
511 for (NotificationRecord record : inGroup1) {
512 assertTrue(record.getGroupKey().equals(group1.getGroupKey()));
513 assertTrue(record.sbn.getId() == 1 || record.sbn.getId() == 4);
518 public void testTvExtenderChannelOverride_onTv() throws Exception {
519 mNotificationManagerService.setIsTelevision(true);
520 mNotificationManagerService.setRankingHelper(mRankingHelper);
521 when(mRankingHelper.getNotificationChannel(
522 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
523 new NotificationChannel("foo", "foo", NotificationManager.IMPORTANCE_HIGH));
525 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
526 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
527 generateNotificationRecord(null, tv).getNotification(), 0);
528 verify(mRankingHelper, times(1)).getNotificationChannel(
529 anyString(), anyInt(), eq("foo"), anyBoolean());
533 public void testTvExtenderChannelOverride_notOnTv() throws Exception {
534 mNotificationManagerService.setIsTelevision(false);
535 mNotificationManagerService.setRankingHelper(mRankingHelper);
536 when(mRankingHelper.getNotificationChannel(
537 anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
538 mTestNotificationChannel);
540 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
541 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
542 generateNotificationRecord(null, tv).getNotification(), 0);
543 verify(mRankingHelper, times(1)).getNotificationChannel(
544 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), anyBoolean());
548 public void testCreateChannelNotifyListener() throws Exception {
549 List<String> associations = new ArrayList<>();
550 associations.add("a");
551 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
552 mNotificationManagerService.setRankingHelper(mRankingHelper);
553 when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
554 eq(mTestNotificationChannel.getId()), anyBoolean()))
555 .thenReturn(mTestNotificationChannel);
556 NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW);
557 when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
558 eq(channel2.getId()), anyBoolean()))
559 .thenReturn(channel2);
561 reset(mNotificationListeners);
562 mBinderService.createNotificationChannels(PKG,
563 new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2)));
564 verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
565 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
566 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
567 verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
568 eq(Process.myUserHandle()), eq(channel2),
569 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
573 public void testCreateChannelGroupNotifyListener() throws Exception {
574 List<String> associations = new ArrayList<>();
575 associations.add("a");
576 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
577 mNotificationManagerService.setRankingHelper(mRankingHelper);
578 NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b");
579 NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m");
581 reset(mNotificationListeners);
582 mBinderService.createNotificationChannelGroups(PKG,
583 new ParceledListSlice(Arrays.asList(group1, group2)));
584 verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG),
585 eq(Process.myUserHandle()), eq(group1),
586 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
587 verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG),
588 eq(Process.myUserHandle()), eq(group2),
589 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED));
593 public void testUpdateChannelNotifyListener() throws Exception {
594 List<String> associations = new ArrayList<>();
595 associations.add("a");
596 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
597 mNotificationManagerService.setRankingHelper(mRankingHelper);
598 mTestNotificationChannel.setLightColor(Color.CYAN);
599 when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
600 eq(mTestNotificationChannel.getId()), anyBoolean()))
601 .thenReturn(mTestNotificationChannel);
603 reset(mNotificationListeners);
604 mBinderService.updateNotificationChannelForPackage(PKG, 0, mTestNotificationChannel);
605 verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
606 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
607 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
611 public void testDeleteChannelNotifyListener() throws Exception {
612 List<String> associations = new ArrayList<>();
613 associations.add("a");
614 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
615 mNotificationManagerService.setRankingHelper(mRankingHelper);
616 when(mRankingHelper.getNotificationChannel(eq(PKG), anyInt(),
617 eq(mTestNotificationChannel.getId()), anyBoolean()))
618 .thenReturn(mTestNotificationChannel);
619 reset(mNotificationListeners);
620 mBinderService.deleteNotificationChannel(PKG, mTestNotificationChannel.getId());
621 verify(mNotificationListeners, times(1)).notifyNotificationChannelChanged(eq(PKG),
622 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
623 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
627 public void testDeleteChannelGroupNotifyListener() throws Exception {
628 List<String> associations = new ArrayList<>();
629 associations.add("a");
630 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
631 NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c");
632 mNotificationManagerService.setRankingHelper(mRankingHelper);
633 when(mRankingHelper.getNotificationChannelGroup(eq(ncg.getId()), eq(PKG), anyInt()))
635 reset(mNotificationListeners);
636 mBinderService.deleteNotificationChannelGroup(PKG, ncg.getId());
637 verify(mNotificationListeners, times(1)).notifyNotificationChannelGroupChanged(eq(PKG),
638 eq(Process.myUserHandle()), eq(ncg),
639 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED));
643 public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception {
644 mNotificationManagerService.setRankingHelper(mRankingHelper);
645 List<String> associations = new ArrayList<>();
646 associations.add("a");
647 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
649 mBinderService.updateNotificationChannelFromPrivilegedListener(
650 null, PKG, Process.myUserHandle(), mTestNotificationChannel);
652 verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any());
654 verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG),
655 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
656 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
660 public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
661 mNotificationManagerService.setRankingHelper(mRankingHelper);
662 List<String> associations = new ArrayList<>();
663 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
666 mBinderService.updateNotificationChannelFromPrivilegedListener(
667 null, PKG, Process.myUserHandle(), mTestNotificationChannel);
668 fail("listeners that don't have a companion device shouldn't be able to call this");
669 } catch (SecurityException e) {
673 verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any());
675 verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG),
676 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
677 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
681 public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception {
682 mNotificationManagerService.setRankingHelper(mRankingHelper);
683 List<String> associations = new ArrayList<>();
684 associations.add("a");
685 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
686 mListener = mock(ManagedServices.ManagedServiceInfo.class);
687 mListener.component = new ComponentName(PKG, PKG);
688 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
689 when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
692 mBinderService.updateNotificationChannelFromPrivilegedListener(
693 null, PKG, UserHandle.ALL, mTestNotificationChannel);
694 fail("incorrectly allowed a change to a user listener cannot see");
695 } catch (SecurityException e) {
699 verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any());
701 verify(mNotificationListeners, never()).notifyNotificationChannelChanged(eq(PKG),
702 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
703 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
707 public void testGetNotificationChannelFromPrivilegedListener_success() throws Exception {
708 mNotificationManagerService.setRankingHelper(mRankingHelper);
709 List<String> associations = new ArrayList<>();
710 associations.add("a");
711 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
713 mBinderService.getNotificationChannelsFromPrivilegedListener(
714 null, PKG, Process.myUserHandle());
716 verify(mRankingHelper, times(1)).getNotificationChannels(
717 anyString(), anyInt(), anyBoolean());
721 public void testGetNotificationChannelFromPrivilegedListener_noAccess() throws Exception {
722 mNotificationManagerService.setRankingHelper(mRankingHelper);
723 List<String> associations = new ArrayList<>();
724 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
727 mBinderService.getNotificationChannelsFromPrivilegedListener(
728 null, PKG, Process.myUserHandle());
729 fail("listeners that don't have a companion device shouldn't be able to call this");
730 } catch (SecurityException e) {
734 verify(mRankingHelper, never()).getNotificationChannels(
735 anyString(), anyInt(), anyBoolean());
739 public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception {
740 mNotificationManagerService.setRankingHelper(mRankingHelper);
741 List<String> associations = new ArrayList<>();
742 associations.add("a");
743 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
744 mListener = mock(ManagedServices.ManagedServiceInfo.class);
745 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
746 when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
749 mBinderService.getNotificationChannelsFromPrivilegedListener(
750 null, PKG, Process.myUserHandle());
751 fail("listener getting channels from a user they cannot see");
752 } catch (SecurityException e) {
756 verify(mRankingHelper, never()).getNotificationChannels(
757 anyString(), anyInt(), anyBoolean());
761 public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception {
762 mNotificationManagerService.setRankingHelper(mRankingHelper);
763 List<String> associations = new ArrayList<>();
764 associations.add("a");
765 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
767 mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
768 null, PKG, Process.myUserHandle());
770 verify(mRankingHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt());
774 public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception {
775 mNotificationManagerService.setRankingHelper(mRankingHelper);
776 List<String> associations = new ArrayList<>();
777 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
780 mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
781 null, PKG, Process.myUserHandle());
782 fail("listeners that don't have a companion device shouldn't be able to call this");
783 } catch (SecurityException e) {
787 verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
791 public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception {
792 mNotificationManagerService.setRankingHelper(mRankingHelper);
793 List<String> associations = new ArrayList<>();
794 when(mCompanionMgr.getAssociations(PKG, uid)).thenReturn(associations);
795 mListener = mock(ManagedServices.ManagedServiceInfo.class);
796 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
797 when(mNotificationListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
800 mBinderService.getNotificationChannelGroupsFromPrivilegedListener(
801 null, PKG, Process.myUserHandle());
802 fail("listeners that don't have a companion device shouldn't be able to call this");
803 } catch (SecurityException e) {
807 verify(mRankingHelper, never()).getNotificationChannelGroups(anyString(), anyInt());
811 public void testHasCompanionDevice_failure() throws Exception {
812 when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow(
813 new IllegalArgumentException());
814 mNotificationManagerService.hasCompanionDevice(mListener);
818 public void testHasCompanionDevice_noService() throws Exception {
819 mNotificationManagerService = new TestableNotificationManagerService(mContext);
821 assertFalse(mNotificationManagerService.hasCompanionDevice(mListener));
825 public void testSnoozeRunnable_snoozeNonGrouped() throws Exception {
826 final NotificationRecord nonGrouped = generateNotificationRecord(
827 mTestNotificationChannel, 1, null, false);
828 final NotificationRecord grouped = generateNotificationRecord(
829 mTestNotificationChannel, 2, "group", false);
830 mNotificationManagerService.addNotification(grouped);
831 mNotificationManagerService.addNotification(nonGrouped);
833 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
834 mNotificationManagerService.new SnoozeNotificationRunnable(
835 nonGrouped.getKey(), 100, null);
836 snoozeNotificationRunnable.run();
838 // only snooze the one notification
839 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
843 public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception {
844 final NotificationRecord parent = generateNotificationRecord(
845 mTestNotificationChannel, 1, "group", true);
846 final NotificationRecord child = generateNotificationRecord(
847 mTestNotificationChannel, 2, "group", false);
848 final NotificationRecord child2 = generateNotificationRecord(
849 mTestNotificationChannel, 3, "group", false);
850 mNotificationManagerService.addNotification(parent);
851 mNotificationManagerService.addNotification(child);
852 mNotificationManagerService.addNotification(child2);
854 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
855 mNotificationManagerService.new SnoozeNotificationRunnable(
856 parent.getKey(), 100, null);
857 snoozeNotificationRunnable.run();
859 // snooze parent and children
860 verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong());
864 public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception {
865 final NotificationRecord parent = generateNotificationRecord(
866 mTestNotificationChannel, 1, "group", true);
867 final NotificationRecord child = generateNotificationRecord(
868 mTestNotificationChannel, 2, "group", false);
869 final NotificationRecord child2 = generateNotificationRecord(
870 mTestNotificationChannel, 3, "group", false);
871 mNotificationManagerService.addNotification(parent);
872 mNotificationManagerService.addNotification(child);
873 mNotificationManagerService.addNotification(child2);
875 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
876 mNotificationManagerService.new SnoozeNotificationRunnable(
877 child2.getKey(), 100, null);
878 snoozeNotificationRunnable.run();
880 // only snooze the one child
881 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
885 public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception {
886 final NotificationRecord parent = generateNotificationRecord(
887 mTestNotificationChannel, 1, "group", true);
888 assertTrue(parent.sbn.getNotification().isGroupSummary());
889 final NotificationRecord child = generateNotificationRecord(
890 mTestNotificationChannel, 2, "group", false);
891 mNotificationManagerService.addNotification(parent);
892 mNotificationManagerService.addNotification(child);
894 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
895 mNotificationManagerService.new SnoozeNotificationRunnable(
896 child.getKey(), 100, null);
897 snoozeNotificationRunnable.run();
899 // snooze child and summary
900 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong());
904 public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception {
905 final NotificationRecord child = generateNotificationRecord(
906 mTestNotificationChannel, 2, "group", false);
907 mNotificationManagerService.addNotification(child);
909 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable =
910 mNotificationManagerService.new SnoozeNotificationRunnable(
911 child.getKey(), 100, null);
912 snoozeNotificationRunnable.run();
915 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong());
919 public void testPostGroupChild_unsnoozeParent() throws Exception {
920 final NotificationRecord child = generateNotificationRecord(
921 mTestNotificationChannel, 2, "group", false);
923 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
924 child.sbn.getId(), child.sbn.getNotification(), child.sbn.getUserId());
927 verify(mSnoozeHelper, times(1)).repostGroupSummary(
928 anyString(), anyInt(), eq(child.getGroupKey()));
932 public void testPostNonGroup_noUnsnoozing() throws Exception {
933 final NotificationRecord record = generateNotificationRecord(
934 mTestNotificationChannel, 2, null, false);
936 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
937 record.sbn.getId(), record.sbn.getNotification(), record.sbn.getUserId());
940 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());
944 public void testPostGroupSummary_noUnsnoozing() throws Exception {
945 final NotificationRecord parent = generateNotificationRecord(
946 mTestNotificationChannel, 2, "group", true);
948 mBinderService.enqueueNotificationWithTag(PKG, "opPkg", null,
949 parent.sbn.getId(), parent.sbn.getNotification(), parent.sbn.getUserId());
952 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString());