RankingHelperTest.java revision 03fa85ddccb30a6f1dcfeaec9dcbba062e5f8573
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 */ 16package com.android.server.notification; 17 18import static android.app.NotificationManager.IMPORTANCE_HIGH; 19import static android.app.NotificationManager.IMPORTANCE_LOW; 20 21import static junit.framework.Assert.assertNull; 22import static junit.framework.Assert.fail; 23 24import org.junit.Before; 25import org.junit.Test; 26import org.junit.runner.RunWith; 27 28import com.android.internal.util.FastXmlSerializer; 29 30import org.mockito.Mock; 31import org.mockito.MockitoAnnotations; 32import org.xmlpull.v1.XmlPullParser; 33import org.xmlpull.v1.XmlSerializer; 34 35import android.app.Notification; 36import android.app.NotificationChannelGroup; 37import android.content.Context; 38import android.app.NotificationChannel; 39import android.app.NotificationManager; 40import android.content.pm.ApplicationInfo; 41import android.content.pm.PackageManager; 42import android.graphics.Color; 43import android.media.AudioAttributes; 44import android.net.Uri; 45import android.os.Build; 46import android.os.UserHandle; 47import android.service.notification.StatusBarNotification; 48import android.support.test.InstrumentationRegistry; 49import android.support.test.runner.AndroidJUnit4; 50import android.test.suitebuilder.annotation.SmallTest; 51import android.util.Xml; 52 53import java.io.BufferedInputStream; 54import java.io.BufferedOutputStream; 55import java.io.ByteArrayInputStream; 56import java.io.ByteArrayOutputStream; 57import java.util.ArrayList; 58import java.util.Arrays; 59import java.util.HashMap; 60import java.util.List; 61import java.util.Map; 62import java.util.Objects; 63 64import static org.junit.Assert.assertEquals; 65import static org.junit.Assert.assertFalse; 66import static org.junit.Assert.assertNotNull; 67import static org.junit.Assert.assertTrue; 68import static org.mockito.Matchers.anyInt; 69import static org.mockito.Matchers.eq; 70import static org.mockito.Mockito.when; 71 72@SmallTest 73@RunWith(AndroidJUnit4.class) 74public class RankingHelperTest { 75 @Mock 76 NotificationUsageStats mUsageStats; 77 @Mock 78 RankingHandler handler; 79 @Mock 80 PackageManager mPm; 81 82 private Notification mNotiGroupGSortA; 83 private Notification mNotiGroupGSortB; 84 private Notification mNotiNoGroup; 85 private Notification mNotiNoGroup2; 86 private Notification mNotiNoGroupSortA; 87 private NotificationRecord mRecordGroupGSortA; 88 private NotificationRecord mRecordGroupGSortB; 89 private NotificationRecord mRecordNoGroup; 90 private NotificationRecord mRecordNoGroup2; 91 private NotificationRecord mRecordNoGroupSortA; 92 private RankingHelper mHelper; 93 private final String pkg = "com.android.server.notification"; 94 private final int uid = 0; 95 private final String pkg2 = "pkg2"; 96 private final int uid2 = 1111111; 97 private static final String TEST_CHANNEL_ID = "test_channel_id"; 98 private AudioAttributes mAudioAttributes; 99 100 private Context getContext() { 101 return InstrumentationRegistry.getTargetContext(); 102 } 103 104 @Before 105 public void setUp() { 106 MockitoAnnotations.initMocks(this); 107 UserHandle user = UserHandle.ALL; 108 109 mHelper = new RankingHelper(getContext(), mPm, handler, mUsageStats, 110 new String[]{ImportanceExtractor.class.getName()}); 111 112 mNotiGroupGSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID) 113 .setContentTitle("A") 114 .setGroup("G") 115 .setSortKey("A") 116 .setWhen(1205) 117 .build(); 118 mRecordGroupGSortA = new NotificationRecord(getContext(), new StatusBarNotification( 119 "package", "package", 1, null, 0, 0, mNotiGroupGSortA, user, 120 null, System.currentTimeMillis()), getDefaultChannel()); 121 122 mNotiGroupGSortB = new Notification.Builder(getContext(), TEST_CHANNEL_ID) 123 .setContentTitle("B") 124 .setGroup("G") 125 .setSortKey("B") 126 .setWhen(1200) 127 .build(); 128 mRecordGroupGSortB = new NotificationRecord(getContext(), new StatusBarNotification( 129 "package", "package", 1, null, 0, 0, mNotiGroupGSortB, user, 130 null, System.currentTimeMillis()), getDefaultChannel()); 131 132 mNotiNoGroup = new Notification.Builder(getContext(), TEST_CHANNEL_ID) 133 .setContentTitle("C") 134 .setWhen(1201) 135 .build(); 136 mRecordNoGroup = new NotificationRecord(getContext(), new StatusBarNotification( 137 "package", "package", 1, null, 0, 0, mNotiNoGroup, user, 138 null, System.currentTimeMillis()), getDefaultChannel()); 139 140 mNotiNoGroup2 = new Notification.Builder(getContext(), TEST_CHANNEL_ID) 141 .setContentTitle("D") 142 .setWhen(1202) 143 .build(); 144 mRecordNoGroup2 = new NotificationRecord(getContext(), new StatusBarNotification( 145 "package", "package", 1, null, 0, 0, mNotiNoGroup2, user, 146 null, System.currentTimeMillis()), getDefaultChannel()); 147 148 mNotiNoGroupSortA = new Notification.Builder(getContext(), TEST_CHANNEL_ID) 149 .setContentTitle("E") 150 .setWhen(1201) 151 .setSortKey("A") 152 .build(); 153 mRecordNoGroupSortA = new NotificationRecord(getContext(), new StatusBarNotification( 154 "package", "package", 1, null, 0, 0, mNotiNoGroupSortA, user, 155 null, System.currentTimeMillis()), getDefaultChannel()); 156 157 mAudioAttributes = new AudioAttributes.Builder() 158 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) 159 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 160 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED) 161 .build(); 162 163 final ApplicationInfo legacy = new ApplicationInfo(); 164 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 165 final ApplicationInfo upgrade = new ApplicationInfo(); 166 upgrade.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 167 try { 168 when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(legacy); 169 when(mPm.getApplicationInfoAsUser(eq(pkg2), anyInt(), anyInt())).thenReturn(upgrade); 170 } catch (PackageManager.NameNotFoundException e) { 171 } 172 } 173 174 private NotificationChannel getDefaultChannel() { 175 return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name", 176 IMPORTANCE_LOW); 177 } 178 179 private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, String... channelIds) 180 throws Exception { 181 XmlSerializer serializer = new FastXmlSerializer(); 182 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 183 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 184 serializer.startDocument(null, true); 185 serializer.startTag(null, "ranking"); 186 mHelper.writeXml(serializer, false); 187 serializer.endTag(null, "ranking"); 188 serializer.endDocument(); 189 serializer.flush(); 190 191 for (String channelId : channelIds) { 192 mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId); 193 } 194 return baos; 195 } 196 197 private void compareChannels(NotificationChannel expected, NotificationChannel actual) { 198 assertEquals(expected.getId(), actual.getId()); 199 assertEquals(expected.getName(), actual.getName()); 200 assertEquals(expected.getNameResId(), actual.getNameResId()); 201 assertEquals(expected.shouldVibrate(), actual.shouldVibrate()); 202 assertEquals(expected.shouldShowLights(), actual.shouldShowLights()); 203 assertEquals(expected.getImportance(), actual.getImportance()); 204 assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility()); 205 assertEquals(expected.getSound(), actual.getSound()); 206 assertEquals(expected.canBypassDnd(), actual.canBypassDnd()); 207 assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern())); 208 assertEquals(expected.getGroup(), actual.getGroup()); 209 assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes()); 210 assertEquals(expected.getLightColor(), actual.getLightColor()); 211 } 212 213 private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) { 214 assertEquals(expected.getId(), actual.getId()); 215 assertEquals(expected.getName(), actual.getName()); 216 assertEquals(expected.getNameResId(), actual.getNameResId()); 217 } 218 219 @Test 220 public void testFindAfterRankingWithASplitGroup() throws Exception { 221 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3); 222 notificationList.add(mRecordGroupGSortA); 223 notificationList.add(mRecordGroupGSortB); 224 notificationList.add(mRecordNoGroup); 225 notificationList.add(mRecordNoGroupSortA); 226 mHelper.sort(notificationList); 227 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortA) >= 0); 228 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortB) >= 0); 229 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroup) >= 0); 230 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0); 231 } 232 233 @Test 234 public void testSortShouldNotThrowWithPlainNotifications() throws Exception { 235 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2); 236 notificationList.add(mRecordNoGroup); 237 notificationList.add(mRecordNoGroup2); 238 mHelper.sort(notificationList); 239 } 240 241 @Test 242 public void testSortShouldNotThrowOneSorted() throws Exception { 243 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2); 244 notificationList.add(mRecordNoGroup); 245 notificationList.add(mRecordNoGroupSortA); 246 mHelper.sort(notificationList); 247 } 248 249 @Test 250 public void testSortShouldNotThrowOneNotification() throws Exception { 251 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1); 252 notificationList.add(mRecordNoGroup); 253 mHelper.sort(notificationList); 254 } 255 256 @Test 257 public void testSortShouldNotThrowOneSortKey() throws Exception { 258 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1); 259 notificationList.add(mRecordGroupGSortB); 260 mHelper.sort(notificationList); 261 } 262 263 @Test 264 public void testSortShouldNotThrowOnEmptyList() throws Exception { 265 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(); 266 mHelper.sort(notificationList); 267 } 268 269 @Test 270 public void testChannelXml() throws Exception { 271 int nameResId = 924896; 272 int groupNameResId = 426272; 273 274 NotificationChannelGroup ncg = new NotificationChannelGroup("1", groupNameResId); 275 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 276 NotificationChannel channel1 = 277 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 278 NotificationChannel channel2 = 279 new NotificationChannel("id2", nameResId, IMPORTANCE_LOW); 280 channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 281 channel2.enableLights(true); 282 channel2.setBypassDnd(true); 283 channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 284 channel2.enableVibration(true); 285 channel2.setGroup(ncg.getId()); 286 channel2.setVibrationPattern(new long[]{100, 67, 145, 156}); 287 channel2.setLightColor(Color.BLUE); 288 289 mHelper.createNotificationChannelGroup(pkg, uid, ncg, true); 290 mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true); 291 mHelper.createNotificationChannel(pkg, uid, channel1, true); 292 mHelper.createNotificationChannel(pkg, uid, channel2, false); 293 294 mHelper.setShowBadge(pkg, uid, true); 295 mHelper.setShowBadge(pkg2, uid2, false); 296 297 ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(), channel2.getId(), 298 NotificationChannel.DEFAULT_CHANNEL_ID); 299 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{pkg}, new int[]{uid}); 300 301 XmlPullParser parser = Xml.newPullParser(); 302 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 303 null); 304 parser.nextTag(); 305 mHelper.readXml(parser, false); 306 307 assertFalse(mHelper.canShowBadge(pkg2, uid2)); 308 assertTrue(mHelper.canShowBadge(pkg, uid)); 309 assertEquals(channel1, mHelper.getNotificationChannel(pkg, uid, channel1.getId(), false)); 310 compareChannels(channel2, 311 mHelper.getNotificationChannel(pkg, uid, channel2.getId(), false)); 312 assertNotNull(mHelper.getNotificationChannel( 313 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false)); 314 315 List<NotificationChannelGroup> actualGroups = 316 mHelper.getNotificationChannelGroups(pkg, uid, false).getList(); 317 boolean foundNcg = false; 318 for (NotificationChannelGroup actual : actualGroups) { 319 if (ncg.getId().equals(actual.getId())) { 320 foundNcg = true; 321 compareGroups(ncg, actual); 322 } else if (ncg2.getId().equals(actual.getId())) { 323 compareGroups(ncg2, actual); 324 } 325 } 326 assertTrue(foundNcg); 327 328 boolean foundChannel2Group = false; 329 for (NotificationChannelGroup actual : actualGroups) { 330 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) { 331 foundChannel2Group = true; 332 break; 333 } 334 } 335 assertTrue(foundChannel2Group); 336 } 337 338 @Test 339 public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception { 340 NotificationChannel channel1 = 341 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_DEFAULT); 342 343 mHelper.createNotificationChannel(pkg, uid, channel1, true); 344 345 ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(), 346 NotificationChannel.DEFAULT_CHANNEL_ID); 347 348 XmlPullParser parser = Xml.newPullParser(); 349 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 350 null); 351 parser.nextTag(); 352 mHelper.readXml(parser, false); 353 354 final NotificationChannel updated = mHelper.getNotificationChannel( 355 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false); 356 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance()); 357 assertFalse(updated.canBypassDnd()); 358 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility()); 359 assertEquals(0, updated.getUserLockedFields()); 360 } 361 362 @Test 363 public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception { 364 NotificationChannel channel1 = 365 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_MIN); 366 mHelper.createNotificationChannel(pkg, uid, channel1, true); 367 368 final NotificationChannel defaultChannel = mHelper.getNotificationChannel( 369 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false); 370 defaultChannel.setImportance(IMPORTANCE_LOW); 371 mHelper.updateNotificationChannel(pkg, uid, defaultChannel); 372 373 ByteArrayOutputStream baos = writeXmlAndPurge(pkg, uid, channel1.getId(), 374 NotificationChannel.DEFAULT_CHANNEL_ID); 375 376 XmlPullParser parser = Xml.newPullParser(); 377 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 378 null); 379 parser.nextTag(); 380 mHelper.readXml(parser, false); 381 382 assertEquals(IMPORTANCE_LOW, mHelper.getNotificationChannel( 383 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance()); 384 } 385 386 @Test 387 public void testChannelXml_upgradeCreateDefaultChannel() throws Exception { 388 final String preupgradeXml = "<ranking version=\"1\">\n" 389 + "<package name=\"" + pkg + "\" importance=\"" 390 + NotificationManager.IMPORTANCE_HIGH 391 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\"" 392 + Notification.VISIBILITY_SECRET + "\"" + " uid=\"" + uid + "\" />\n" 393 + "<package name=\"" + pkg2 + "\" uid=\"" + uid2 + "\" visibility=\"" 394 + Notification.VISIBILITY_PRIVATE + "\" />\n" 395 + "</ranking>"; 396 XmlPullParser parser = Xml.newPullParser(); 397 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), 398 null); 399 parser.nextTag(); 400 mHelper.readXml(parser, false); 401 402 final NotificationChannel updated1 = mHelper.getNotificationChannel( 403 pkg, uid, NotificationChannel.DEFAULT_CHANNEL_ID, false); 404 assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance()); 405 assertTrue(updated1.canBypassDnd()); 406 assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility()); 407 assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE 408 | NotificationChannel.USER_LOCKED_PRIORITY 409 | NotificationChannel.USER_LOCKED_VISIBILITY, updated1.getUserLockedFields()); 410 411 final NotificationChannel updated2 = mHelper.getNotificationChannel( 412 pkg2, uid2, NotificationChannel.DEFAULT_CHANNEL_ID, false); 413 // clamped 414 assertEquals(IMPORTANCE_LOW, updated2.getImportance()); 415 assertFalse(updated2.canBypassDnd()); 416 assertEquals(Notification.VISIBILITY_PRIVATE, updated2.getLockscreenVisibility()); 417 assertEquals(NotificationChannel.USER_LOCKED_VISIBILITY, updated2.getUserLockedFields()); 418 } 419 420 @Test 421 public void testCreateChannel_blocked() throws Exception { 422 mHelper.setImportance(pkg, uid, NotificationManager.IMPORTANCE_NONE); 423 424 try { 425 mHelper.createNotificationChannel(pkg, uid, 426 new NotificationChannel(pkg, "", IMPORTANCE_LOW), true); 427 fail("Channel creation should fail"); 428 } catch (IllegalArgumentException e) { 429 // pass 430 } 431 } 432 433 @Test 434 public void testUpdate_userLockedImportance() throws Exception { 435 // all fields locked by user 436 final NotificationChannel channel = 437 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 438 channel.lockFields(NotificationChannel.USER_LOCKED_IMPORTANCE); 439 440 mHelper.createNotificationChannel(pkg, uid, channel, false); 441 442 // same id, try to update 443 final NotificationChannel channel2 = 444 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 445 446 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); 447 448 // no fields should be changed 449 assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 450 } 451 452 @Test 453 public void testUpdate_userLockedVisibility() throws Exception { 454 // all fields locked by user 455 final NotificationChannel channel = 456 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 457 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 458 channel.lockFields(NotificationChannel.USER_LOCKED_VISIBILITY); 459 460 mHelper.createNotificationChannel(pkg, uid, channel, false); 461 462 // same id, try to update 463 final NotificationChannel channel2 = 464 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 465 channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); 466 467 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); 468 469 // no fields should be changed 470 assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 471 } 472 473 @Test 474 public void testUpdate_userLockedVibration() throws Exception { 475 // all fields locked by user 476 final NotificationChannel channel = 477 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 478 channel.enableLights(false); 479 channel.lockFields(NotificationChannel.USER_LOCKED_VIBRATION); 480 481 mHelper.createNotificationChannel(pkg, uid, channel, false); 482 483 // same id, try to update 484 final NotificationChannel channel2 = 485 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 486 channel2.enableVibration(true); 487 channel2.setVibrationPattern(new long[]{100}); 488 489 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); 490 491 // no fields should be changed 492 assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 493 } 494 495 @Test 496 public void testUpdate_userLockedLights() throws Exception { 497 // all fields locked by user 498 final NotificationChannel channel = 499 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 500 channel.enableLights(false); 501 channel.lockFields(NotificationChannel.USER_LOCKED_LIGHTS); 502 503 mHelper.createNotificationChannel(pkg, uid, channel, false); 504 505 // same id, try to update 506 final NotificationChannel channel2 = 507 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 508 channel2.enableLights(true); 509 510 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); 511 512 // no fields should be changed 513 assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 514 } 515 516 @Test 517 public void testUpdate_userLockedPriority() throws Exception { 518 // all fields locked by user 519 final NotificationChannel channel = 520 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 521 channel.setBypassDnd(true); 522 channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); 523 524 mHelper.createNotificationChannel(pkg, uid, channel, false); 525 526 // same id, try to update all fields 527 final NotificationChannel channel2 = 528 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 529 channel2.setBypassDnd(false); 530 531 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); 532 533 // no fields should be changed 534 assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 535 } 536 537 @Test 538 public void testUpdate_userLockedRingtone() throws Exception { 539 // all fields locked by user 540 final NotificationChannel channel = 541 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 542 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 543 channel.lockFields(NotificationChannel.USER_LOCKED_SOUND); 544 545 mHelper.createNotificationChannel(pkg, uid, channel, false); 546 547 // same id, try to update all fields 548 final NotificationChannel channel2 = 549 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 550 channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes); 551 552 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); 553 554 // no fields should be changed 555 assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 556 } 557 558 @Test 559 public void testUpdate_userLockedBadge() throws Exception { 560 final NotificationChannel channel = 561 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 562 channel.setShowBadge(true); 563 channel.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE); 564 565 mHelper.createNotificationChannel(pkg, uid, channel, false); 566 567 final NotificationChannel channel2 = 568 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 569 channel2.setShowBadge(false); 570 571 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel2); 572 573 // no fields should be changed 574 assertEquals(channel, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 575 } 576 577 @Test 578 public void testUpdate() throws Exception { 579 // no fields locked by user 580 final NotificationChannel channel = 581 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 582 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 583 channel.enableLights(true); 584 channel.setBypassDnd(true); 585 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 586 587 mHelper.createNotificationChannel(pkg, uid, channel, false); 588 589 // same id, try to update all fields 590 final NotificationChannel channel2 = 591 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 592 channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes); 593 channel2.enableLights(false); 594 channel2.setBypassDnd(false); 595 channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); 596 597 mHelper.updateNotificationChannel(pkg, uid, channel2); 598 599 // all fields should be changed 600 assertEquals(channel2, mHelper.getNotificationChannel(pkg, uid, channel.getId(), false)); 601 } 602 603 @Test 604 public void testGetChannelWithFallback() throws Exception { 605 NotificationChannel channel = 606 mHelper.getNotificationChannelWithFallback(pkg, uid, "garbage", false); 607 assertEquals(NotificationChannel.DEFAULT_CHANNEL_ID, channel.getId()); 608 } 609 610 @Test 611 public void testCreateChannel_CannotChangeHiddenFields() throws Exception { 612 final NotificationChannel channel = 613 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 614 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 615 channel.enableLights(true); 616 channel.setBypassDnd(true); 617 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 618 channel.setShowBadge(true); 619 int lockMask = 0; 620 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 621 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 622 } 623 channel.lockFields(lockMask); 624 625 mHelper.createNotificationChannel(pkg, uid, channel, true); 626 627 NotificationChannel savedChannel = 628 mHelper.getNotificationChannel(pkg, uid, channel.getId(), false); 629 630 assertEquals(channel.getName(), savedChannel.getName()); 631 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 632 assertFalse(savedChannel.canBypassDnd()); 633 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 634 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 635 } 636 637 @Test 638 public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception { 639 final NotificationChannel channel = 640 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 641 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 642 channel.enableLights(true); 643 channel.setBypassDnd(true); 644 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 645 channel.setShowBadge(true); 646 int lockMask = 0; 647 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 648 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 649 } 650 channel.lockFields(lockMask); 651 652 mHelper.createNotificationChannel(pkg, uid, channel, true); 653 654 NotificationChannel savedChannel = 655 mHelper.getNotificationChannel(pkg, uid, channel.getId(), false); 656 657 assertEquals(channel.getName(), savedChannel.getName()); 658 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 659 assertFalse(savedChannel.canBypassDnd()); 660 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 661 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 662 } 663 664 @Test 665 public void testGetDeletedChannel() throws Exception { 666 NotificationChannel channel = 667 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 668 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 669 channel.enableLights(true); 670 channel.setBypassDnd(true); 671 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 672 channel.enableVibration(true); 673 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 674 675 mHelper.createNotificationChannel(pkg, uid, channel, true); 676 mHelper.deleteNotificationChannel(pkg, uid, channel.getId()); 677 678 // Does not return deleted channel 679 NotificationChannel response = 680 mHelper.getNotificationChannel(pkg, uid, channel.getId(), false); 681 assertNull(response); 682 683 // Returns deleted channel 684 response = mHelper.getNotificationChannel(pkg, uid, channel.getId(), true); 685 compareChannels(channel, response); 686 assertTrue(response.isDeleted()); 687 } 688 689 @Test 690 public void testGetDeletedChannels() throws Exception { 691 Map<String, NotificationChannel> channelMap = new HashMap<>(); 692 NotificationChannel channel = 693 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 694 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 695 channel.enableLights(true); 696 channel.setBypassDnd(true); 697 channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); 698 channel.enableVibration(true); 699 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 700 channelMap.put(channel.getId(), channel); 701 NotificationChannel channel2 = 702 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 703 channelMap.put(channel2.getId(), channel2); 704 mHelper.createNotificationChannel(pkg, uid, channel, true); 705 mHelper.createNotificationChannel(pkg, uid, channel2, true); 706 707 mHelper.deleteNotificationChannel(pkg, uid, channel.getId()); 708 709 // Returns only non-deleted channels 710 List<NotificationChannel> channels = 711 mHelper.getNotificationChannels(pkg, uid, false).getList(); 712 assertEquals(2, channels.size()); // Default channel + non-deleted channel 713 for (NotificationChannel nc : channels) { 714 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 715 compareChannels(channel2, nc); 716 } 717 } 718 719 // Returns deleted channels too 720 channels = mHelper.getNotificationChannels(pkg, uid, true).getList(); 721 assertEquals(3, channels.size()); // Includes default channel 722 for (NotificationChannel nc : channels) { 723 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 724 compareChannels(channelMap.get(nc.getId()), nc); 725 } 726 } 727 } 728 729 @Test 730 public void testUpdateDeletedChannels() throws Exception { 731 NotificationChannel channel = 732 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 733 mHelper.createNotificationChannel(pkg, uid, channel, true); 734 735 mHelper.deleteNotificationChannel(pkg, uid, channel.getId()); 736 737 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 738 try { 739 mHelper.updateNotificationChannel(pkg, uid, channel); 740 fail("Updated deleted channel"); 741 } catch (IllegalArgumentException e) { 742 // :) 743 } 744 745 try { 746 mHelper.updateNotificationChannelFromAssistant(pkg, uid, channel); 747 fail("Updated deleted channel"); 748 } catch (IllegalArgumentException e) { 749 // :) 750 } 751 } 752 753 @Test 754 public void testCreateDeletedChannel() throws Exception { 755 long[] vibration = new long[]{100, 67, 145, 156}; 756 NotificationChannel channel = 757 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 758 channel.setVibrationPattern(vibration); 759 760 mHelper.createNotificationChannel(pkg, uid, channel, true); 761 mHelper.deleteNotificationChannel(pkg, uid, channel.getId()); 762 763 NotificationChannel newChannel = new NotificationChannel( 764 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 765 newChannel.setVibrationPattern(new long[]{100}); 766 767 mHelper.createNotificationChannel(pkg, uid, newChannel, true); 768 769 // No long deleted, using old settings 770 compareChannels(channel, 771 mHelper.getNotificationChannel(pkg, uid, newChannel.getId(), false)); 772 } 773 774 @Test 775 public void testCreateChannel_defaultChannelId() throws Exception { 776 try { 777 mHelper.createNotificationChannel(pkg2, uid2, new NotificationChannel( 778 NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true); 779 fail("Allowed to create default channel"); 780 } catch (IllegalArgumentException e) { 781 // pass 782 } 783 } 784 785 @Test 786 public void testCreateChannel_alreadyExists() throws Exception { 787 long[] vibration = new long[]{100, 67, 145, 156}; 788 NotificationChannel channel = 789 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 790 channel.setVibrationPattern(vibration); 791 792 mHelper.createNotificationChannel(pkg, uid, channel, true); 793 794 NotificationChannel newChannel = new NotificationChannel( 795 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 796 newChannel.setVibrationPattern(new long[]{100}); 797 798 mHelper.createNotificationChannel(pkg, uid, newChannel, true); 799 800 // Old settings not overridden 801 compareChannels(channel, 802 mHelper.getNotificationChannel(pkg, uid, newChannel.getId(), false)); 803 } 804 805 @Test 806 public void testCreateChannel_addMissingSound() throws Exception { 807 final NotificationChannel channel = 808 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 809 mHelper.createNotificationChannel(pkg, uid, channel, true); 810 assertNotNull(mHelper.getNotificationChannel( 811 pkg, uid, channel.getId(), false).getSound()); 812 } 813 814 @Test 815 public void testCreateChannel_noOverrideSound() throws Exception { 816 Uri sound = new Uri.Builder().scheme("test").build(); 817 final NotificationChannel channel = new NotificationChannel("id2", "name2", 818 NotificationManager.IMPORTANCE_DEFAULT); 819 channel.setSound(sound, mAudioAttributes); 820 mHelper.createNotificationChannel(pkg, uid, channel, true); 821 assertEquals(sound, mHelper.getNotificationChannel( 822 pkg, uid, channel.getId(), false).getSound()); 823 } 824 825 @Test 826 public void testPermanentlyDeleteChannels() throws Exception { 827 NotificationChannel channel1 = 828 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 829 NotificationChannel channel2 = 830 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 831 832 mHelper.createNotificationChannel(pkg, uid, channel1, true); 833 mHelper.createNotificationChannel(pkg, uid, channel2, false); 834 835 mHelper.permanentlyDeleteNotificationChannels(pkg, uid); 836 837 // Only default channel remains 838 assertEquals(1, mHelper.getNotificationChannels(pkg, uid, true).getList().size()); 839 } 840 841 @Test 842 public void testOnPackageChanged_packageRemoval() throws Exception { 843 // Deleted 844 NotificationChannel channel1 = 845 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 846 mHelper.createNotificationChannel(pkg, uid, channel1, true); 847 848 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid}); 849 850 assertEquals(0, mHelper.getNotificationChannels(pkg, uid, true).getList().size()); 851 852 // Not deleted 853 mHelper.createNotificationChannel(pkg, uid, channel1, true); 854 855 mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid}); 856 assertEquals(2, mHelper.getNotificationChannels(pkg, uid, false).getList().size()); 857 } 858 859 @Test 860 public void testOnPackageChanged_packageRemoval_importance() throws Exception { 861 mHelper.setImportance(pkg, uid, NotificationManager.IMPORTANCE_HIGH); 862 863 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid}); 864 865 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(pkg, uid)); 866 } 867 868 @Test 869 public void testOnPackageChanged_packageRemoval_groups() throws Exception { 870 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 871 mHelper.createNotificationChannelGroup(pkg, uid, ncg, true); 872 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 873 mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true); 874 875 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{pkg}, new int[]{uid}); 876 877 assertEquals(0, mHelper.getNotificationChannelGroups(pkg, uid, true).getList().size()); 878 } 879 880 @Test 881 public void testRecordDefaults() throws Exception { 882 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(pkg, uid)); 883 assertEquals(true, mHelper.canShowBadge(pkg, uid)); 884 assertEquals(1, mHelper.getNotificationChannels(pkg, uid, false).getList().size()); 885 } 886 887 @Test 888 public void testCreateGroup() throws Exception { 889 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 890 mHelper.createNotificationChannelGroup(pkg, uid, ncg, true); 891 assertEquals(ncg, mHelper.getNotificationChannelGroups(pkg, uid).iterator().next()); 892 } 893 894 @Test 895 public void testCannotCreateChannel_badGroup() throws Exception { 896 NotificationChannel channel1 = 897 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 898 channel1.setGroup("garbage"); 899 try { 900 mHelper.createNotificationChannel(pkg, uid, channel1, true); 901 fail("Created a channel with a bad group"); 902 } catch (IllegalArgumentException e) { 903 } 904 } 905 906 @Test 907 public void testCannotCreateChannel_goodGroup() throws Exception { 908 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 909 mHelper.createNotificationChannelGroup(pkg, uid, ncg, true); 910 NotificationChannel channel1 = 911 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 912 channel1.setGroup(ncg.getId()); 913 mHelper.createNotificationChannel(pkg, uid, channel1, true); 914 915 assertEquals(ncg.getId(), 916 mHelper.getNotificationChannel(pkg, uid, channel1.getId(), false).getGroup()); 917 } 918 919 @Test 920 public void testGetChannelGroups() throws Exception { 921 NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s"); 922 mHelper.createNotificationChannelGroup(pkg, uid, unused, true); 923 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 924 mHelper.createNotificationChannelGroup(pkg, uid, ncg, true); 925 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 926 mHelper.createNotificationChannelGroup(pkg, uid, ncg2, true); 927 928 NotificationChannel channel1 = 929 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 930 channel1.setGroup(ncg.getId()); 931 mHelper.createNotificationChannel(pkg, uid, channel1, true); 932 NotificationChannel channel1a = 933 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH); 934 channel1a.setGroup(ncg.getId()); 935 mHelper.createNotificationChannel(pkg, uid, channel1a, true); 936 937 NotificationChannel channel2 = 938 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); 939 channel2.setGroup(ncg2.getId()); 940 mHelper.createNotificationChannel(pkg, uid, channel2, true); 941 942 NotificationChannel channel3 = 943 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH); 944 mHelper.createNotificationChannel(pkg, uid, channel3, true); 945 946 List<NotificationChannelGroup> actual = 947 mHelper.getNotificationChannelGroups(pkg, uid, true).getList(); 948 assertEquals(3, actual.size()); 949 for (NotificationChannelGroup group : actual) { 950 if (group.getId() == null) { 951 assertEquals(2, group.getChannels().size()); // misc channel too 952 assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()) 953 || channel3.getId().equals(group.getChannels().get(1).getId())); 954 } else if (group.getId().equals(ncg.getId())) { 955 assertEquals(2, group.getChannels().size()); 956 if (group.getChannels().get(0).getId().equals(channel1.getId())) { 957 assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId())); 958 } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) { 959 assertTrue(group.getChannels().get(1).getId().equals(channel1.getId())); 960 } else { 961 fail("expected channel not found"); 962 } 963 } else if (group.getId().equals(ncg2.getId())) { 964 assertEquals(1, group.getChannels().size()); 965 assertEquals(channel2.getId(), group.getChannels().get(0).getId()); 966 } 967 } 968 } 969 970 @Test 971 public void testGetChannelGroups_noSideEffects() throws Exception { 972 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 973 mHelper.createNotificationChannelGroup(pkg, uid, ncg, true); 974 975 NotificationChannel channel1 = 976 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 977 channel1.setGroup(ncg.getId()); 978 mHelper.createNotificationChannel(pkg, uid, channel1, true); 979 mHelper.getNotificationChannelGroups(pkg, uid, true).getList(); 980 981 channel1.setImportance(IMPORTANCE_LOW); 982 mHelper.updateNotificationChannel(pkg, uid, channel1); 983 984 List<NotificationChannelGroup> actual = 985 mHelper.getNotificationChannelGroups(pkg, uid, true).getList(); 986 987 assertEquals(2, actual.size()); 988 for (NotificationChannelGroup group : actual) { 989 if (Objects.equals(group.getId(),ncg.getId())) { 990 assertEquals(1, group.getChannels().size()); 991 } 992 } 993 } 994} 995