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