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