2 * Copyright (C) 2014 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.
16 package com.android.server.notification;
18 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
19 import static android.app.NotificationManager.IMPORTANCE_HIGH;
20 import static android.app.NotificationManager.IMPORTANCE_LOW;
21 import static android.app.NotificationManager.IMPORTANCE_MAX;
22 import static android.app.NotificationManager.IMPORTANCE_NONE;
23 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
25 import static junit.framework.Assert.assertNull;
26 import static junit.framework.Assert.fail;
28 import org.json.JSONArray;
29 import org.json.JSONObject;
30 import org.junit.Before;
31 import org.junit.Ignore;
32 import org.junit.Test;
33 import org.junit.runner.RunWith;
35 import com.android.internal.util.FastXmlSerializer;
37 import org.mockito.Mock;
38 import org.mockito.MockitoAnnotations;
39 import org.xmlpull.v1.XmlPullParser;
40 import org.xmlpull.v1.XmlSerializer;
42 import android.app.Notification;
43 import android.app.NotificationChannelGroup;
44 import android.content.Context;
45 import android.app.NotificationChannel;
46 import android.app.NotificationManager;
47 import android.content.pm.ApplicationInfo;
48 import android.content.pm.PackageManager;
49 import android.content.res.Resources;
50 import android.graphics.Color;
51 import android.media.AudioAttributes;
52 import android.net.Uri;
53 import android.os.Build;
54 import android.os.UserHandle;
55 import android.provider.Settings.Secure;
56 import android.service.notification.StatusBarNotification;
57 import android.support.test.InstrumentationRegistry;
58 import android.support.test.runner.AndroidJUnit4;
59 import android.test.suitebuilder.annotation.SmallTest;
60 import android.util.ArrayMap;
61 import android.util.Xml;
63 import java.io.BufferedInputStream;
64 import java.io.BufferedOutputStream;
65 import java.io.ByteArrayInputStream;
66 import java.io.ByteArrayOutputStream;
67 import java.util.ArrayList;
68 import java.util.Arrays;
69 import java.util.HashMap;
70 import java.util.List;
72 import java.util.Objects;
73 import java.util.concurrent.ThreadLocalRandom;
75 import static org.junit.Assert.assertEquals;
76 import static org.junit.Assert.assertFalse;
77 import static org.junit.Assert.assertNotNull;
78 import static org.junit.Assert.assertTrue;
79 import static org.mockito.Matchers.anyInt;
80 import static org.mockito.Matchers.anyString;
81 import static org.mockito.Matchers.eq;
82 import static org.mockito.Mockito.mock;
83 import static org.mockito.Mockito.never;
84 import static org.mockito.Mockito.times;
85 import static org.mockito.Mockito.verify;
86 import static org.mockito.Mockito.when;
89 @RunWith(AndroidJUnit4.class)
90 public class RankingHelperTest extends NotificationTestCase {
91 private static final String PKG = "com.android.server.notification";
92 private static final int UID = 0;
93 private static final UserHandle USER = UserHandle.of(0);
94 private static final String UPDATED_PKG = "updatedPkg";
95 private static final int UID2 = 1111;
96 private static final UserHandle USER2 = UserHandle.of(10);
97 private static final String TEST_CHANNEL_ID = "test_channel_id";
99 @Mock NotificationUsageStats mUsageStats;
100 @Mock RankingHandler mHandler;
101 @Mock PackageManager mPm;
102 @Mock Context mContext;
104 private Notification mNotiGroupGSortA;
105 private Notification mNotiGroupGSortB;
106 private Notification mNotiNoGroup;
107 private Notification mNotiNoGroup2;
108 private Notification mNotiNoGroupSortA;
109 private NotificationRecord mRecordGroupGSortA;
110 private NotificationRecord mRecordGroupGSortB;
111 private NotificationRecord mRecordNoGroup;
112 private NotificationRecord mRecordNoGroup2;
113 private NotificationRecord mRecordNoGroupSortA;
114 private RankingHelper mHelper;
115 private AudioAttributes mAudioAttributes;
118 public void setUp() throws Exception {
119 MockitoAnnotations.initMocks(this);
120 UserHandle user = UserHandle.ALL;
122 final ApplicationInfo legacy = new ApplicationInfo();
123 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
124 final ApplicationInfo upgrade = new ApplicationInfo();
125 upgrade.targetSdkVersion = Build.VERSION_CODES.O;
126 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
127 when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade);
128 when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID);
129 when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2);
130 when(mContext.getResources()).thenReturn(
131 InstrumentationRegistry.getContext().getResources());
132 when(mContext.getContentResolver()).thenReturn(
133 InstrumentationRegistry.getContext().getContentResolver());
134 when(mContext.getPackageManager()).thenReturn(mPm);
135 when(mContext.getApplicationInfo()).thenReturn(legacy);
136 // most tests assume badging is enabled
137 Secure.putIntForUser(getContext().getContentResolver(),
138 Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID));
140 mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats,
141 new String[] {ImportanceExtractor.class.getName()});
143 mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
144 .setContentTitle("A")
149 mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification(
150 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user,
151 null, System.currentTimeMillis()), getDefaultChannel());
153 mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID)
154 .setContentTitle("B")
159 mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification(
160 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user,
161 null, System.currentTimeMillis()), getDefaultChannel());
163 mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID)
164 .setContentTitle("C")
167 mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification(
168 PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user,
169 null, System.currentTimeMillis()), getDefaultChannel());
171 mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID)
172 .setContentTitle("D")
175 mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification(
176 PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user,
177 null, System.currentTimeMillis()), getDefaultChannel());
179 mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID)
180 .setContentTitle("E")
184 mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification(
185 PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user,
186 null, System.currentTimeMillis()), getDefaultChannel());
188 mAudioAttributes = new AudioAttributes.Builder()
189 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN)
190 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE)
191 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED)
195 private NotificationChannel getDefaultChannel() {
196 return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name",
200 private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup,
201 String... channelIds)
203 XmlSerializer serializer = new FastXmlSerializer();
204 ByteArrayOutputStream baos = new ByteArrayOutputStream();
205 serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
206 serializer.startDocument(null, true);
207 mHelper.writeXml(serializer, forBackup);
208 serializer.endDocument();
210 for (String channelId : channelIds) {
211 mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId);
216 private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore) throws Exception {
217 XmlPullParser parser = Xml.newPullParser();
218 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(stream.toByteArray())),
221 mHelper.readXml(parser, forRestore);
224 private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
225 assertEquals(expected.getId(), actual.getId());
226 assertEquals(expected.getName(), actual.getName());
227 assertEquals(expected.getDescription(), actual.getDescription());
228 assertEquals(expected.shouldVibrate(), actual.shouldVibrate());
229 assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
230 assertEquals(expected.getImportance(), actual.getImportance());
231 assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
232 assertEquals(expected.getSound(), actual.getSound());
233 assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
234 assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
235 assertEquals(expected.getGroup(), actual.getGroup());
236 assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes());
237 assertEquals(expected.getLightColor(), actual.getLightColor());
240 private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) {
241 assertEquals(expected.getId(), actual.getId());
242 assertEquals(expected.getName(), actual.getName());
245 private NotificationChannel getChannel() {
246 return new NotificationChannel("id", "name", IMPORTANCE_LOW);
250 public void testFindAfterRankingWithASplitGroup() throws Exception {
251 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3);
252 notificationList.add(mRecordGroupGSortA);
253 notificationList.add(mRecordGroupGSortB);
254 notificationList.add(mRecordNoGroup);
255 notificationList.add(mRecordNoGroupSortA);
256 mHelper.sort(notificationList);
257 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortA) >= 0);
258 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortB) >= 0);
259 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroup) >= 0);
260 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0);
264 public void testSortShouldNotThrowWithPlainNotifications() throws Exception {
265 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
266 notificationList.add(mRecordNoGroup);
267 notificationList.add(mRecordNoGroup2);
268 mHelper.sort(notificationList);
272 public void testSortShouldNotThrowOneSorted() throws Exception {
273 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2);
274 notificationList.add(mRecordNoGroup);
275 notificationList.add(mRecordNoGroupSortA);
276 mHelper.sort(notificationList);
280 public void testSortShouldNotThrowOneNotification() throws Exception {
281 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
282 notificationList.add(mRecordNoGroup);
283 mHelper.sort(notificationList);
287 public void testSortShouldNotThrowOneSortKey() throws Exception {
288 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1);
289 notificationList.add(mRecordGroupGSortB);
290 mHelper.sort(notificationList);
294 public void testSortShouldNotThrowOnEmptyList() throws Exception {
295 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>();
296 mHelper.sort(notificationList);
300 public void testChannelXml() throws Exception {
301 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
302 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
303 NotificationChannel channel1 =
304 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
305 NotificationChannel channel2 =
306 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
307 channel2.setDescription("descriptions for all");
308 channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
309 channel2.enableLights(true);
310 channel2.setBypassDnd(true);
311 channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
312 channel2.enableVibration(true);
313 channel2.setGroup(ncg.getId());
314 channel2.setVibrationPattern(new long[]{100, 67, 145, 156});
315 channel2.setLightColor(Color.BLUE);
317 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
318 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
319 mHelper.createNotificationChannel(PKG, UID, channel1, true);
320 mHelper.createNotificationChannel(PKG, UID, channel2, false);
322 mHelper.setShowBadge(PKG, UID, true);
324 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(),
325 channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
326 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});
328 loadStreamXml(baos, false);
330 assertTrue(mHelper.canShowBadge(PKG, UID));
331 assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
332 compareChannels(channel2,
333 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
335 List<NotificationChannelGroup> actualGroups =
336 mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
337 boolean foundNcg = false;
338 for (NotificationChannelGroup actual : actualGroups) {
339 if (ncg.getId().equals(actual.getId())) {
341 compareGroups(ncg, actual);
342 } else if (ncg2.getId().equals(actual.getId())) {
343 compareGroups(ncg2, actual);
346 assertTrue(foundNcg);
348 boolean foundChannel2Group = false;
349 for (NotificationChannelGroup actual : actualGroups) {
350 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
351 foundChannel2Group = true;
355 assertTrue(foundChannel2Group);
359 public void testChannelXmlForBackup() throws Exception {
360 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
361 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
362 NotificationChannel channel1 =
363 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
364 NotificationChannel channel2 =
365 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
366 channel2.setDescription("descriptions for all");
367 channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
368 channel2.enableLights(true);
369 channel2.setBypassDnd(true);
370 channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
371 channel2.enableVibration(false);
372 channel2.setGroup(ncg.getId());
373 channel2.setLightColor(Color.BLUE);
374 NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
375 channel3.enableVibration(true);
377 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
378 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
379 mHelper.createNotificationChannel(PKG, UID, channel1, true);
380 mHelper.createNotificationChannel(PKG, UID, channel2, false);
381 mHelper.createNotificationChannel(PKG, UID, channel3, false);
382 mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true);
384 mHelper.setShowBadge(PKG, UID, true);
386 mHelper.setImportance(UPDATED_PKG, UID2, IMPORTANCE_NONE);
388 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(),
389 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
390 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG, UPDATED_PKG},
391 new int[]{UID, UID2});
393 mHelper.setShowBadge(UPDATED_PKG, UID2, true);
395 loadStreamXml(baos, true);
397 assertEquals(IMPORTANCE_NONE, mHelper.getImportance(UPDATED_PKG, UID2));
398 assertTrue(mHelper.canShowBadge(PKG, UID));
399 assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
400 compareChannels(channel2,
401 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
402 compareChannels(channel3,
403 mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
405 List<NotificationChannelGroup> actualGroups =
406 mHelper.getNotificationChannelGroups(PKG, UID, false).getList();
407 boolean foundNcg = false;
408 for (NotificationChannelGroup actual : actualGroups) {
409 if (ncg.getId().equals(actual.getId())) {
411 compareGroups(ncg, actual);
412 } else if (ncg2.getId().equals(actual.getId())) {
413 compareGroups(ncg2, actual);
416 assertTrue(foundNcg);
418 boolean foundChannel2Group = false;
419 for (NotificationChannelGroup actual : actualGroups) {
420 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) {
421 foundChannel2Group = true;
425 assertTrue(foundChannel2Group);
429 public void testChannelXml_backup() throws Exception {
430 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
431 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
432 NotificationChannel channel1 =
433 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
434 NotificationChannel channel2 =
435 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
436 NotificationChannel channel3 =
437 new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
438 channel3.setGroup(ncg.getId());
440 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
441 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
442 mHelper.createNotificationChannel(PKG, UID, channel1, true);
443 mHelper.createNotificationChannel(PKG, UID, channel2, false);
444 mHelper.createNotificationChannel(PKG, UID, channel3, true);
446 mHelper.deleteNotificationChannel(PKG, UID, channel1.getId());
447 mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId());
448 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
450 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(),
451 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
452 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID});
454 XmlPullParser parser = Xml.newPullParser();
455 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
458 mHelper.readXml(parser, true);
460 assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false));
461 assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false));
462 assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID));
463 //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID));
464 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false));
468 public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
469 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
470 NotificationChannel.DEFAULT_CHANNEL_ID);
472 loadStreamXml(baos, false);
474 final NotificationChannel updated = mHelper.getNotificationChannel(PKG, UID,
475 NotificationChannel.DEFAULT_CHANNEL_ID, false);
476 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance());
477 assertFalse(updated.canBypassDnd());
478 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility());
479 assertEquals(0, updated.getUserLockedFields());
483 public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception {
484 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
485 NotificationChannel.DEFAULT_CHANNEL_ID, false);
486 defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
487 mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
489 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
490 NotificationChannel.DEFAULT_CHANNEL_ID);
492 loadStreamXml(baos, false);
494 assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
495 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
499 public void testChannelXml_upgradeCreateDefaultChannel() throws Exception {
500 final String preupgradeXml = "<ranking version=\"1\">\n"
501 + "<package name=\"" + PKG
502 + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH
503 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\""
504 + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID + "\" />\n"
505 + "<package name=\"" + UPDATED_PKG + "\" uid=\"" + UID2 + "\" visibility=\""
506 + Notification.VISIBILITY_PRIVATE + "\" />\n"
508 XmlPullParser parser = Xml.newPullParser();
509 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
512 mHelper.readXml(parser, false);
514 final NotificationChannel updated1 =
515 mHelper.getNotificationChannel(PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
516 assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance());
517 assertTrue(updated1.canBypassDnd());
518 assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility());
519 assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE
520 | NotificationChannel.USER_LOCKED_PRIORITY
521 | NotificationChannel.USER_LOCKED_VISIBILITY,
522 updated1.getUserLockedFields());
524 // No Default Channel created for updated packages
525 assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2,
526 NotificationChannel.DEFAULT_CHANNEL_ID, false));
530 public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception {
531 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
532 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
533 assertTrue(defaultChannel != null);
534 ByteArrayOutputStream baos =
535 writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID);
536 // Load package at higher sdk.
537 final ApplicationInfo upgraded = new ApplicationInfo();
538 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
539 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
540 loadStreamXml(baos, false);
542 // Default Channel should be gone.
543 assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
544 NotificationChannel.DEFAULT_CHANNEL_ID, false));
548 public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception {
549 mHelper.createNotificationChannel(PKG, UID,
550 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
551 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
552 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
554 // Load package at higher sdk.
555 final ApplicationInfo upgraded = new ApplicationInfo();
556 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
557 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded);
558 loadStreamXml(baos, false);
560 // Default Channel should be gone.
561 assertEquals(null, mHelper.getNotificationChannel(PKG, UID,
562 NotificationChannel.DEFAULT_CHANNEL_ID, false));
566 public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception {
567 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
568 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
569 mHelper.createNotificationChannel(PKG, UID,
570 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
572 loadStreamXml(baos, false);
574 // Should still have the newly created channel that wasn't in the xml.
575 assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null);
579 public void testCreateChannel_blocked() throws Exception {
580 mHelper.setImportance(PKG, UID, IMPORTANCE_NONE);
582 mHelper.createNotificationChannel(PKG, UID,
583 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true);
587 public void testCreateChannel_badImportance() throws Exception {
589 mHelper.createNotificationChannel(PKG, UID,
590 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), true);
591 fail("Was allowed to create a channel with invalid importance");
592 } catch (IllegalArgumentException e) {
596 mHelper.createNotificationChannel(PKG, UID,
597 new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), true);
598 fail("Was allowed to create a channel with invalid importance");
599 } catch (IllegalArgumentException e) {
603 mHelper.createNotificationChannel(PKG, UID,
604 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), true);
605 fail("Was allowed to create a channel with invalid importance");
606 } catch (IllegalArgumentException e) {
609 mHelper.createNotificationChannel(PKG, UID,
610 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true);
611 mHelper.createNotificationChannel(PKG, UID,
612 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true);
617 public void testUpdate() throws Exception {
618 // no fields locked by user
619 final NotificationChannel channel =
620 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
621 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
622 channel.enableLights(true);
623 channel.setBypassDnd(true);
624 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
626 mHelper.createNotificationChannel(PKG, UID, channel, false);
628 // same id, try to update all fields
629 final NotificationChannel channel2 =
630 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH);
631 channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes);
632 channel2.enableLights(false);
633 channel2.setBypassDnd(false);
634 channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
636 mHelper.updateNotificationChannel(PKG, UID, channel2);
638 // all fields should be changed
639 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false));
641 verify(mHandler, times(1)).requestSort();
645 public void testUpdate_preUpgrade_updatesAppFields() throws Exception {
646 mHelper.setImportance(PKG, UID, IMPORTANCE_UNSPECIFIED);
647 assertTrue(mHelper.canShowBadge(PKG, UID));
648 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
649 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
650 mHelper.getPackageVisibility(PKG, UID));
652 NotificationChannel defaultChannel = mHelper.getNotificationChannel(
653 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false);
655 defaultChannel.setShowBadge(false);
656 defaultChannel.setImportance(IMPORTANCE_NONE);
657 defaultChannel.setBypassDnd(true);
658 defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
660 mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
662 // ensure app level fields are changed
663 assertFalse(mHelper.canShowBadge(PKG, UID));
664 assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG, UID));
665 assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG, UID));
666 assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG, UID));
670 public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception {
671 final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
673 mHelper.createNotificationChannel(PKG, UID, channel, false);
674 assertTrue(mHelper.canShowBadge(PKG, UID));
675 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
676 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
677 mHelper.getPackageVisibility(PKG, UID));
679 channel.setShowBadge(false);
680 channel.setImportance(IMPORTANCE_NONE);
681 channel.setBypassDnd(true);
682 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
684 mHelper.updateNotificationChannel(PKG, UID, channel);
686 // ensure app level fields are not changed
687 assertTrue(mHelper.canShowBadge(PKG, UID));
688 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID));
689 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE,
690 mHelper.getPackageVisibility(PKG, UID));
691 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
695 public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception {
696 assertEquals(null, mHelper.getNotificationChannel(PKG, UID, "garbage", false));
700 public void testCreateChannel_CannotChangeHiddenFields() throws Exception {
701 final NotificationChannel channel =
702 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
703 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
704 channel.enableLights(true);
705 channel.setBypassDnd(true);
706 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
707 channel.setShowBadge(true);
709 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
710 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
712 channel.lockFields(lockMask);
714 mHelper.createNotificationChannel(PKG, UID, channel, true);
716 NotificationChannel savedChannel =
717 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
719 assertEquals(channel.getName(), savedChannel.getName());
720 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
721 assertFalse(savedChannel.canBypassDnd());
722 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
723 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
725 verify(mHandler, never()).requestSort();
729 public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception {
730 final NotificationChannel channel =
731 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
732 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
733 channel.enableLights(true);
734 channel.setBypassDnd(true);
735 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
736 channel.setShowBadge(true);
738 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) {
739 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i];
741 channel.lockFields(lockMask);
743 mHelper.createNotificationChannel(PKG, UID, channel, true);
745 NotificationChannel savedChannel =
746 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
748 assertEquals(channel.getName(), savedChannel.getName());
749 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights());
750 assertFalse(savedChannel.canBypassDnd());
751 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility());
752 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge());
756 public void testClearLockedFields() throws Exception {
757 final NotificationChannel channel = getChannel();
758 mHelper.clearLockedFields(channel);
759 assertEquals(0, channel.getUserLockedFields());
761 channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
762 | NotificationChannel.USER_LOCKED_IMPORTANCE);
763 mHelper.clearLockedFields(channel);
764 assertEquals(0, channel.getUserLockedFields());
768 public void testLockFields_soundAndVibration() throws Exception {
769 mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
771 final NotificationChannel update1 = getChannel();
772 update1.setSound(new Uri.Builder().scheme("test").build(),
773 new AudioAttributes.Builder().build());
774 update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
775 mHelper.updateNotificationChannel(PKG, UID, update1);
776 assertEquals(NotificationChannel.USER_LOCKED_SOUND,
777 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
778 .getUserLockedFields());
780 NotificationChannel update2 = getChannel();
781 update2.enableVibration(true);
782 mHelper.updateNotificationChannel(PKG, UID, update2);
783 assertEquals(NotificationChannel.USER_LOCKED_SOUND
784 | NotificationChannel.USER_LOCKED_VIBRATION,
785 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
786 .getUserLockedFields());
790 public void testLockFields_vibrationAndLights() throws Exception {
791 mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
793 final NotificationChannel update1 = getChannel();
794 update1.setVibrationPattern(new long[]{7945, 46 ,246});
795 mHelper.updateNotificationChannel(PKG, UID, update1);
796 assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
797 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
798 .getUserLockedFields());
800 final NotificationChannel update2 = getChannel();
801 update2.enableLights(true);
802 mHelper.updateNotificationChannel(PKG, UID, update2);
803 assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
804 | NotificationChannel.USER_LOCKED_LIGHTS,
805 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
806 .getUserLockedFields());
810 public void testLockFields_lightsAndImportance() throws Exception {
811 mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
813 final NotificationChannel update1 = getChannel();
814 update1.setLightColor(Color.GREEN);
815 mHelper.updateNotificationChannel(PKG, UID, update1);
816 assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
817 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
818 .getUserLockedFields());
820 final NotificationChannel update2 = getChannel();
821 update2.setImportance(IMPORTANCE_DEFAULT);
822 mHelper.updateNotificationChannel(PKG, UID, update2);
823 assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
824 | NotificationChannel.USER_LOCKED_IMPORTANCE,
825 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
826 .getUserLockedFields());
830 public void testLockFields_visibilityAndDndAndBadge() throws Exception {
831 mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
833 mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false)
834 .getUserLockedFields());
836 final NotificationChannel update1 = getChannel();
837 update1.setBypassDnd(true);
838 mHelper.updateNotificationChannel(PKG, UID, update1);
839 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
840 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
841 .getUserLockedFields());
843 final NotificationChannel update2 = getChannel();
844 update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
845 mHelper.updateNotificationChannel(PKG, UID, update2);
846 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
847 | NotificationChannel.USER_LOCKED_VISIBILITY,
848 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
849 .getUserLockedFields());
851 final NotificationChannel update3 = getChannel();
852 update3.setShowBadge(false);
853 mHelper.updateNotificationChannel(PKG, UID, update3);
854 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
855 | NotificationChannel.USER_LOCKED_VISIBILITY
856 | NotificationChannel.USER_LOCKED_SHOW_BADGE,
857 mHelper.getNotificationChannel(PKG, UID, update3.getId(), false)
858 .getUserLockedFields());
862 public void testDeleteNonExistentChannel() throws Exception {
863 mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist");
867 public void testGetDeletedChannel() throws Exception {
868 NotificationChannel channel = getChannel();
869 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
870 channel.enableLights(true);
871 channel.setBypassDnd(true);
872 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
873 channel.enableVibration(true);
874 channel.setVibrationPattern(new long[]{100, 67, 145, 156});
876 mHelper.createNotificationChannel(PKG, UID, channel, true);
877 mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
879 // Does not return deleted channel
880 NotificationChannel response =
881 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false);
882 assertNull(response);
884 // Returns deleted channel
885 response = mHelper.getNotificationChannel(PKG, UID, channel.getId(), true);
886 compareChannels(channel, response);
887 assertTrue(response.isDeleted());
891 public void testGetDeletedChannels() throws Exception {
892 Map<String, NotificationChannel> channelMap = new HashMap<>();
893 NotificationChannel channel =
894 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
895 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes);
896 channel.enableLights(true);
897 channel.setBypassDnd(true);
898 channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
899 channel.enableVibration(true);
900 channel.setVibrationPattern(new long[]{100, 67, 145, 156});
901 channelMap.put(channel.getId(), channel);
902 NotificationChannel channel2 =
903 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
904 channelMap.put(channel2.getId(), channel2);
905 mHelper.createNotificationChannel(PKG, UID, channel, true);
906 mHelper.createNotificationChannel(PKG, UID, channel2, true);
908 mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
910 // Returns only non-deleted channels
911 List<NotificationChannel> channels =
912 mHelper.getNotificationChannels(PKG, UID, false).getList();
913 assertEquals(2, channels.size()); // Default channel + non-deleted channel
914 for (NotificationChannel nc : channels) {
915 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
916 compareChannels(channel2, nc);
920 // Returns deleted channels too
921 channels = mHelper.getNotificationChannels(PKG, UID, true).getList();
922 assertEquals(3, channels.size()); // Includes default channel
923 for (NotificationChannel nc : channels) {
924 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) {
925 compareChannels(channelMap.get(nc.getId()), nc);
931 public void testGetDeletedChannelCount() throws Exception {
932 NotificationChannel channel =
933 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
934 NotificationChannel channel2 =
935 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
936 NotificationChannel channel3 =
937 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH);
938 mHelper.createNotificationChannel(PKG, UID, channel, true);
939 mHelper.createNotificationChannel(PKG, UID, channel2, true);
940 mHelper.createNotificationChannel(PKG, UID, channel3, true);
942 mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
943 mHelper.deleteNotificationChannel(PKG, UID, channel3.getId());
945 assertEquals(2, mHelper.getDeletedChannelCount(PKG, UID));
946 assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID2));
950 public void testCreateDeletedChannel() throws Exception {
951 long[] vibration = new long[]{100, 67, 145, 156};
952 NotificationChannel channel =
953 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
954 channel.setVibrationPattern(vibration);
956 mHelper.createNotificationChannel(PKG, UID, channel, true);
957 mHelper.deleteNotificationChannel(PKG, UID, channel.getId());
959 NotificationChannel newChannel = new NotificationChannel(
960 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
961 newChannel.setVibrationPattern(new long[]{100});
963 mHelper.createNotificationChannel(PKG, UID, newChannel, true);
965 // No long deleted, using old settings
966 compareChannels(channel,
967 mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false));
971 public void testOnlyHasDefaultChannel() throws Exception {
972 assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID));
973 assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2));
975 mHelper.createNotificationChannel(PKG, UID, getChannel(), true);
976 assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID));
980 public void testCreateChannel_defaultChannelId() throws Exception {
982 mHelper.createNotificationChannel(PKG, UID, new NotificationChannel(
983 NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true);
984 fail("Allowed to create default channel");
985 } catch (IllegalArgumentException e) {
991 public void testCreateChannel_alreadyExists() throws Exception {
992 long[] vibration = new long[]{100, 67, 145, 156};
993 NotificationChannel channel =
994 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
995 channel.setVibrationPattern(vibration);
997 mHelper.createNotificationChannel(PKG, UID, channel, true);
999 NotificationChannel newChannel = new NotificationChannel(
1000 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH);
1001 newChannel.setVibrationPattern(new long[]{100});
1003 mHelper.createNotificationChannel(PKG, UID, newChannel, true);
1005 // Old settings not overridden
1006 compareChannels(channel,
1007 mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false));
1011 public void testCreateChannel_noOverrideSound() throws Exception {
1012 Uri sound = new Uri.Builder().scheme("test").build();
1013 final NotificationChannel channel = new NotificationChannel("id2", "name2",
1014 NotificationManager.IMPORTANCE_DEFAULT);
1015 channel.setSound(sound, mAudioAttributes);
1016 mHelper.createNotificationChannel(PKG, UID, channel, true);
1017 assertEquals(sound, mHelper.getNotificationChannel(
1018 PKG, UID, channel.getId(), false).getSound());
1022 public void testPermanentlyDeleteChannels() throws Exception {
1023 NotificationChannel channel1 =
1024 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1025 NotificationChannel channel2 =
1026 new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
1028 mHelper.createNotificationChannel(PKG, UID, channel1, true);
1029 mHelper.createNotificationChannel(PKG, UID, channel2, false);
1031 mHelper.permanentlyDeleteNotificationChannels(PKG, UID);
1033 // Only default channel remains
1034 assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
1038 public void testDeleteGroup() throws Exception {
1039 NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted");
1040 NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted");
1041 NotificationChannel nonGroupedNonDeletedChannel =
1042 new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH);
1043 NotificationChannel groupedButNotDeleted =
1044 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT);
1045 groupedButNotDeleted.setGroup("not");
1046 NotificationChannel groupedAndDeleted =
1047 new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT);
1048 groupedAndDeleted.setGroup("totally");
1050 mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true);
1051 mHelper.createNotificationChannelGroup(PKG, UID, deleted, true);
1052 mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true);
1053 mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true);
1054 mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true);
1056 mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId());
1058 assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG, UID));
1059 assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG, UID));
1061 assertNull(mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), false));
1062 compareChannels(groupedAndDeleted,
1063 mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), true));
1065 compareChannels(groupedButNotDeleted,
1066 mHelper.getNotificationChannel(PKG, UID, groupedButNotDeleted.getId(), false));
1067 compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel(
1068 PKG, UID, nonGroupedNonDeletedChannel.getId(), false));
1071 assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID).size());
1073 verify(mHandler, never()).requestSort();
1077 public void testOnUserRemoved() throws Exception {
1078 int[] user0Uids = {98, 235, 16, 3782};
1079 int[] user1Uids = new int[user0Uids.length];
1080 for (int i = 0; i < user0Uids.length; i++) {
1081 user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i];
1083 final ApplicationInfo legacy = new ApplicationInfo();
1084 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
1085 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy);
1087 // create records with the default channel for all user 0 and user 1 uids
1088 mHelper.getImportance(PKG, user0Uids[i]);
1089 mHelper.getImportance(PKG, user1Uids[i]);
1092 mHelper.onUserRemoved(1);
1094 // user 0 records remain
1095 for (int i = 0; i < user0Uids.length; i++) {
1097 mHelper.getNotificationChannels(PKG, user0Uids[i], false).getList().size());
1099 // user 1 records are gone
1100 for (int i = 0; i < user1Uids.length; i++) {
1102 mHelper.getNotificationChannels(PKG, user1Uids[i], false).getList().size());
1107 public void testOnPackageChanged_packageRemoval() throws Exception {
1109 NotificationChannel channel1 =
1110 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1111 mHelper.createNotificationChannel(PKG, UID, channel1, true);
1113 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1115 assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size());
1118 mHelper.createNotificationChannel(PKG, UID, channel1, true);
1120 mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1121 assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
1125 public void testOnPackageChanged_packageRemoval_importance() throws Exception {
1126 mHelper.setImportance(PKG, UID, NotificationManager.IMPORTANCE_HIGH);
1128 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1130 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
1134 public void testOnPackageChanged_packageRemoval_groups() throws Exception {
1135 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1136 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1137 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
1138 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
1140 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID});
1142 assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size());
1146 public void testOnPackageChange_downgradeTargetSdk() throws Exception {
1147 // create channel as api 26
1148 mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true);
1150 // install new app version targeting 25
1151 final ApplicationInfo legacy = new ApplicationInfo();
1152 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
1153 when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(legacy);
1154 mHelper.onPackagesChanged(
1155 false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2});
1157 // make sure the default channel was readded
1158 //assertEquals(2, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size());
1159 assertNotNull(mHelper.getNotificationChannel(
1160 UPDATED_PKG, UID2, NotificationChannel.DEFAULT_CHANNEL_ID, false));
1164 public void testRecordDefaults() throws Exception {
1165 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID));
1166 assertEquals(true, mHelper.canShowBadge(PKG, UID));
1167 assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size());
1171 public void testCreateGroup() throws Exception {
1172 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1173 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1174 assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG, UID).iterator().next());
1175 verify(mHandler, never()).requestSort();
1179 public void testCannotCreateChannel_badGroup() throws Exception {
1180 NotificationChannel channel1 =
1181 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1182 channel1.setGroup("garbage");
1184 mHelper.createNotificationChannel(PKG, UID, channel1, true);
1185 fail("Created a channel with a bad group");
1186 } catch (IllegalArgumentException e) {
1191 public void testCannotCreateChannel_goodGroup() throws Exception {
1192 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1193 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1194 NotificationChannel channel1 =
1195 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1196 channel1.setGroup(ncg.getId());
1197 mHelper.createNotificationChannel(PKG, UID, channel1, true);
1199 assertEquals(ncg.getId(),
1200 mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup());
1204 public void testGetChannelGroups() throws Exception {
1205 NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s");
1206 mHelper.createNotificationChannelGroup(PKG, UID, unused, true);
1207 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1208 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1209 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2");
1210 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true);
1212 NotificationChannel channel1 =
1213 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1214 channel1.setGroup(ncg.getId());
1215 mHelper.createNotificationChannel(PKG, UID, channel1, true);
1216 NotificationChannel channel1a =
1217 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH);
1218 channel1a.setGroup(ncg.getId());
1219 mHelper.createNotificationChannel(PKG, UID, channel1a, true);
1221 NotificationChannel channel2 =
1222 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH);
1223 channel2.setGroup(ncg2.getId());
1224 mHelper.createNotificationChannel(PKG, UID, channel2, true);
1226 NotificationChannel channel3 =
1227 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH);
1228 mHelper.createNotificationChannel(PKG, UID, channel3, true);
1230 List<NotificationChannelGroup> actual =
1231 mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
1232 assertEquals(3, actual.size());
1233 for (NotificationChannelGroup group : actual) {
1234 if (group.getId() == null) {
1235 assertEquals(2, group.getChannels().size()); // misc channel too
1236 assertTrue(channel3.getId().equals(group.getChannels().get(0).getId())
1237 || channel3.getId().equals(group.getChannels().get(1).getId()));
1238 } else if (group.getId().equals(ncg.getId())) {
1239 assertEquals(2, group.getChannels().size());
1240 if (group.getChannels().get(0).getId().equals(channel1.getId())) {
1241 assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId()));
1242 } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) {
1243 assertTrue(group.getChannels().get(1).getId().equals(channel1.getId()));
1245 fail("expected channel not found");
1247 } else if (group.getId().equals(ncg2.getId())) {
1248 assertEquals(1, group.getChannels().size());
1249 assertEquals(channel2.getId(), group.getChannels().get(0).getId());
1255 public void testGetChannelGroups_noSideEffects() throws Exception {
1256 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1");
1257 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true);
1259 NotificationChannel channel1 =
1260 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
1261 channel1.setGroup(ncg.getId());
1262 mHelper.createNotificationChannel(PKG, UID, channel1, true);
1263 mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
1265 channel1.setImportance(IMPORTANCE_LOW);
1266 mHelper.updateNotificationChannel(PKG, UID, channel1);
1268 List<NotificationChannelGroup> actual =
1269 mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
1271 assertEquals(2, actual.size());
1272 for (NotificationChannelGroup group : actual) {
1273 if (Objects.equals(group.getId(), ncg.getId())) {
1274 assertEquals(1, group.getChannels().size());
1280 public void testCreateChannel_updateName() throws Exception {
1281 NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT);
1282 mHelper.createNotificationChannel(PKG, UID, nc, true);
1283 NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
1284 assertEquals("hello", actual.getName());
1286 nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH);
1287 mHelper.createNotificationChannel(PKG, UID, nc, true);
1289 actual = mHelper.getNotificationChannel(PKG, UID, "id", false);
1290 assertEquals("goodbye", actual.getName());
1291 assertEquals(IMPORTANCE_DEFAULT, actual.getImportance());
1293 verify(mHandler, times(1)).requestSort();
1297 public void testDumpChannelsJson() throws Exception {
1298 final ApplicationInfo upgrade = new ApplicationInfo();
1299 upgrade.targetSdkVersion = Build.VERSION_CODES.O;
1301 when(mPm.getApplicationInfoAsUser(
1302 anyString(), anyInt(), anyInt())).thenReturn(upgrade);
1303 } catch (PackageManager.NameNotFoundException e) {
1305 ArrayMap<String, Integer> expectedChannels = new ArrayMap<>();
1306 int numPackages = ThreadLocalRandom.current().nextInt(1, 5);
1307 for (int i = 0; i < numPackages; i++) {
1308 String pkgName = "pkg" + i;
1309 int numChannels = ThreadLocalRandom.current().nextInt(1, 10);
1310 for (int j = 0; j < numChannels; j++) {
1311 mHelper.createNotificationChannel(pkgName, UID,
1312 new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true);
1314 expectedChannels.put(pkgName, numChannels);
1317 // delete the first channel of the first package
1318 String pkg = expectedChannels.keyAt(0);
1319 mHelper.deleteNotificationChannel("pkg" + 0, UID, "0");
1320 // dump should not include deleted channels
1321 int count = expectedChannels.get(pkg);
1322 expectedChannels.put(pkg, count - 1);
1324 JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter());
1325 assertEquals(numPackages, actual.length());
1326 for (int i = 0; i < numPackages; i++) {
1327 JSONObject object = actual.getJSONObject(i);
1328 assertTrue(expectedChannels.containsKey(object.get("packageName")));
1329 assertEquals(expectedChannels.get(object.get("packageName")).intValue(),
1330 object.getInt("channelCount"));
1335 public void testBadgingOverrideTrue() throws Exception {
1336 Secure.putIntForUser(getContext().getContentResolver(),
1337 Secure.NOTIFICATION_BADGING, 1,
1338 USER.getIdentifier());
1339 mHelper.updateBadgingEnabled(); // would be called by settings observer
1340 assertTrue(mHelper.badgingEnabled(USER));
1344 public void testBadgingOverrideFalse() throws Exception {
1345 Secure.putIntForUser(getContext().getContentResolver(),
1346 Secure.NOTIFICATION_BADGING, 0,
1347 USER.getIdentifier());
1348 mHelper.updateBadgingEnabled(); // would be called by settings observer
1349 assertFalse(mHelper.badgingEnabled(USER));
1353 public void testBadgingForUserAll() throws Exception {
1355 mHelper.badgingEnabled(UserHandle.ALL);
1356 } catch (Exception e) {
1357 fail("just don't throw");
1362 public void testBadgingOverrideUserIsolation() throws Exception {
1363 Secure.putIntForUser(getContext().getContentResolver(),
1364 Secure.NOTIFICATION_BADGING, 0,
1365 USER.getIdentifier());
1366 Secure.putIntForUser(getContext().getContentResolver(),
1367 Secure.NOTIFICATION_BADGING, 1,
1368 USER2.getIdentifier());
1369 mHelper.updateBadgingEnabled(); // would be called by settings observer
1370 assertFalse(mHelper.badgingEnabled(USER));
1371 assertTrue(mHelper.badgingEnabled(USER2));
1375 public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
1376 String newLabel = "bananas!";
1377 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
1378 NotificationChannel.DEFAULT_CHANNEL_ID, false);
1379 assertFalse(newLabel.equals(defaultChannel.getName()));
1381 Resources res = mock(Resources.class);
1382 when(mContext.getResources()).thenReturn(res);
1383 when(res.getString(com.android.internal.R.string.default_notification_channel_label))
1384 .thenReturn(newLabel);
1386 mHelper.onLocaleChanged(mContext, USER.getIdentifier());
1388 assertEquals(newLabel, mHelper.getNotificationChannel(PKG, UID,
1389 NotificationChannel.DEFAULT_CHANNEL_ID, false).getName());