1 /* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.server.notification; 17 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; 24 25 import static junit.framework.Assert.assertNull; 26 import static junit.framework.Assert.fail; 27 28 import static org.junit.Assert.assertEquals; 29 import static org.junit.Assert.assertFalse; 30 import static org.junit.Assert.assertNotNull; 31 import static org.junit.Assert.assertTrue; 32 import static org.mockito.ArgumentMatchers.any; 33 import static org.mockito.Matchers.anyInt; 34 import static org.mockito.Matchers.anyString; 35 import static org.mockito.Matchers.eq; 36 import static org.mockito.Mockito.atLeast; 37 import static org.mockito.Mockito.mock; 38 import static org.mockito.Mockito.never; 39 import static org.mockito.Mockito.reset; 40 import static org.mockito.Mockito.times; 41 import static org.mockito.Mockito.verify; 42 import static org.mockito.Mockito.when; 43 44 import android.app.Notification; 45 import android.app.NotificationChannel; 46 import android.app.NotificationChannelGroup; 47 import android.app.NotificationManager; 48 import android.content.ContentProvider; 49 import android.content.Context; 50 import android.content.IContentProvider; 51 import android.content.pm.ApplicationInfo; 52 import android.content.pm.PackageInfo; 53 import android.content.pm.PackageManager; 54 import android.content.pm.Signature; 55 import android.content.res.Resources; 56 import android.graphics.Color; 57 import android.media.AudioAttributes; 58 import android.net.Uri; 59 import android.os.Build; 60 import android.os.UserHandle; 61 import android.provider.Settings; 62 import android.provider.Settings.Secure; 63 import android.service.notification.StatusBarNotification; 64 import android.support.test.InstrumentationRegistry; 65 import android.support.test.runner.AndroidJUnit4; 66 import android.test.suitebuilder.annotation.SmallTest; 67 import android.testing.TestableContentResolver; 68 import android.util.ArrayMap; 69 import android.util.Xml; 70 71 import com.android.internal.util.FastXmlSerializer; 72 import com.android.server.UiServiceTestCase; 73 74 import org.json.JSONArray; 75 import org.json.JSONObject; 76 import org.junit.Before; 77 import org.junit.Test; 78 import org.junit.runner.RunWith; 79 import org.mockito.Mock; 80 import org.mockito.MockitoAnnotations; 81 import org.xmlpull.v1.XmlPullParser; 82 import org.xmlpull.v1.XmlSerializer; 83 84 import java.io.BufferedInputStream; 85 import java.io.BufferedOutputStream; 86 import java.io.ByteArrayInputStream; 87 import java.io.ByteArrayOutputStream; 88 import java.util.ArrayList; 89 import java.util.Arrays; 90 import java.util.HashMap; 91 import java.util.List; 92 import java.util.Map; 93 import java.util.Objects; 94 import java.util.concurrent.ThreadLocalRandom; 95 96 @SmallTest 97 @RunWith(AndroidJUnit4.class) 98 public class RankingHelperTest extends UiServiceTestCase { 99 private static final String PKG = "com.android.server.notification"; 100 private static final int UID = 0; 101 private static final UserHandle USER = UserHandle.of(0); 102 private static final String UPDATED_PKG = "updatedPkg"; 103 private static final int UID2 = 1111; 104 private static final String SYSTEM_PKG = "android"; 105 private static final int SYSTEM_UID= 1000; 106 private static final UserHandle USER2 = UserHandle.of(10); 107 private static final String TEST_CHANNEL_ID = "test_channel_id"; 108 private static final String TEST_AUTHORITY = "test"; 109 private static final Uri SOUND_URI = 110 Uri.parse("content://" + TEST_AUTHORITY + "/internal/audio/media/10"); 111 private static final Uri CANONICAL_SOUND_URI = 112 Uri.parse("content://" + TEST_AUTHORITY 113 + "/internal/audio/media/10?title=Test&canonical=1"); 114 115 @Mock NotificationUsageStats mUsageStats; 116 @Mock RankingHandler mHandler; 117 @Mock PackageManager mPm; 118 @Mock IContentProvider mTestIContentProvider; 119 @Mock Context mContext; 120 @Mock ZenModeHelper mMockZenModeHelper; 121 122 private NotificationManager.Policy mTestNotificationPolicy; 123 private Notification mNotiGroupGSortA; 124 private Notification mNotiGroupGSortB; 125 private Notification mNotiNoGroup; 126 private Notification mNotiNoGroup2; 127 private Notification mNotiNoGroupSortA; 128 private NotificationRecord mRecordGroupGSortA; 129 private NotificationRecord mRecordGroupGSortB; 130 private NotificationRecord mRecordNoGroup; 131 private NotificationRecord mRecordNoGroup2; 132 private NotificationRecord mRecordNoGroupSortA; 133 private RankingHelper mHelper; 134 private AudioAttributes mAudioAttributes; 135 136 @Before 137 public void setUp() throws Exception { 138 MockitoAnnotations.initMocks(this); 139 UserHandle user = UserHandle.ALL; 140 141 final ApplicationInfo legacy = new ApplicationInfo(); 142 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 143 final ApplicationInfo upgrade = new ApplicationInfo(); 144 upgrade.targetSdkVersion = Build.VERSION_CODES.O; 145 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy); 146 when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade); 147 when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade); 148 when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID); 149 when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2); 150 when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID); 151 PackageInfo info = mock(PackageInfo.class); 152 info.signatures = new Signature[] {mock(Signature.class)}; 153 when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info); 154 when(mPm.getPackageInfoAsUser(eq(PKG), anyInt(), anyInt())) 155 .thenReturn(mock(PackageInfo.class)); 156 when(mContext.getResources()).thenReturn( 157 InstrumentationRegistry.getContext().getResources()); 158 when(mContext.getContentResolver()).thenReturn( 159 InstrumentationRegistry.getContext().getContentResolver()); 160 when(mContext.getPackageManager()).thenReturn(mPm); 161 when(mContext.getApplicationInfo()).thenReturn(legacy); 162 // most tests assume badging is enabled 163 TestableContentResolver contentResolver = getContext().getContentResolver(); 164 contentResolver.setFallbackToExisting(false); 165 Secure.putIntForUser(contentResolver, 166 Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID)); 167 168 ContentProvider testContentProvider = mock(ContentProvider.class); 169 when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider); 170 contentResolver.addProvider(TEST_AUTHORITY, testContentProvider); 171 172 when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI))) 173 .thenReturn(CANONICAL_SOUND_URI); 174 when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI))) 175 .thenReturn(CANONICAL_SOUND_URI); 176 when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI))) 177 .thenReturn(SOUND_URI); 178 179 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 180 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND); 181 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 182 mHelper = new RankingHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 183 mUsageStats, new String[] {ImportanceExtractor.class.getName()}); 184 resetZenModeHelper(); 185 186 mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID) 187 .setContentTitle("A") 188 .setGroup("G") 189 .setSortKey("A") 190 .setWhen(1205) 191 .build(); 192 mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification( 193 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user, 194 null, System.currentTimeMillis()), getDefaultChannel()); 195 196 mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID) 197 .setContentTitle("B") 198 .setGroup("G") 199 .setSortKey("B") 200 .setWhen(1200) 201 .build(); 202 mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification( 203 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user, 204 null, System.currentTimeMillis()), getDefaultChannel()); 205 206 mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID) 207 .setContentTitle("C") 208 .setWhen(1201) 209 .build(); 210 mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification( 211 PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user, 212 null, System.currentTimeMillis()), getDefaultChannel()); 213 214 mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID) 215 .setContentTitle("D") 216 .setWhen(1202) 217 .build(); 218 mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification( 219 PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user, 220 null, System.currentTimeMillis()), getDefaultChannel()); 221 222 mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID) 223 .setContentTitle("E") 224 .setWhen(1201) 225 .setSortKey("A") 226 .build(); 227 mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification( 228 PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user, 229 null, System.currentTimeMillis()), getDefaultChannel()); 230 231 mAudioAttributes = new AudioAttributes.Builder() 232 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) 233 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 234 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED) 235 .build(); 236 } 237 238 private NotificationChannel getDefaultChannel() { 239 return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name", 240 IMPORTANCE_LOW); 241 } 242 243 private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup, 244 String... channelIds) 245 throws Exception { 246 XmlSerializer serializer = new FastXmlSerializer(); 247 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 248 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 249 serializer.startDocument(null, true); 250 mHelper.writeXml(serializer, forBackup); 251 serializer.endDocument(); 252 serializer.flush(); 253 for (String channelId : channelIds) { 254 mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId); 255 } 256 return baos; 257 } 258 259 private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore) throws Exception { 260 loadByteArrayXml(stream.toByteArray(), forRestore); 261 } 262 263 private void loadByteArrayXml(byte[] byteArray, boolean forRestore) throws Exception { 264 XmlPullParser parser = Xml.newPullParser(); 265 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null); 266 parser.nextTag(); 267 mHelper.readXml(parser, forRestore); 268 } 269 270 private void compareChannels(NotificationChannel expected, NotificationChannel actual) { 271 assertEquals(expected.getId(), actual.getId()); 272 assertEquals(expected.getName(), actual.getName()); 273 assertEquals(expected.getDescription(), actual.getDescription()); 274 assertEquals(expected.shouldVibrate(), actual.shouldVibrate()); 275 assertEquals(expected.shouldShowLights(), actual.shouldShowLights()); 276 assertEquals(expected.getImportance(), actual.getImportance()); 277 assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility()); 278 assertEquals(expected.getSound(), actual.getSound()); 279 assertEquals(expected.canBypassDnd(), actual.canBypassDnd()); 280 assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern())); 281 assertEquals(expected.getGroup(), actual.getGroup()); 282 assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes()); 283 assertEquals(expected.getLightColor(), actual.getLightColor()); 284 } 285 286 private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) { 287 assertEquals(expected.getId(), actual.getId()); 288 assertEquals(expected.getName(), actual.getName()); 289 assertEquals(expected.getDescription(), actual.getDescription()); 290 assertEquals(expected.isBlocked(), actual.isBlocked()); 291 } 292 293 private NotificationChannel getChannel() { 294 return new NotificationChannel("id", "name", IMPORTANCE_LOW); 295 } 296 297 private NotificationChannel findChannel(List<NotificationChannel> channels, String id) { 298 for (NotificationChannel channel : channels) { 299 if (channel.getId().equals(id)) { 300 return channel; 301 } 302 } 303 return null; 304 } 305 306 private void resetZenModeHelper() { 307 reset(mMockZenModeHelper); 308 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 309 } 310 311 @Test 312 public void testFindAfterRankingWithASplitGroup() throws Exception { 313 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3); 314 notificationList.add(mRecordGroupGSortA); 315 notificationList.add(mRecordGroupGSortB); 316 notificationList.add(mRecordNoGroup); 317 notificationList.add(mRecordNoGroupSortA); 318 mHelper.sort(notificationList); 319 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortA) >= 0); 320 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortB) >= 0); 321 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroup) >= 0); 322 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0); 323 } 324 325 @Test 326 public void testSortShouldNotThrowWithPlainNotifications() throws Exception { 327 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2); 328 notificationList.add(mRecordNoGroup); 329 notificationList.add(mRecordNoGroup2); 330 mHelper.sort(notificationList); 331 } 332 333 @Test 334 public void testSortShouldNotThrowOneSorted() throws Exception { 335 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2); 336 notificationList.add(mRecordNoGroup); 337 notificationList.add(mRecordNoGroupSortA); 338 mHelper.sort(notificationList); 339 } 340 341 @Test 342 public void testSortShouldNotThrowOneNotification() throws Exception { 343 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1); 344 notificationList.add(mRecordNoGroup); 345 mHelper.sort(notificationList); 346 } 347 348 @Test 349 public void testSortShouldNotThrowOneSortKey() throws Exception { 350 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1); 351 notificationList.add(mRecordGroupGSortB); 352 mHelper.sort(notificationList); 353 } 354 355 @Test 356 public void testSortShouldNotThrowOnEmptyList() throws Exception { 357 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(); 358 mHelper.sort(notificationList); 359 } 360 361 @Test 362 public void testChannelXml() throws Exception { 363 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 364 ncg.setBlocked(true); 365 ncg.setDescription("group desc"); 366 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 367 NotificationChannel channel1 = 368 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 369 NotificationChannel channel2 = 370 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 371 channel2.setDescription("descriptions for all"); 372 channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 373 channel2.enableLights(true); 374 channel2.setBypassDnd(true); 375 channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 376 channel2.enableVibration(true); 377 channel2.setGroup(ncg.getId()); 378 channel2.setVibrationPattern(new long[]{100, 67, 145, 156}); 379 channel2.setLightColor(Color.BLUE); 380 381 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 382 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 383 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 384 mHelper.createNotificationChannel(PKG, UID, channel2, false, false); 385 386 mHelper.setShowBadge(PKG, UID, true); 387 mHelper.setAppImportanceLocked(PKG, UID); 388 389 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(), 390 channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID); 391 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID}); 392 393 loadStreamXml(baos, false); 394 395 assertTrue(mHelper.canShowBadge(PKG, UID)); 396 assertTrue(mHelper.getIsAppImportanceLocked(PKG, UID)); 397 assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false)); 398 compareChannels(channel2, 399 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 400 401 List<NotificationChannelGroup> actualGroups = 402 mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList(); 403 boolean foundNcg = false; 404 for (NotificationChannelGroup actual : actualGroups) { 405 if (ncg.getId().equals(actual.getId())) { 406 foundNcg = true; 407 compareGroups(ncg, actual); 408 } else if (ncg2.getId().equals(actual.getId())) { 409 compareGroups(ncg2, actual); 410 } 411 } 412 assertTrue(foundNcg); 413 414 boolean foundChannel2Group = false; 415 for (NotificationChannelGroup actual : actualGroups) { 416 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) { 417 foundChannel2Group = true; 418 break; 419 } 420 } 421 assertTrue(foundChannel2Group); 422 } 423 424 @Test 425 public void testChannelXmlForBackup() throws Exception { 426 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 427 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 428 NotificationChannel channel1 = 429 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 430 NotificationChannel channel2 = 431 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 432 channel2.setDescription("descriptions for all"); 433 channel2.setSound(SOUND_URI, mAudioAttributes); 434 channel2.enableLights(true); 435 channel2.setBypassDnd(true); 436 channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 437 channel2.enableVibration(false); 438 channel2.setGroup(ncg.getId()); 439 channel2.setLightColor(Color.BLUE); 440 NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); 441 channel3.enableVibration(true); 442 443 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 444 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 445 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 446 mHelper.createNotificationChannel(PKG, UID, channel2, false, false); 447 mHelper.createNotificationChannel(PKG, UID, channel3, false, false); 448 mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false); 449 450 mHelper.setShowBadge(PKG, UID, true); 451 452 mHelper.setImportance(UPDATED_PKG, UID2, IMPORTANCE_NONE); 453 454 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(), 455 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID); 456 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG, UPDATED_PKG}, 457 new int[]{UID, UID2}); 458 459 mHelper.setShowBadge(UPDATED_PKG, UID2, true); 460 461 loadStreamXml(baos, true); 462 463 assertEquals(IMPORTANCE_NONE, mHelper.getImportance(UPDATED_PKG, UID2)); 464 assertTrue(mHelper.canShowBadge(PKG, UID)); 465 assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false)); 466 compareChannels(channel2, 467 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 468 compareChannels(channel3, 469 mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false)); 470 471 List<NotificationChannelGroup> actualGroups = 472 mHelper.getNotificationChannelGroups(PKG, UID, false, true).getList(); 473 boolean foundNcg = false; 474 for (NotificationChannelGroup actual : actualGroups) { 475 if (ncg.getId().equals(actual.getId())) { 476 foundNcg = true; 477 compareGroups(ncg, actual); 478 } else if (ncg2.getId().equals(actual.getId())) { 479 compareGroups(ncg2, actual); 480 } 481 } 482 assertTrue(foundNcg); 483 484 boolean foundChannel2Group = false; 485 for (NotificationChannelGroup actual : actualGroups) { 486 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) { 487 foundChannel2Group = true; 488 break; 489 } 490 } 491 assertTrue(foundChannel2Group); 492 } 493 494 @Test 495 public void testBackupXml_backupCanonicalizedSoundUri() throws Exception { 496 NotificationChannel channel = 497 new NotificationChannel("id", "name", IMPORTANCE_LOW); 498 channel.setSound(SOUND_URI, mAudioAttributes); 499 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 500 501 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); 502 503 // Testing that in restore we are given the canonical version 504 loadStreamXml(baos, true); 505 verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI)); 506 } 507 508 @Test 509 public void testRestoreXml_withExistentCanonicalizedSoundUri() throws Exception { 510 Uri localUri = Uri.parse("content://" + TEST_AUTHORITY + "/local/url"); 511 Uri canonicalBasedOnLocal = localUri.buildUpon() 512 .appendQueryParameter("title", "Test") 513 .appendQueryParameter("canonical", "1") 514 .build(); 515 when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI))) 516 .thenReturn(canonicalBasedOnLocal); 517 when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI))) 518 .thenReturn(localUri); 519 when(mTestIContentProvider.uncanonicalize(any(), eq(canonicalBasedOnLocal))) 520 .thenReturn(localUri); 521 522 NotificationChannel channel = 523 new NotificationChannel("id", "name", IMPORTANCE_LOW); 524 channel.setSound(SOUND_URI, mAudioAttributes); 525 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 526 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); 527 528 loadStreamXml(baos, true); 529 530 NotificationChannel actualChannel = mHelper.getNotificationChannel( 531 PKG, UID, channel.getId(), false); 532 assertEquals(localUri, actualChannel.getSound()); 533 } 534 535 @Test 536 public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception { 537 Thread.sleep(3000); 538 when(mTestIContentProvider.canonicalize(any(), eq(CANONICAL_SOUND_URI))) 539 .thenReturn(null); 540 when(mTestIContentProvider.uncanonicalize(any(), eq(CANONICAL_SOUND_URI))) 541 .thenReturn(null); 542 543 NotificationChannel channel = 544 new NotificationChannel("id", "name", IMPORTANCE_LOW); 545 channel.setSound(SOUND_URI, mAudioAttributes); 546 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 547 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); 548 549 loadStreamXml(baos, true); 550 551 NotificationChannel actualChannel = mHelper.getNotificationChannel( 552 PKG, UID, channel.getId(), false); 553 assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound()); 554 } 555 556 557 /** 558 * Although we don't make backups with uncanonicalized uris anymore, we used to, so we have to 559 * handle its restore properly. 560 */ 561 @Test 562 public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception { 563 // Not a local uncanonicalized uri, simulating that it fails to exist locally 564 when(mTestIContentProvider.canonicalize(any(), eq(SOUND_URI))).thenReturn(null); 565 String id = "id"; 566 String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n" 567 + "<package name=\"com.android.server.notification\" show_badge=\"true\">\n" 568 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" " 569 + "sound=\"" + SOUND_URI + "\" " 570 + "usage=\"6\" content_type=\"0\" flags=\"1\" show_badge=\"true\" />\n" 571 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" " 572 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" 573 + "</package>\n" 574 + "</ranking>\n"; 575 576 loadByteArrayXml(backupWithUncanonicalizedSoundUri.getBytes(), true); 577 578 NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG, UID, id, false); 579 assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound()); 580 } 581 582 @Test 583 public void testBackupRestoreXml_withNullSoundUri() throws Exception { 584 NotificationChannel channel = 585 new NotificationChannel("id", "name", IMPORTANCE_LOW); 586 channel.setSound(null, mAudioAttributes); 587 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 588 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel.getId()); 589 590 loadStreamXml(baos, true); 591 592 NotificationChannel actualChannel = mHelper.getNotificationChannel( 593 PKG, UID, channel.getId(), false); 594 assertEquals(null, actualChannel.getSound()); 595 } 596 597 @Test 598 public void testChannelXml_backup() throws Exception { 599 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 600 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 601 NotificationChannel channel1 = 602 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 603 NotificationChannel channel2 = 604 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 605 NotificationChannel channel3 = 606 new NotificationChannel("id3", "name3", IMPORTANCE_LOW); 607 channel3.setGroup(ncg.getId()); 608 609 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 610 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 611 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 612 mHelper.createNotificationChannel(PKG, UID, channel2, false, false); 613 mHelper.createNotificationChannel(PKG, UID, channel3, true, false); 614 615 mHelper.deleteNotificationChannel(PKG, UID, channel1.getId()); 616 mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId()); 617 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 618 619 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(), 620 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID); 621 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID}); 622 623 XmlPullParser parser = Xml.newPullParser(); 624 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 625 null); 626 parser.nextTag(); 627 mHelper.readXml(parser, true); 628 629 assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false)); 630 assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false)); 631 assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID)); 632 //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID)); 633 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 634 } 635 636 @Test 637 public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception { 638 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 639 NotificationChannel.DEFAULT_CHANNEL_ID); 640 641 loadStreamXml(baos, false); 642 643 final NotificationChannel updated = mHelper.getNotificationChannel(PKG, UID, 644 NotificationChannel.DEFAULT_CHANNEL_ID, false); 645 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance()); 646 assertFalse(updated.canBypassDnd()); 647 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility()); 648 assertEquals(0, updated.getUserLockedFields()); 649 } 650 651 @Test 652 public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception { 653 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID, 654 NotificationChannel.DEFAULT_CHANNEL_ID, false); 655 defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 656 mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true); 657 658 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 659 NotificationChannel.DEFAULT_CHANNEL_ID); 660 661 loadStreamXml(baos, false); 662 663 assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel( 664 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance()); 665 } 666 667 @Test 668 public void testChannelXml_upgradeCreateDefaultChannel() throws Exception { 669 final String preupgradeXml = "<ranking version=\"1\">\n" 670 + "<package name=\"" + PKG 671 + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH 672 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\"" 673 + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID + "\" />\n" 674 + "<package name=\"" + UPDATED_PKG + "\" uid=\"" + UID2 + "\" visibility=\"" 675 + Notification.VISIBILITY_PRIVATE + "\" />\n" 676 + "</ranking>"; 677 XmlPullParser parser = Xml.newPullParser(); 678 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), 679 null); 680 parser.nextTag(); 681 mHelper.readXml(parser, false); 682 683 final NotificationChannel updated1 = 684 mHelper.getNotificationChannel(PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false); 685 assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance()); 686 assertTrue(updated1.canBypassDnd()); 687 assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility()); 688 assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE 689 | NotificationChannel.USER_LOCKED_PRIORITY 690 | NotificationChannel.USER_LOCKED_VISIBILITY, 691 updated1.getUserLockedFields()); 692 693 // No Default Channel created for updated packages 694 assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2, 695 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 696 } 697 698 @Test 699 public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception { 700 final NotificationChannel defaultChannel = mHelper.getNotificationChannel( 701 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false); 702 assertTrue(defaultChannel != null); 703 ByteArrayOutputStream baos = 704 writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID); 705 // Load package at higher sdk. 706 final ApplicationInfo upgraded = new ApplicationInfo(); 707 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 708 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded); 709 loadStreamXml(baos, false); 710 711 // Default Channel should be gone. 712 assertEquals(null, mHelper.getNotificationChannel(PKG, UID, 713 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 714 } 715 716 @Test 717 public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception { 718 mHelper.createNotificationChannel(PKG, UID, 719 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); 720 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 721 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); 722 723 // Load package at higher sdk. 724 final ApplicationInfo upgraded = new ApplicationInfo(); 725 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 726 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded); 727 loadStreamXml(baos, false); 728 729 // Default Channel should be gone. 730 assertEquals(null, mHelper.getNotificationChannel(PKG, UID, 731 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 732 } 733 734 @Test 735 public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception { 736 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 737 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); 738 mHelper.createNotificationChannel(PKG, UID, 739 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); 740 741 loadStreamXml(baos, false); 742 743 // Should still have the newly created channel that wasn't in the xml. 744 assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null); 745 } 746 747 @Test 748 public void testCreateChannel_blocked() throws Exception { 749 mHelper.setImportance(PKG, UID, IMPORTANCE_NONE); 750 751 mHelper.createNotificationChannel(PKG, UID, 752 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false); 753 } 754 755 @Test 756 public void testCreateChannel_badImportance() throws Exception { 757 try { 758 mHelper.createNotificationChannel(PKG, UID, 759 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), 760 true, false); 761 fail("Was allowed to create a channel with invalid importance"); 762 } catch (IllegalArgumentException e) { 763 // yay 764 } 765 try { 766 mHelper.createNotificationChannel(PKG, UID, 767 new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), 768 true, false); 769 fail("Was allowed to create a channel with invalid importance"); 770 } catch (IllegalArgumentException e) { 771 // yay 772 } 773 try { 774 mHelper.createNotificationChannel(PKG, UID, 775 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), 776 true, false); 777 fail("Was allowed to create a channel with invalid importance"); 778 } catch (IllegalArgumentException e) { 779 // yay 780 } 781 mHelper.createNotificationChannel(PKG, UID, 782 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false); 783 mHelper.createNotificationChannel(PKG, UID, 784 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false); 785 } 786 787 788 @Test 789 public void testUpdate() throws Exception { 790 // no fields locked by user 791 final NotificationChannel channel = 792 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 793 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 794 channel.enableLights(true); 795 channel.setBypassDnd(true); 796 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 797 798 mHelper.createNotificationChannel(PKG, UID, channel, false, false); 799 800 // same id, try to update all fields 801 final NotificationChannel channel2 = 802 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 803 channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes); 804 channel2.enableLights(false); 805 channel2.setBypassDnd(false); 806 channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); 807 808 mHelper.updateNotificationChannel(PKG, UID, channel2, true); 809 810 // all fields should be changed 811 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false)); 812 813 verify(mHandler, times(1)).requestSort(); 814 } 815 816 @Test 817 public void testUpdate_preUpgrade_updatesAppFields() throws Exception { 818 mHelper.setImportance(PKG, UID, IMPORTANCE_UNSPECIFIED); 819 assertTrue(mHelper.canShowBadge(PKG, UID)); 820 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); 821 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, 822 mHelper.getPackageVisibility(PKG, UID)); 823 assertFalse(mHelper.getIsAppImportanceLocked(PKG, UID)); 824 825 NotificationChannel defaultChannel = mHelper.getNotificationChannel( 826 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false); 827 828 defaultChannel.setShowBadge(false); 829 defaultChannel.setImportance(IMPORTANCE_NONE); 830 defaultChannel.setBypassDnd(true); 831 defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 832 833 mHelper.setAppImportanceLocked(PKG, UID); 834 mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true); 835 836 // ensure app level fields are changed 837 assertFalse(mHelper.canShowBadge(PKG, UID)); 838 assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG, UID)); 839 assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG, UID)); 840 assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG, UID)); 841 assertTrue(mHelper.getIsAppImportanceLocked(PKG, UID)); 842 } 843 844 @Test 845 public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception { 846 final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 847 848 mHelper.createNotificationChannel(PKG, UID, channel, false, false); 849 assertTrue(mHelper.canShowBadge(PKG, UID)); 850 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); 851 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, 852 mHelper.getPackageVisibility(PKG, UID)); 853 854 channel.setShowBadge(false); 855 channel.setImportance(IMPORTANCE_NONE); 856 channel.setBypassDnd(true); 857 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 858 859 mHelper.updateNotificationChannel(PKG, UID, channel, true); 860 861 // ensure app level fields are not changed 862 assertTrue(mHelper.canShowBadge(PKG, UID)); 863 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); 864 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, 865 mHelper.getPackageVisibility(PKG, UID)); 866 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID)); 867 } 868 869 @Test 870 public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception { 871 assertEquals(null, mHelper.getNotificationChannel(PKG, UID, "garbage", false)); 872 } 873 874 @Test 875 public void testCreateChannel_CannotChangeHiddenFields() throws Exception { 876 final NotificationChannel channel = 877 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 878 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 879 channel.enableLights(true); 880 channel.setBypassDnd(true); 881 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 882 channel.setShowBadge(true); 883 int lockMask = 0; 884 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 885 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 886 } 887 channel.lockFields(lockMask); 888 889 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 890 891 NotificationChannel savedChannel = 892 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); 893 894 assertEquals(channel.getName(), savedChannel.getName()); 895 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 896 assertFalse(savedChannel.canBypassDnd()); 897 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 898 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 899 900 verify(mHandler, never()).requestSort(); 901 } 902 903 @Test 904 public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception { 905 final NotificationChannel channel = 906 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 907 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 908 channel.enableLights(true); 909 channel.setBypassDnd(true); 910 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 911 channel.setShowBadge(true); 912 int lockMask = 0; 913 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 914 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 915 } 916 channel.lockFields(lockMask); 917 918 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 919 920 NotificationChannel savedChannel = 921 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); 922 923 assertEquals(channel.getName(), savedChannel.getName()); 924 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 925 assertFalse(savedChannel.canBypassDnd()); 926 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 927 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 928 } 929 930 @Test 931 public void testClearLockedFields() throws Exception { 932 final NotificationChannel channel = getChannel(); 933 mHelper.clearLockedFields(channel); 934 assertEquals(0, channel.getUserLockedFields()); 935 936 channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY 937 | NotificationChannel.USER_LOCKED_IMPORTANCE); 938 mHelper.clearLockedFields(channel); 939 assertEquals(0, channel.getUserLockedFields()); 940 } 941 942 @Test 943 public void testLockFields_soundAndVibration() throws Exception { 944 mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); 945 946 final NotificationChannel update1 = getChannel(); 947 update1.setSound(new Uri.Builder().scheme("test").build(), 948 new AudioAttributes.Builder().build()); 949 update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); 950 mHelper.updateNotificationChannel(PKG, UID, update1, true); 951 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY 952 | NotificationChannel.USER_LOCKED_SOUND, 953 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 954 .getUserLockedFields()); 955 956 NotificationChannel update2 = getChannel(); 957 update2.enableVibration(true); 958 mHelper.updateNotificationChannel(PKG, UID, update2, true); 959 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY 960 | NotificationChannel.USER_LOCKED_SOUND 961 | NotificationChannel.USER_LOCKED_VIBRATION, 962 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 963 .getUserLockedFields()); 964 } 965 966 @Test 967 public void testLockFields_vibrationAndLights() throws Exception { 968 mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); 969 970 final NotificationChannel update1 = getChannel(); 971 update1.setVibrationPattern(new long[]{7945, 46 ,246}); 972 mHelper.updateNotificationChannel(PKG, UID, update1, true); 973 assertEquals(NotificationChannel.USER_LOCKED_VIBRATION, 974 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 975 .getUserLockedFields()); 976 977 final NotificationChannel update2 = getChannel(); 978 update2.enableLights(true); 979 mHelper.updateNotificationChannel(PKG, UID, update2, true); 980 assertEquals(NotificationChannel.USER_LOCKED_VIBRATION 981 | NotificationChannel.USER_LOCKED_LIGHTS, 982 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 983 .getUserLockedFields()); 984 } 985 986 @Test 987 public void testLockFields_lightsAndImportance() throws Exception { 988 mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); 989 990 final NotificationChannel update1 = getChannel(); 991 update1.setLightColor(Color.GREEN); 992 mHelper.updateNotificationChannel(PKG, UID, update1, true); 993 assertEquals(NotificationChannel.USER_LOCKED_LIGHTS, 994 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 995 .getUserLockedFields()); 996 997 final NotificationChannel update2 = getChannel(); 998 update2.setImportance(IMPORTANCE_DEFAULT); 999 mHelper.updateNotificationChannel(PKG, UID, update2, true); 1000 assertEquals(NotificationChannel.USER_LOCKED_LIGHTS 1001 | NotificationChannel.USER_LOCKED_IMPORTANCE, 1002 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 1003 .getUserLockedFields()); 1004 } 1005 1006 @Test 1007 public void testLockFields_visibilityAndDndAndBadge() throws Exception { 1008 mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); 1009 assertEquals(0, 1010 mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false) 1011 .getUserLockedFields()); 1012 1013 final NotificationChannel update1 = getChannel(); 1014 update1.setBypassDnd(true); 1015 mHelper.updateNotificationChannel(PKG, UID, update1, true); 1016 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY, 1017 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 1018 .getUserLockedFields()); 1019 1020 final NotificationChannel update2 = getChannel(); 1021 update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 1022 mHelper.updateNotificationChannel(PKG, UID, update2, true); 1023 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY 1024 | NotificationChannel.USER_LOCKED_VISIBILITY, 1025 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 1026 .getUserLockedFields()); 1027 1028 final NotificationChannel update3 = getChannel(); 1029 update3.setShowBadge(false); 1030 mHelper.updateNotificationChannel(PKG, UID, update3, true); 1031 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY 1032 | NotificationChannel.USER_LOCKED_VISIBILITY 1033 | NotificationChannel.USER_LOCKED_SHOW_BADGE, 1034 mHelper.getNotificationChannel(PKG, UID, update3.getId(), false) 1035 .getUserLockedFields()); 1036 } 1037 1038 @Test 1039 public void testDeleteNonExistentChannel() throws Exception { 1040 mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist"); 1041 } 1042 1043 @Test 1044 public void testGetDeletedChannel() throws Exception { 1045 NotificationChannel channel = getChannel(); 1046 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 1047 channel.enableLights(true); 1048 channel.setBypassDnd(true); 1049 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 1050 channel.enableVibration(true); 1051 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 1052 1053 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1054 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 1055 1056 // Does not return deleted channel 1057 NotificationChannel response = 1058 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); 1059 assertNull(response); 1060 1061 // Returns deleted channel 1062 response = mHelper.getNotificationChannel(PKG, UID, channel.getId(), true); 1063 compareChannels(channel, response); 1064 assertTrue(response.isDeleted()); 1065 } 1066 1067 @Test 1068 public void testGetDeletedChannels() throws Exception { 1069 Map<String, NotificationChannel> channelMap = new HashMap<>(); 1070 NotificationChannel channel = 1071 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1072 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 1073 channel.enableLights(true); 1074 channel.setBypassDnd(true); 1075 channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); 1076 channel.enableVibration(true); 1077 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 1078 channelMap.put(channel.getId(), channel); 1079 NotificationChannel channel2 = 1080 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 1081 channelMap.put(channel2.getId(), channel2); 1082 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1083 mHelper.createNotificationChannel(PKG, UID, channel2, true, false); 1084 1085 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 1086 1087 // Returns only non-deleted channels 1088 List<NotificationChannel> channels = 1089 mHelper.getNotificationChannels(PKG, UID, false).getList(); 1090 assertEquals(2, channels.size()); // Default channel + non-deleted channel 1091 for (NotificationChannel nc : channels) { 1092 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 1093 compareChannels(channel2, nc); 1094 } 1095 } 1096 1097 // Returns deleted channels too 1098 channels = mHelper.getNotificationChannels(PKG, UID, true).getList(); 1099 assertEquals(3, channels.size()); // Includes default channel 1100 for (NotificationChannel nc : channels) { 1101 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 1102 compareChannels(channelMap.get(nc.getId()), nc); 1103 } 1104 } 1105 } 1106 1107 @Test 1108 public void testGetDeletedChannelCount() throws Exception { 1109 NotificationChannel channel = 1110 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1111 NotificationChannel channel2 = 1112 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 1113 NotificationChannel channel3 = 1114 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_HIGH); 1115 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1116 mHelper.createNotificationChannel(PKG, UID, channel2, true, false); 1117 mHelper.createNotificationChannel(PKG, UID, channel3, true, false); 1118 1119 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 1120 mHelper.deleteNotificationChannel(PKG, UID, channel3.getId()); 1121 1122 assertEquals(2, mHelper.getDeletedChannelCount(PKG, UID)); 1123 assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID2)); 1124 } 1125 1126 @Test 1127 public void testGetBlockedChannelCount() throws Exception { 1128 NotificationChannel channel = 1129 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1130 NotificationChannel channel2 = 1131 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_NONE); 1132 NotificationChannel channel3 = 1133 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_NONE); 1134 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1135 mHelper.createNotificationChannel(PKG, UID, channel2, true, false); 1136 mHelper.createNotificationChannel(PKG, UID, channel3, true, false); 1137 1138 mHelper.deleteNotificationChannel(PKG, UID, channel3.getId()); 1139 1140 assertEquals(1, mHelper.getBlockedChannelCount(PKG, UID)); 1141 assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID2)); 1142 } 1143 1144 @Test 1145 public void testCreateAndDeleteCanChannelsBypassDnd() throws Exception { 1146 // create notification channel that can't bypass dnd 1147 // expected result: areChannelsBypassingDnd = false 1148 // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false 1149 NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); 1150 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1151 assertFalse(mHelper.areChannelsBypassingDnd()); 1152 verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); 1153 resetZenModeHelper(); 1154 1155 // create notification channel that can bypass dnd 1156 // expected result: areChannelsBypassingDnd = true 1157 NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1158 channel2.setBypassDnd(true); 1159 mHelper.createNotificationChannel(PKG, UID, channel2, true, true); 1160 assertTrue(mHelper.areChannelsBypassingDnd()); 1161 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); 1162 resetZenModeHelper(); 1163 1164 // delete channels 1165 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 1166 assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND 1167 verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); 1168 resetZenModeHelper(); 1169 1170 mHelper.deleteNotificationChannel(PKG, UID, channel2.getId()); 1171 assertFalse(mHelper.areChannelsBypassingDnd()); 1172 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); 1173 resetZenModeHelper(); 1174 } 1175 1176 @Test 1177 public void testUpdateCanChannelsBypassDnd() throws Exception { 1178 // create notification channel that can't bypass dnd 1179 // expected result: areChannelsBypassingDnd = false 1180 // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false 1181 NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); 1182 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1183 assertFalse(mHelper.areChannelsBypassingDnd()); 1184 verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); 1185 resetZenModeHelper(); 1186 1187 // update channel so it CAN bypass dnd: 1188 // expected result: areChannelsBypassingDnd = true 1189 channel.setBypassDnd(true); 1190 mHelper.updateNotificationChannel(PKG, UID, channel, true); 1191 assertTrue(mHelper.areChannelsBypassingDnd()); 1192 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); 1193 resetZenModeHelper(); 1194 1195 // update channel so it can't bypass dnd: 1196 // expected result: areChannelsBypassingDnd = false 1197 channel.setBypassDnd(false); 1198 mHelper.updateNotificationChannel(PKG, UID, channel, true); 1199 assertFalse(mHelper.areChannelsBypassingDnd()); 1200 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); 1201 resetZenModeHelper(); 1202 } 1203 1204 @Test 1205 public void testSetupNewZenModeHelper_canBypass() { 1206 // start notification policy off with mAreChannelsBypassingDnd = true, but 1207 // RankingHelper should change to false 1208 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 1209 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND); 1210 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 1211 mHelper = new RankingHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 1212 mUsageStats, new String[] {ImportanceExtractor.class.getName()}); 1213 assertFalse(mHelper.areChannelsBypassingDnd()); 1214 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any()); 1215 resetZenModeHelper(); 1216 } 1217 1218 @Test 1219 public void testSetupNewZenModeHelper_cannotBypass() { 1220 // start notification policy off with mAreChannelsBypassingDnd = false 1221 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0); 1222 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 1223 mHelper = new RankingHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 1224 mUsageStats, new String[] {ImportanceExtractor.class.getName()}); 1225 assertFalse(mHelper.areChannelsBypassingDnd()); 1226 verify(mMockZenModeHelper, never()).setNotificationPolicy(any()); 1227 resetZenModeHelper(); 1228 } 1229 1230 @Test 1231 public void testCreateDeletedChannel() throws Exception { 1232 long[] vibration = new long[]{100, 67, 145, 156}; 1233 NotificationChannel channel = 1234 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1235 channel.setVibrationPattern(vibration); 1236 1237 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1238 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 1239 1240 NotificationChannel newChannel = new NotificationChannel( 1241 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 1242 newChannel.setVibrationPattern(new long[]{100}); 1243 1244 mHelper.createNotificationChannel(PKG, UID, newChannel, true, false); 1245 1246 // No long deleted, using old settings 1247 compareChannels(channel, 1248 mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false)); 1249 } 1250 1251 @Test 1252 public void testOnlyHasDefaultChannel() throws Exception { 1253 assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID)); 1254 assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2)); 1255 1256 mHelper.createNotificationChannel(PKG, UID, getChannel(), true, false); 1257 assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID)); 1258 } 1259 1260 @Test 1261 public void testCreateChannel_defaultChannelId() throws Exception { 1262 try { 1263 mHelper.createNotificationChannel(PKG, UID, new NotificationChannel( 1264 NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false); 1265 fail("Allowed to create default channel"); 1266 } catch (IllegalArgumentException e) { 1267 // pass 1268 } 1269 } 1270 1271 @Test 1272 public void testCreateChannel_alreadyExists() throws Exception { 1273 long[] vibration = new long[]{100, 67, 145, 156}; 1274 NotificationChannel channel = 1275 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1276 channel.setVibrationPattern(vibration); 1277 1278 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1279 1280 NotificationChannel newChannel = new NotificationChannel( 1281 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 1282 newChannel.setVibrationPattern(new long[]{100}); 1283 1284 mHelper.createNotificationChannel(PKG, UID, newChannel, true, false); 1285 1286 // Old settings not overridden 1287 compareChannels(channel, 1288 mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false)); 1289 } 1290 1291 @Test 1292 public void testCreateChannel_noOverrideSound() throws Exception { 1293 Uri sound = new Uri.Builder().scheme("test").build(); 1294 final NotificationChannel channel = new NotificationChannel("id2", "name2", 1295 NotificationManager.IMPORTANCE_DEFAULT); 1296 channel.setSound(sound, mAudioAttributes); 1297 mHelper.createNotificationChannel(PKG, UID, channel, true, false); 1298 assertEquals(sound, mHelper.getNotificationChannel( 1299 PKG, UID, channel.getId(), false).getSound()); 1300 } 1301 1302 @Test 1303 public void testPermanentlyDeleteChannels() throws Exception { 1304 NotificationChannel channel1 = 1305 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1306 NotificationChannel channel2 = 1307 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1308 1309 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 1310 mHelper.createNotificationChannel(PKG, UID, channel2, false, false); 1311 1312 mHelper.permanentlyDeleteNotificationChannels(PKG, UID); 1313 1314 // Only default channel remains 1315 assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size()); 1316 } 1317 1318 @Test 1319 public void testDeleteGroup() throws Exception { 1320 NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted"); 1321 NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted"); 1322 NotificationChannel nonGroupedNonDeletedChannel = 1323 new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH); 1324 NotificationChannel groupedButNotDeleted = 1325 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT); 1326 groupedButNotDeleted.setGroup("not"); 1327 NotificationChannel groupedAndDeleted = 1328 new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT); 1329 groupedAndDeleted.setGroup("totally"); 1330 1331 mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true); 1332 mHelper.createNotificationChannelGroup(PKG, UID, deleted, true); 1333 mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true, false); 1334 mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true, false); 1335 mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true, false); 1336 1337 mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId()); 1338 1339 assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG, UID)); 1340 assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG, UID)); 1341 1342 assertNull(mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), false)); 1343 compareChannels(groupedAndDeleted, 1344 mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), true)); 1345 1346 compareChannels(groupedButNotDeleted, 1347 mHelper.getNotificationChannel(PKG, UID, groupedButNotDeleted.getId(), false)); 1348 compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel( 1349 PKG, UID, nonGroupedNonDeletedChannel.getId(), false)); 1350 1351 // notDeleted 1352 assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID).size()); 1353 1354 verify(mHandler, never()).requestSort(); 1355 } 1356 1357 @Test 1358 public void testOnUserRemoved() throws Exception { 1359 int[] user0Uids = {98, 235, 16, 3782}; 1360 int[] user1Uids = new int[user0Uids.length]; 1361 for (int i = 0; i < user0Uids.length; i++) { 1362 user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i]; 1363 1364 final ApplicationInfo legacy = new ApplicationInfo(); 1365 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1366 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy); 1367 1368 // create records with the default channel for all user 0 and user 1 uids 1369 mHelper.getImportance(PKG, user0Uids[i]); 1370 mHelper.getImportance(PKG, user1Uids[i]); 1371 } 1372 1373 mHelper.onUserRemoved(1); 1374 1375 // user 0 records remain 1376 for (int i = 0; i < user0Uids.length; i++) { 1377 assertEquals(1, 1378 mHelper.getNotificationChannels(PKG, user0Uids[i], false).getList().size()); 1379 } 1380 // user 1 records are gone 1381 for (int i = 0; i < user1Uids.length; i++) { 1382 assertEquals(0, 1383 mHelper.getNotificationChannels(PKG, user1Uids[i], false).getList().size()); 1384 } 1385 } 1386 1387 @Test 1388 public void testOnPackageChanged_packageRemoval() throws Exception { 1389 // Deleted 1390 NotificationChannel channel1 = 1391 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1392 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 1393 1394 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1395 1396 assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size()); 1397 1398 // Not deleted 1399 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 1400 1401 mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1402 assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size()); 1403 } 1404 1405 @Test 1406 public void testOnPackageChanged_packageRemoval_importance() throws Exception { 1407 mHelper.setImportance(PKG, UID, NotificationManager.IMPORTANCE_HIGH); 1408 1409 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1410 1411 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID)); 1412 } 1413 1414 @Test 1415 public void testOnPackageChanged_packageRemoval_groups() throws Exception { 1416 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1417 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1418 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 1419 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 1420 1421 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1422 1423 assertEquals(0, 1424 mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList().size()); 1425 } 1426 1427 @Test 1428 public void testOnPackageChange_downgradeTargetSdk() throws Exception { 1429 // create channel as api 26 1430 mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true, false); 1431 1432 // install new app version targeting 25 1433 final ApplicationInfo legacy = new ApplicationInfo(); 1434 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1435 when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(legacy); 1436 mHelper.onPackagesChanged( 1437 false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2}); 1438 1439 // make sure the default channel was readded 1440 //assertEquals(2, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size()); 1441 assertNotNull(mHelper.getNotificationChannel( 1442 UPDATED_PKG, UID2, NotificationChannel.DEFAULT_CHANNEL_ID, false)); 1443 } 1444 1445 @Test 1446 public void testRecordDefaults() throws Exception { 1447 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID)); 1448 assertEquals(true, mHelper.canShowBadge(PKG, UID)); 1449 assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size()); 1450 } 1451 1452 @Test 1453 public void testCreateGroup() throws Exception { 1454 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1455 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1456 assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG, UID).iterator().next()); 1457 verify(mHandler, never()).requestSort(); 1458 } 1459 1460 @Test 1461 public void testCannotCreateChannel_badGroup() throws Exception { 1462 NotificationChannel channel1 = 1463 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1464 channel1.setGroup("garbage"); 1465 try { 1466 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 1467 fail("Created a channel with a bad group"); 1468 } catch (IllegalArgumentException e) { 1469 } 1470 } 1471 1472 @Test 1473 public void testCannotCreateChannel_goodGroup() throws Exception { 1474 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1475 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1476 NotificationChannel channel1 = 1477 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1478 channel1.setGroup(ncg.getId()); 1479 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 1480 1481 assertEquals(ncg.getId(), 1482 mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup()); 1483 } 1484 1485 @Test 1486 public void testGetChannelGroups() throws Exception { 1487 NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s"); 1488 mHelper.createNotificationChannelGroup(PKG, UID, unused, true); 1489 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1490 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1491 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 1492 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 1493 1494 NotificationChannel channel1 = 1495 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1496 channel1.setGroup(ncg.getId()); 1497 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 1498 NotificationChannel channel1a = 1499 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH); 1500 channel1a.setGroup(ncg.getId()); 1501 mHelper.createNotificationChannel(PKG, UID, channel1a, true, false); 1502 1503 NotificationChannel channel2 = 1504 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); 1505 channel2.setGroup(ncg2.getId()); 1506 mHelper.createNotificationChannel(PKG, UID, channel2, true, false); 1507 1508 NotificationChannel channel3 = 1509 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH); 1510 mHelper.createNotificationChannel(PKG, UID, channel3, true, false); 1511 1512 List<NotificationChannelGroup> actual = 1513 mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList(); 1514 assertEquals(3, actual.size()); 1515 for (NotificationChannelGroup group : actual) { 1516 if (group.getId() == null) { 1517 assertEquals(2, group.getChannels().size()); // misc channel too 1518 assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()) 1519 || channel3.getId().equals(group.getChannels().get(1).getId())); 1520 } else if (group.getId().equals(ncg.getId())) { 1521 assertEquals(2, group.getChannels().size()); 1522 if (group.getChannels().get(0).getId().equals(channel1.getId())) { 1523 assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId())); 1524 } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) { 1525 assertTrue(group.getChannels().get(1).getId().equals(channel1.getId())); 1526 } else { 1527 fail("expected channel not found"); 1528 } 1529 } else if (group.getId().equals(ncg2.getId())) { 1530 assertEquals(1, group.getChannels().size()); 1531 assertEquals(channel2.getId(), group.getChannels().get(0).getId()); 1532 } 1533 } 1534 } 1535 1536 @Test 1537 public void testGetChannelGroups_noSideEffects() throws Exception { 1538 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1539 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1540 1541 NotificationChannel channel1 = 1542 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1543 channel1.setGroup(ncg.getId()); 1544 mHelper.createNotificationChannel(PKG, UID, channel1, true, false); 1545 mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList(); 1546 1547 channel1.setImportance(IMPORTANCE_LOW); 1548 mHelper.updateNotificationChannel(PKG, UID, channel1, true); 1549 1550 List<NotificationChannelGroup> actual = 1551 mHelper.getNotificationChannelGroups(PKG, UID, true, true).getList(); 1552 1553 assertEquals(2, actual.size()); 1554 for (NotificationChannelGroup group : actual) { 1555 if (Objects.equals(group.getId(), ncg.getId())) { 1556 assertEquals(1, group.getChannels().size()); 1557 } 1558 } 1559 } 1560 1561 @Test 1562 public void testCreateChannel_updateName() throws Exception { 1563 NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); 1564 mHelper.createNotificationChannel(PKG, UID, nc, true, false); 1565 NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false); 1566 assertEquals("hello", actual.getName()); 1567 1568 nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH); 1569 mHelper.createNotificationChannel(PKG, UID, nc, true, false); 1570 1571 actual = mHelper.getNotificationChannel(PKG, UID, "id", false); 1572 assertEquals("goodbye", actual.getName()); 1573 assertEquals(IMPORTANCE_DEFAULT, actual.getImportance()); 1574 1575 verify(mHandler, times(1)).requestSort(); 1576 } 1577 1578 @Test 1579 public void testCreateChannel_addToGroup() throws Exception { 1580 NotificationChannelGroup group = new NotificationChannelGroup("group", ""); 1581 mHelper.createNotificationChannelGroup(PKG, UID, group, true); 1582 NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); 1583 mHelper.createNotificationChannel(PKG, UID, nc, true, false); 1584 NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false); 1585 assertNull(actual.getGroup()); 1586 1587 nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH); 1588 nc.setGroup(group.getId()); 1589 mHelper.createNotificationChannel(PKG, UID, nc, true, false); 1590 1591 actual = mHelper.getNotificationChannel(PKG, UID, "id", false); 1592 assertNotNull(actual.getGroup()); 1593 assertEquals(IMPORTANCE_DEFAULT, actual.getImportance()); 1594 1595 verify(mHandler, times(1)).requestSort(); 1596 } 1597 1598 @Test 1599 public void testDumpChannelsJson() throws Exception { 1600 final ApplicationInfo upgrade = new ApplicationInfo(); 1601 upgrade.targetSdkVersion = Build.VERSION_CODES.O; 1602 try { 1603 when(mPm.getApplicationInfoAsUser( 1604 anyString(), anyInt(), anyInt())).thenReturn(upgrade); 1605 } catch (PackageManager.NameNotFoundException e) { 1606 } 1607 ArrayMap<String, Integer> expectedChannels = new ArrayMap<>(); 1608 int numPackages = ThreadLocalRandom.current().nextInt(1, 5); 1609 for (int i = 0; i < numPackages; i++) { 1610 String pkgName = "pkg" + i; 1611 int numChannels = ThreadLocalRandom.current().nextInt(1, 10); 1612 for (int j = 0; j < numChannels; j++) { 1613 mHelper.createNotificationChannel(pkgName, UID, 1614 new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false); 1615 } 1616 expectedChannels.put(pkgName, numChannels); 1617 } 1618 1619 // delete the first channel of the first package 1620 String pkg = expectedChannels.keyAt(0); 1621 mHelper.deleteNotificationChannel("pkg" + 0, UID, "0"); 1622 // dump should not include deleted channels 1623 int count = expectedChannels.get(pkg); 1624 expectedChannels.put(pkg, count - 1); 1625 1626 JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter()); 1627 assertEquals(numPackages, actual.length()); 1628 for (int i = 0; i < numPackages; i++) { 1629 JSONObject object = actual.getJSONObject(i); 1630 assertTrue(expectedChannels.containsKey(object.get("packageName"))); 1631 assertEquals(expectedChannels.get(object.get("packageName")).intValue(), 1632 object.getInt("channelCount")); 1633 } 1634 } 1635 1636 @Test 1637 public void testBadgingOverrideTrue() throws Exception { 1638 Secure.putIntForUser(getContext().getContentResolver(), 1639 Secure.NOTIFICATION_BADGING, 1, 1640 USER.getIdentifier()); 1641 mHelper.updateBadgingEnabled(); // would be called by settings observer 1642 assertTrue(mHelper.badgingEnabled(USER)); 1643 } 1644 1645 @Test 1646 public void testBadgingOverrideFalse() throws Exception { 1647 Secure.putIntForUser(getContext().getContentResolver(), 1648 Secure.NOTIFICATION_BADGING, 0, 1649 USER.getIdentifier()); 1650 mHelper.updateBadgingEnabled(); // would be called by settings observer 1651 assertFalse(mHelper.badgingEnabled(USER)); 1652 } 1653 1654 @Test 1655 public void testBadgingForUserAll() throws Exception { 1656 try { 1657 mHelper.badgingEnabled(UserHandle.ALL); 1658 } catch (Exception e) { 1659 fail("just don't throw"); 1660 } 1661 } 1662 1663 @Test 1664 public void testBadgingOverrideUserIsolation() throws Exception { 1665 Secure.putIntForUser(getContext().getContentResolver(), 1666 Secure.NOTIFICATION_BADGING, 0, 1667 USER.getIdentifier()); 1668 Secure.putIntForUser(getContext().getContentResolver(), 1669 Secure.NOTIFICATION_BADGING, 1, 1670 USER2.getIdentifier()); 1671 mHelper.updateBadgingEnabled(); // would be called by settings observer 1672 assertFalse(mHelper.badgingEnabled(USER)); 1673 assertTrue(mHelper.badgingEnabled(USER2)); 1674 } 1675 1676 @Test 1677 public void testOnLocaleChanged_updatesDefaultChannels() throws Exception { 1678 String newLabel = "bananas!"; 1679 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID, 1680 NotificationChannel.DEFAULT_CHANNEL_ID, false); 1681 assertFalse(newLabel.equals(defaultChannel.getName())); 1682 1683 Resources res = mock(Resources.class); 1684 when(mContext.getResources()).thenReturn(res); 1685 when(res.getString(com.android.internal.R.string.default_notification_channel_label)) 1686 .thenReturn(newLabel); 1687 1688 mHelper.onLocaleChanged(mContext, USER.getIdentifier()); 1689 1690 assertEquals(newLabel, mHelper.getNotificationChannel(PKG, UID, 1691 NotificationChannel.DEFAULT_CHANNEL_ID, false).getName()); 1692 } 1693 1694 @Test 1695 public void testIsGroupBlocked_noGroup() throws Exception { 1696 assertFalse(mHelper.isGroupBlocked(PKG, UID, null)); 1697 1698 assertFalse(mHelper.isGroupBlocked(PKG, UID, "non existent group")); 1699 } 1700 1701 @Test 1702 public void testIsGroupBlocked_notBlocked() throws Exception { 1703 NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); 1704 mHelper.createNotificationChannelGroup(PKG, UID, group, true); 1705 1706 assertFalse(mHelper.isGroupBlocked(PKG, UID, group.getId())); 1707 } 1708 1709 @Test 1710 public void testIsGroupBlocked_blocked() throws Exception { 1711 NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); 1712 mHelper.createNotificationChannelGroup(PKG, UID, group, true); 1713 group.setBlocked(true); 1714 mHelper.createNotificationChannelGroup(PKG, UID, group, false); 1715 1716 assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId())); 1717 } 1718 1719 @Test 1720 public void testIsGroup_appCannotResetBlock() throws Exception { 1721 NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); 1722 mHelper.createNotificationChannelGroup(PKG, UID, group, true); 1723 NotificationChannelGroup group2 = group.clone(); 1724 group2.setBlocked(true); 1725 mHelper.createNotificationChannelGroup(PKG, UID, group2, false); 1726 assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId())); 1727 1728 NotificationChannelGroup group3 = group.clone(); 1729 group3.setBlocked(false); 1730 mHelper.createNotificationChannelGroup(PKG, UID, group3, true); 1731 assertTrue(mHelper.isGroupBlocked(PKG, UID, group.getId())); 1732 } 1733 1734 @Test 1735 public void testGetNotificationChannelGroupWithChannels() throws Exception { 1736 NotificationChannelGroup group = new NotificationChannelGroup("group", ""); 1737 NotificationChannelGroup other = new NotificationChannelGroup("something else", ""); 1738 mHelper.createNotificationChannelGroup(PKG, UID, group, true); 1739 mHelper.createNotificationChannelGroup(PKG, UID, other, true); 1740 1741 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); 1742 a.setGroup(group.getId()); 1743 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT); 1744 b.setGroup(other.getId()); 1745 NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); 1746 c.setGroup(group.getId()); 1747 NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT); 1748 1749 mHelper.createNotificationChannel(PKG, UID, a, true, false); 1750 mHelper.createNotificationChannel(PKG, UID, b, true, false); 1751 mHelper.createNotificationChannel(PKG, UID, c, true, false); 1752 mHelper.createNotificationChannel(PKG, UID, d, true, false); 1753 mHelper.deleteNotificationChannel(PKG, UID, c.getId()); 1754 1755 NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels( 1756 PKG, UID, group.getId(), true); 1757 assertEquals(2, retrieved.getChannels().size()); 1758 compareChannels(a, findChannel(retrieved.getChannels(), a.getId())); 1759 compareChannels(c, findChannel(retrieved.getChannels(), c.getId())); 1760 1761 retrieved = mHelper.getNotificationChannelGroupWithChannels( 1762 PKG, UID, group.getId(), false); 1763 assertEquals(1, retrieved.getChannels().size()); 1764 compareChannels(a, findChannel(retrieved.getChannels(), a.getId())); 1765 } 1766 1767 @Test 1768 public void testAndroidPkgCannotBypassDnd_creation() { 1769 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1770 test.setBypassDnd(true); 1771 1772 mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); 1773 1774 assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) 1775 .canBypassDnd()); 1776 } 1777 1778 @Test 1779 public void testDndPkgCanBypassDnd_creation() { 1780 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1781 test.setBypassDnd(true); 1782 1783 mHelper.createNotificationChannel(PKG, UID, test, true, true); 1784 1785 assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd()); 1786 } 1787 1788 @Test 1789 public void testNormalPkgCannotBypassDnd_creation() { 1790 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1791 test.setBypassDnd(true); 1792 1793 mHelper.createNotificationChannel(PKG, 1000, test, true, false); 1794 1795 assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); 1796 } 1797 1798 @Test 1799 public void testAndroidPkgCannotBypassDnd_update() throws Exception { 1800 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1801 mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false); 1802 1803 NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1804 update.setBypassDnd(true); 1805 mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false); 1806 1807 assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) 1808 .canBypassDnd()); 1809 } 1810 1811 @Test 1812 public void testDndPkgCanBypassDnd_update() throws Exception { 1813 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1814 mHelper.createNotificationChannel(PKG, UID, test, true, true); 1815 1816 NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1817 update.setBypassDnd(true); 1818 mHelper.createNotificationChannel(PKG, UID, update, true, true); 1819 1820 assertTrue(mHelper.getNotificationChannel(PKG, UID, "A", false).canBypassDnd()); 1821 } 1822 1823 @Test 1824 public void testNormalPkgCannotBypassDnd_update() { 1825 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1826 mHelper.createNotificationChannel(PKG, 1000, test, true, false); 1827 NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); 1828 update.setBypassDnd(true); 1829 mHelper.createNotificationChannel(PKG, 1000, update, true, false); 1830 assertFalse(mHelper.getNotificationChannel(PKG, 1000, "A", false).canBypassDnd()); 1831 } 1832 1833 @Test 1834 public void testGetBlockedAppCount_noApps() { 1835 assertEquals(0, mHelper.getBlockedAppCount(0)); 1836 } 1837 1838 @Test 1839 public void testGetBlockedAppCount_noAppsForUserId() { 1840 mHelper.setEnabled(PKG, 100, false); 1841 assertEquals(0, mHelper.getBlockedAppCount(9)); 1842 } 1843 1844 @Test 1845 public void testGetBlockedAppCount_appsForUserId() { 1846 mHelper.setEnabled(PKG, 1020, false); 1847 mHelper.setEnabled(PKG, 1030, false); 1848 mHelper.setEnabled(PKG, 1060, false); 1849 mHelper.setEnabled(PKG, 1000, true); 1850 assertEquals(3, mHelper.getBlockedAppCount(0)); 1851 } 1852 } 1853