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