RankingHelperTest.java revision 5fe2eae6b9a2da7791b4686958425b6f0d89dc49
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_DEFAULT; 19import static android.app.NotificationManager.IMPORTANCE_HIGH; 20import static android.app.NotificationManager.IMPORTANCE_LOW; 21import static android.app.NotificationManager.IMPORTANCE_NONE; 22import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; 23 24import static junit.framework.Assert.assertNull; 25import static junit.framework.Assert.fail; 26 27import org.json.JSONArray; 28import org.json.JSONObject; 29import org.junit.Before; 30import org.junit.Ignore; 31import org.junit.Test; 32import org.junit.runner.RunWith; 33 34import com.android.internal.util.FastXmlSerializer; 35 36import org.mockito.Mock; 37import org.mockito.MockitoAnnotations; 38import org.xmlpull.v1.XmlPullParser; 39import org.xmlpull.v1.XmlSerializer; 40 41import android.app.Notification; 42import android.app.NotificationChannelGroup; 43import android.content.Context; 44import android.app.NotificationChannel; 45import android.app.NotificationManager; 46import android.content.pm.ApplicationInfo; 47import android.content.pm.PackageManager; 48import android.graphics.Color; 49import android.media.AudioAttributes; 50import android.net.Uri; 51import android.os.Build; 52import android.os.UserHandle; 53import android.provider.Settings.Secure; 54import android.service.notification.StatusBarNotification; 55import android.support.test.InstrumentationRegistry; 56import android.support.test.runner.AndroidJUnit4; 57import android.test.suitebuilder.annotation.SmallTest; 58import android.util.ArrayMap; 59import android.util.Xml; 60 61import java.io.BufferedInputStream; 62import java.io.BufferedOutputStream; 63import java.io.ByteArrayInputStream; 64import java.io.ByteArrayOutputStream; 65import java.util.ArrayList; 66import java.util.Arrays; 67import java.util.HashMap; 68import java.util.List; 69import java.util.Map; 70import java.util.Objects; 71import java.util.concurrent.ThreadLocalRandom; 72 73import static org.junit.Assert.assertEquals; 74import static org.junit.Assert.assertFalse; 75import static org.junit.Assert.assertNotNull; 76import static org.junit.Assert.assertTrue; 77import static org.mockito.Matchers.anyInt; 78import static org.mockito.Matchers.anyString; 79import static org.mockito.Matchers.eq; 80import static org.mockito.Mockito.when; 81 82@SmallTest 83@RunWith(AndroidJUnit4.class) 84public class RankingHelperTest extends NotificationTestCase { 85 private static final String PKG = "com.android.server.notification"; 86 private static final int UID = 0; 87 private static final UserHandle USER = UserHandle.of(0); 88 private static final String UPDATED_PKG = "updatedPkg"; 89 private static final int UID2 = 1111; 90 private static final UserHandle USER2 = UserHandle.of(10); 91 private static final String TEST_CHANNEL_ID = "test_channel_id"; 92 93 @Mock NotificationUsageStats mUsageStats; 94 @Mock RankingHandler mHandler; 95 @Mock PackageManager mPm; 96 @Mock Context mContext; 97 98 private Notification mNotiGroupGSortA; 99 private Notification mNotiGroupGSortB; 100 private Notification mNotiNoGroup; 101 private Notification mNotiNoGroup2; 102 private Notification mNotiNoGroupSortA; 103 private NotificationRecord mRecordGroupGSortA; 104 private NotificationRecord mRecordGroupGSortB; 105 private NotificationRecord mRecordNoGroup; 106 private NotificationRecord mRecordNoGroup2; 107 private NotificationRecord mRecordNoGroupSortA; 108 private RankingHelper mHelper; 109 private AudioAttributes mAudioAttributes; 110 111 @Before 112 public void setUp() throws Exception { 113 MockitoAnnotations.initMocks(this); 114 UserHandle user = UserHandle.ALL; 115 116 final ApplicationInfo legacy = new ApplicationInfo(); 117 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 118 final ApplicationInfo upgrade = new ApplicationInfo(); 119 upgrade.targetSdkVersion = Build.VERSION_CODES.O; 120 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy); 121 when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(upgrade); 122 when(mPm.getPackageUidAsUser(eq(PKG), anyInt())).thenReturn(UID); 123 when(mPm.getPackageUidAsUser(eq(UPDATED_PKG), anyInt())).thenReturn(UID2); 124 when(mContext.getResources()).thenReturn( 125 InstrumentationRegistry.getContext().getResources()); 126 when(mContext.getPackageManager()).thenReturn(mPm); 127 when(mContext.getApplicationInfo()).thenReturn(legacy); 128 // most tests assume badging is enabled 129 Secure.putIntForUser(getContext().getContentResolver(), 130 Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID)); 131 132 mHelper = new RankingHelper(getContext(), mPm, mHandler, mUsageStats, 133 new String[] {ImportanceExtractor.class.getName()}); 134 135 mNotiGroupGSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID) 136 .setContentTitle("A") 137 .setGroup("G") 138 .setSortKey("A") 139 .setWhen(1205) 140 .build(); 141 mRecordGroupGSortA = new NotificationRecord(mContext, new StatusBarNotification( 142 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortA, user, 143 null, System.currentTimeMillis()), getDefaultChannel()); 144 145 mNotiGroupGSortB = new Notification.Builder(mContext, TEST_CHANNEL_ID) 146 .setContentTitle("B") 147 .setGroup("G") 148 .setSortKey("B") 149 .setWhen(1200) 150 .build(); 151 mRecordGroupGSortB = new NotificationRecord(mContext, new StatusBarNotification( 152 PKG, PKG, 1, null, 0, 0, mNotiGroupGSortB, user, 153 null, System.currentTimeMillis()), getDefaultChannel()); 154 155 mNotiNoGroup = new Notification.Builder(mContext, TEST_CHANNEL_ID) 156 .setContentTitle("C") 157 .setWhen(1201) 158 .build(); 159 mRecordNoGroup = new NotificationRecord(mContext, new StatusBarNotification( 160 PKG, PKG, 1, null, 0, 0, mNotiNoGroup, user, 161 null, System.currentTimeMillis()), getDefaultChannel()); 162 163 mNotiNoGroup2 = new Notification.Builder(mContext, TEST_CHANNEL_ID) 164 .setContentTitle("D") 165 .setWhen(1202) 166 .build(); 167 mRecordNoGroup2 = new NotificationRecord(mContext, new StatusBarNotification( 168 PKG, PKG, 1, null, 0, 0, mNotiNoGroup2, user, 169 null, System.currentTimeMillis()), getDefaultChannel()); 170 171 mNotiNoGroupSortA = new Notification.Builder(mContext, TEST_CHANNEL_ID) 172 .setContentTitle("E") 173 .setWhen(1201) 174 .setSortKey("A") 175 .build(); 176 mRecordNoGroupSortA = new NotificationRecord(mContext, new StatusBarNotification( 177 PKG, PKG, 1, null, 0, 0, mNotiNoGroupSortA, user, 178 null, System.currentTimeMillis()), getDefaultChannel()); 179 180 mAudioAttributes = new AudioAttributes.Builder() 181 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) 182 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 183 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED) 184 .build(); 185 } 186 187 private NotificationChannel getDefaultChannel() { 188 return new NotificationChannel(NotificationChannel.DEFAULT_CHANNEL_ID, "name", 189 IMPORTANCE_LOW); 190 } 191 192 private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup, 193 String... channelIds) 194 throws Exception { 195 XmlSerializer serializer = new FastXmlSerializer(); 196 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 197 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 198 serializer.startDocument(null, true); 199 mHelper.writeXml(serializer, forBackup); 200 serializer.endDocument(); 201 serializer.flush(); 202 for (String channelId : channelIds) { 203 mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId); 204 } 205 return baos; 206 } 207 208 private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore) throws Exception { 209 XmlPullParser parser = Xml.newPullParser(); 210 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(stream.toByteArray())), 211 null); 212 parser.nextTag(); 213 mHelper.readXml(parser, forRestore); 214 } 215 216 private void compareChannels(NotificationChannel expected, NotificationChannel actual) { 217 assertEquals(expected.getId(), actual.getId()); 218 assertEquals(expected.getName(), actual.getName()); 219 assertEquals(expected.getDescription(), actual.getDescription()); 220 assertEquals(expected.shouldVibrate(), actual.shouldVibrate()); 221 assertEquals(expected.shouldShowLights(), actual.shouldShowLights()); 222 assertEquals(expected.getImportance(), actual.getImportance()); 223 assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility()); 224 assertEquals(expected.getSound(), actual.getSound()); 225 assertEquals(expected.canBypassDnd(), actual.canBypassDnd()); 226 assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern())); 227 assertEquals(expected.getGroup(), actual.getGroup()); 228 assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes()); 229 assertEquals(expected.getLightColor(), actual.getLightColor()); 230 } 231 232 private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) { 233 assertEquals(expected.getId(), actual.getId()); 234 assertEquals(expected.getName(), actual.getName()); 235 } 236 237 private NotificationChannel getChannel() { 238 return new NotificationChannel("id", "name", IMPORTANCE_LOW); 239 } 240 241 @Test 242 public void testFindAfterRankingWithASplitGroup() throws Exception { 243 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(3); 244 notificationList.add(mRecordGroupGSortA); 245 notificationList.add(mRecordGroupGSortB); 246 notificationList.add(mRecordNoGroup); 247 notificationList.add(mRecordNoGroupSortA); 248 mHelper.sort(notificationList); 249 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortA) >= 0); 250 assertTrue(mHelper.indexOf(notificationList, mRecordGroupGSortB) >= 0); 251 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroup) >= 0); 252 assertTrue(mHelper.indexOf(notificationList, mRecordNoGroupSortA) >= 0); 253 } 254 255 @Test 256 public void testSortShouldNotThrowWithPlainNotifications() throws Exception { 257 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2); 258 notificationList.add(mRecordNoGroup); 259 notificationList.add(mRecordNoGroup2); 260 mHelper.sort(notificationList); 261 } 262 263 @Test 264 public void testSortShouldNotThrowOneSorted() throws Exception { 265 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(2); 266 notificationList.add(mRecordNoGroup); 267 notificationList.add(mRecordNoGroupSortA); 268 mHelper.sort(notificationList); 269 } 270 271 @Test 272 public void testSortShouldNotThrowOneNotification() throws Exception { 273 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1); 274 notificationList.add(mRecordNoGroup); 275 mHelper.sort(notificationList); 276 } 277 278 @Test 279 public void testSortShouldNotThrowOneSortKey() throws Exception { 280 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(1); 281 notificationList.add(mRecordGroupGSortB); 282 mHelper.sort(notificationList); 283 } 284 285 @Test 286 public void testSortShouldNotThrowOnEmptyList() throws Exception { 287 ArrayList<NotificationRecord> notificationList = new ArrayList<NotificationRecord>(); 288 mHelper.sort(notificationList); 289 } 290 291 @Test 292 public void testChannelXml() throws Exception { 293 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 294 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 295 NotificationChannel channel1 = 296 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 297 NotificationChannel channel2 = 298 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 299 channel2.setDescription("descriptions for all"); 300 channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 301 channel2.enableLights(true); 302 channel2.setBypassDnd(true); 303 channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 304 channel2.enableVibration(true); 305 channel2.setGroup(ncg.getId()); 306 channel2.setVibrationPattern(new long[]{100, 67, 145, 156}); 307 channel2.setLightColor(Color.BLUE); 308 309 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 310 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 311 mHelper.createNotificationChannel(PKG, UID, channel1, true); 312 mHelper.createNotificationChannel(PKG, UID, channel2, false); 313 314 mHelper.setShowBadge(PKG, UID, true); 315 316 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, channel1.getId(), 317 channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID); 318 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID}); 319 320 loadStreamXml(baos, false); 321 322 assertTrue(mHelper.canShowBadge(PKG, UID)); 323 assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false)); 324 compareChannels(channel2, 325 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 326 327 List<NotificationChannelGroup> actualGroups = 328 mHelper.getNotificationChannelGroups(PKG, UID, false).getList(); 329 boolean foundNcg = false; 330 for (NotificationChannelGroup actual : actualGroups) { 331 if (ncg.getId().equals(actual.getId())) { 332 foundNcg = true; 333 compareGroups(ncg, actual); 334 } else if (ncg2.getId().equals(actual.getId())) { 335 compareGroups(ncg2, actual); 336 } 337 } 338 assertTrue(foundNcg); 339 340 boolean foundChannel2Group = false; 341 for (NotificationChannelGroup actual : actualGroups) { 342 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) { 343 foundChannel2Group = true; 344 break; 345 } 346 } 347 assertTrue(foundChannel2Group); 348 } 349 350 @Test 351 public void testChannelXmlForBackup() throws Exception { 352 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 353 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 354 NotificationChannel channel1 = 355 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 356 NotificationChannel channel2 = 357 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 358 channel2.setDescription("descriptions for all"); 359 channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 360 channel2.enableLights(true); 361 channel2.setBypassDnd(true); 362 channel2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 363 channel2.enableVibration(false); 364 channel2.setGroup(ncg.getId()); 365 channel2.setLightColor(Color.BLUE); 366 367 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 368 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 369 mHelper.createNotificationChannel(PKG, UID, channel1, true); 370 mHelper.createNotificationChannel(PKG, UID, channel2, false); 371 mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true); 372 373 mHelper.setShowBadge(PKG, UID, true); 374 375 mHelper.setImportance(UPDATED_PKG, UID2, IMPORTANCE_NONE); 376 377 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(), 378 channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID); 379 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG, UPDATED_PKG}, new int[]{UID, UID2}); 380 381 mHelper.setShowBadge(UPDATED_PKG, UID2, true); 382 383 loadStreamXml(baos, true); 384 385 assertEquals(IMPORTANCE_NONE, mHelper.getImportance(UPDATED_PKG, UID2)); 386 assertTrue(mHelper.canShowBadge(PKG, UID)); 387 assertEquals(channel1, mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false)); 388 compareChannels(channel2, 389 mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 390 391 List<NotificationChannelGroup> actualGroups = 392 mHelper.getNotificationChannelGroups(PKG, UID, false).getList(); 393 boolean foundNcg = false; 394 for (NotificationChannelGroup actual : actualGroups) { 395 if (ncg.getId().equals(actual.getId())) { 396 foundNcg = true; 397 compareGroups(ncg, actual); 398 } else if (ncg2.getId().equals(actual.getId())) { 399 compareGroups(ncg2, actual); 400 } 401 } 402 assertTrue(foundNcg); 403 404 boolean foundChannel2Group = false; 405 for (NotificationChannelGroup actual : actualGroups) { 406 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) { 407 foundChannel2Group = true; 408 break; 409 } 410 } 411 assertTrue(foundChannel2Group); 412 } 413 414 @Test 415 public void testChannelXml_backup() throws Exception { 416 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 417 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 418 NotificationChannel channel1 = 419 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 420 NotificationChannel channel2 = 421 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 422 NotificationChannel channel3 = 423 new NotificationChannel("id3", "name3", IMPORTANCE_LOW); 424 channel3.setGroup(ncg.getId()); 425 426 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 427 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 428 mHelper.createNotificationChannel(PKG, UID, channel1, true); 429 mHelper.createNotificationChannel(PKG, UID, channel2, false); 430 mHelper.createNotificationChannel(PKG, UID, channel3, true); 431 432 mHelper.deleteNotificationChannel(PKG, UID, channel1.getId()); 433 mHelper.deleteNotificationChannelGroup(PKG, UID, ncg.getId()); 434 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 435 436 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, true, channel1.getId(), 437 channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID); 438 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG}, new int[]{UID}); 439 440 XmlPullParser parser = Xml.newPullParser(); 441 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 442 null); 443 parser.nextTag(); 444 mHelper.readXml(parser, true); 445 446 assertNull(mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false)); 447 assertNull(mHelper.getNotificationChannel(PKG, UID, channel3.getId(), false)); 448 assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG, UID)); 449 //assertEquals(ncg2, mHelper.getNotificationChannelGroup(ncg2.getId(), PKG, UID)); 450 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel2.getId(), false)); 451 } 452 453 @Test 454 public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception { 455 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 456 NotificationChannel.DEFAULT_CHANNEL_ID); 457 458 loadStreamXml(baos, false); 459 460 final NotificationChannel updated = mHelper.getNotificationChannel(PKG, UID, 461 NotificationChannel.DEFAULT_CHANNEL_ID, false); 462 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance()); 463 assertFalse(updated.canBypassDnd()); 464 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility()); 465 assertEquals(0, updated.getUserLockedFields()); 466 } 467 468 @Test 469 public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception { 470 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID, 471 NotificationChannel.DEFAULT_CHANNEL_ID, false); 472 defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 473 mHelper.updateNotificationChannel(PKG, UID, defaultChannel); 474 475 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 476 NotificationChannel.DEFAULT_CHANNEL_ID); 477 478 loadStreamXml(baos, false); 479 480 assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel( 481 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance()); 482 } 483 484 @Test 485 public void testChannelXml_upgradeCreateDefaultChannel() throws Exception { 486 final String preupgradeXml = "<ranking version=\"1\">\n" 487 + "<package name=\"" + PKG 488 + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH 489 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\"" 490 + Notification.VISIBILITY_SECRET + "\"" +" uid=\"" + UID + "\" />\n" 491 + "<package name=\"" + UPDATED_PKG + "\" uid=\"" + UID2 + "\" visibility=\"" 492 + Notification.VISIBILITY_PRIVATE + "\" />\n" 493 + "</ranking>"; 494 XmlPullParser parser = Xml.newPullParser(); 495 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), 496 null); 497 parser.nextTag(); 498 mHelper.readXml(parser, false); 499 500 final NotificationChannel updated1 = 501 mHelper.getNotificationChannel(PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false); 502 assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance()); 503 assertTrue(updated1.canBypassDnd()); 504 assertEquals(Notification.VISIBILITY_SECRET, updated1.getLockscreenVisibility()); 505 assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE 506 | NotificationChannel.USER_LOCKED_PRIORITY 507 | NotificationChannel.USER_LOCKED_VISIBILITY, 508 updated1.getUserLockedFields()); 509 510 // No Default Channel created for updated packages 511 assertEquals(null, mHelper.getNotificationChannel(UPDATED_PKG, UID2, 512 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 513 } 514 515 @Test 516 public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception { 517 final NotificationChannel defaultChannel = mHelper.getNotificationChannel( 518 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false); 519 assertTrue(defaultChannel != null); 520 ByteArrayOutputStream baos = 521 writeXmlAndPurge(PKG, UID, false, NotificationChannel.DEFAULT_CHANNEL_ID); 522 // Load package at higher sdk. 523 final ApplicationInfo upgraded = new ApplicationInfo(); 524 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 525 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded); 526 loadStreamXml(baos, false); 527 528 // Default Channel should be gone. 529 assertEquals(null, mHelper.getNotificationChannel(PKG, UID, 530 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 531 } 532 533 @Test 534 public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception { 535 mHelper.createNotificationChannel(PKG, UID, 536 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); 537 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 538 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); 539 540 // Load package at higher sdk. 541 final ApplicationInfo upgraded = new ApplicationInfo(); 542 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 543 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(upgraded); 544 loadStreamXml(baos, false); 545 546 // Default Channel should be gone. 547 assertEquals(null, mHelper.getNotificationChannel(PKG, UID, 548 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 549 } 550 551 @Test 552 public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception { 553 ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false, 554 NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); 555 mHelper.createNotificationChannel(PKG, UID, 556 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); 557 558 loadStreamXml(baos, false); 559 560 // Should still have the newly created channel that wasn't in the xml. 561 assertTrue(mHelper.getNotificationChannel(PKG, UID, "bananas", false) != null); 562 } 563 564 @Test 565 public void testCreateChannel_blocked() throws Exception { 566 mHelper.setImportance(PKG, UID, IMPORTANCE_NONE); 567 568 mHelper.createNotificationChannel(PKG, UID, 569 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true); 570 } 571 572 @Test 573 public void testCreateChannel_ImportanceNone() throws Exception { 574 try { 575 mHelper.createNotificationChannel(PKG, UID, 576 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true); 577 fail("Was allowed to create a blocked channel"); 578 } catch (IllegalArgumentException e) { 579 // yay 580 } 581 } 582 583 584 @Test 585 public void testUpdate() throws Exception { 586 // no fields locked by user 587 final NotificationChannel channel = 588 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 589 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 590 channel.enableLights(true); 591 channel.setBypassDnd(true); 592 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 593 594 mHelper.createNotificationChannel(PKG, UID, channel, false); 595 596 // same id, try to update all fields 597 final NotificationChannel channel2 = 598 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 599 channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes); 600 channel2.enableLights(false); 601 channel2.setBypassDnd(false); 602 channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); 603 604 mHelper.updateNotificationChannel(PKG, UID, channel2); 605 606 // all fields should be changed 607 assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false)); 608 } 609 610 @Test 611 public void testUpdate_preUpgrade_updatesAppFields() throws Exception { 612 mHelper.setImportance(PKG, UID, IMPORTANCE_UNSPECIFIED); 613 assertTrue(mHelper.canShowBadge(PKG, UID)); 614 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); 615 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, 616 mHelper.getPackageVisibility(PKG, UID)); 617 618 NotificationChannel defaultChannel = mHelper.getNotificationChannel( 619 PKG, UID, NotificationChannel.DEFAULT_CHANNEL_ID, false); 620 621 defaultChannel.setShowBadge(false); 622 defaultChannel.setImportance(IMPORTANCE_NONE); 623 defaultChannel.setBypassDnd(true); 624 defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 625 626 mHelper.updateNotificationChannel(PKG, UID, defaultChannel); 627 628 // ensure app level fields are changed 629 assertFalse(mHelper.canShowBadge(PKG, UID)); 630 assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG, UID)); 631 assertEquals(Notification.VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG, UID)); 632 assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG, UID)); 633 } 634 635 @Test 636 public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception { 637 final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 638 639 mHelper.createNotificationChannel(PKG, UID, channel, false); 640 assertTrue(mHelper.canShowBadge(PKG, UID)); 641 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); 642 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, 643 mHelper.getPackageVisibility(PKG, UID)); 644 645 channel.setShowBadge(false); 646 channel.setImportance(IMPORTANCE_NONE); 647 channel.setBypassDnd(true); 648 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 649 650 mHelper.updateNotificationChannel(PKG, UID, channel); 651 652 // ensure app level fields are not changed 653 assertTrue(mHelper.canShowBadge(PKG, UID)); 654 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG, UID)); 655 assertEquals(NotificationManager.VISIBILITY_NO_OVERRIDE, 656 mHelper.getPackageVisibility(PKG, UID)); 657 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID)); 658 } 659 660 @Test 661 public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception { 662 assertEquals(null, mHelper.getNotificationChannel(PKG, UID, "garbage", false)); 663 } 664 665 @Test 666 public void testCreateChannel_CannotChangeHiddenFields() throws Exception { 667 final NotificationChannel channel = 668 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 669 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 670 channel.enableLights(true); 671 channel.setBypassDnd(true); 672 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 673 channel.setShowBadge(true); 674 int lockMask = 0; 675 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 676 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 677 } 678 channel.lockFields(lockMask); 679 680 mHelper.createNotificationChannel(PKG, UID, channel, true); 681 682 NotificationChannel savedChannel = 683 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); 684 685 assertEquals(channel.getName(), savedChannel.getName()); 686 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 687 assertFalse(savedChannel.canBypassDnd()); 688 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 689 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 690 } 691 692 @Test 693 public void testCreateChannel_CannotChangeHiddenFieldsAssistant() throws Exception { 694 final NotificationChannel channel = 695 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 696 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 697 channel.enableLights(true); 698 channel.setBypassDnd(true); 699 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 700 channel.setShowBadge(true); 701 int lockMask = 0; 702 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 703 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 704 } 705 channel.lockFields(lockMask); 706 707 mHelper.createNotificationChannel(PKG, UID, channel, true); 708 709 NotificationChannel savedChannel = 710 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); 711 712 assertEquals(channel.getName(), savedChannel.getName()); 713 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 714 assertFalse(savedChannel.canBypassDnd()); 715 assertFalse(Notification.VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 716 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 717 } 718 719 @Test 720 public void testClearLockedFields() throws Exception { 721 final NotificationChannel channel = getChannel(); 722 mHelper.clearLockedFields(channel); 723 assertEquals(0, channel.getUserLockedFields()); 724 725 channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY 726 | NotificationChannel.USER_LOCKED_IMPORTANCE); 727 mHelper.clearLockedFields(channel); 728 assertEquals(0, channel.getUserLockedFields()); 729 } 730 731 @Test 732 public void testLockFields_soundAndVibration() throws Exception { 733 mHelper.createNotificationChannel(PKG, UID, getChannel(), true); 734 735 final NotificationChannel update1 = getChannel(); 736 update1.setSound(new Uri.Builder().scheme("test").build(), 737 new AudioAttributes.Builder().build()); 738 update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored 739 mHelper.updateNotificationChannel(PKG, UID, update1); 740 assertEquals(NotificationChannel.USER_LOCKED_SOUND, 741 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 742 .getUserLockedFields()); 743 744 NotificationChannel update2 = getChannel(); 745 update2.enableVibration(true); 746 mHelper.updateNotificationChannel(PKG, UID, update2); 747 assertEquals(NotificationChannel.USER_LOCKED_SOUND 748 | NotificationChannel.USER_LOCKED_VIBRATION, 749 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 750 .getUserLockedFields()); 751 } 752 753 @Test 754 public void testLockFields_vibrationAndLights() throws Exception { 755 mHelper.createNotificationChannel(PKG, UID, getChannel(), true); 756 757 final NotificationChannel update1 = getChannel(); 758 update1.setVibrationPattern(new long[]{7945, 46 ,246}); 759 mHelper.updateNotificationChannel(PKG, UID, update1); 760 assertEquals(NotificationChannel.USER_LOCKED_VIBRATION, 761 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 762 .getUserLockedFields()); 763 764 final NotificationChannel update2 = getChannel(); 765 update2.enableLights(true); 766 mHelper.updateNotificationChannel(PKG, UID, update2); 767 assertEquals(NotificationChannel.USER_LOCKED_VIBRATION 768 | NotificationChannel.USER_LOCKED_LIGHTS, 769 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 770 .getUserLockedFields()); 771 } 772 773 @Test 774 public void testLockFields_lightsAndImportance() throws Exception { 775 mHelper.createNotificationChannel(PKG, UID, getChannel(), true); 776 777 final NotificationChannel update1 = getChannel(); 778 update1.setLightColor(Color.GREEN); 779 mHelper.updateNotificationChannel(PKG, UID, update1); 780 assertEquals(NotificationChannel.USER_LOCKED_LIGHTS, 781 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 782 .getUserLockedFields()); 783 784 final NotificationChannel update2 = getChannel(); 785 update2.setImportance(IMPORTANCE_DEFAULT); 786 mHelper.updateNotificationChannel(PKG, UID, update2); 787 assertEquals(NotificationChannel.USER_LOCKED_LIGHTS 788 | NotificationChannel.USER_LOCKED_IMPORTANCE, 789 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 790 .getUserLockedFields()); 791 } 792 793 @Test 794 public void testLockFields_visibilityAndDndAndBadge() throws Exception { 795 mHelper.createNotificationChannel(PKG, UID, getChannel(), true); 796 assertEquals(0, 797 mHelper.getNotificationChannel(PKG, UID, getChannel().getId(), false) 798 .getUserLockedFields()); 799 800 final NotificationChannel update1 = getChannel(); 801 update1.setBypassDnd(true); 802 mHelper.updateNotificationChannel(PKG, UID, update1); 803 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY, 804 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false) 805 .getUserLockedFields()); 806 807 final NotificationChannel update2 = getChannel(); 808 update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 809 mHelper.updateNotificationChannel(PKG, UID, update2); 810 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY 811 | NotificationChannel.USER_LOCKED_VISIBILITY, 812 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false) 813 .getUserLockedFields()); 814 815 final NotificationChannel update3 = getChannel(); 816 update3.setShowBadge(false); 817 mHelper.updateNotificationChannel(PKG, UID, update3); 818 assertEquals(NotificationChannel.USER_LOCKED_PRIORITY 819 | NotificationChannel.USER_LOCKED_VISIBILITY 820 | NotificationChannel.USER_LOCKED_SHOW_BADGE, 821 mHelper.getNotificationChannel(PKG, UID, update3.getId(), false) 822 .getUserLockedFields()); 823 } 824 825 @Test 826 public void testDeleteNonExistentChannel() throws Exception { 827 mHelper.deleteNotificationChannelGroup(PKG, UID, "does not exist"); 828 } 829 830 @Test 831 public void testGetDeletedChannel() throws Exception { 832 NotificationChannel channel = getChannel(); 833 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 834 channel.enableLights(true); 835 channel.setBypassDnd(true); 836 channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET); 837 channel.enableVibration(true); 838 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 839 840 mHelper.createNotificationChannel(PKG, UID, channel, true); 841 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 842 843 // Does not return deleted channel 844 NotificationChannel response = 845 mHelper.getNotificationChannel(PKG, UID, channel.getId(), false); 846 assertNull(response); 847 848 // Returns deleted channel 849 response = mHelper.getNotificationChannel(PKG, UID, channel.getId(), true); 850 compareChannels(channel, response); 851 assertTrue(response.isDeleted()); 852 } 853 854 @Test 855 public void testGetDeletedChannels() throws Exception { 856 Map<String, NotificationChannel> channelMap = new HashMap<>(); 857 NotificationChannel channel = 858 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 859 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 860 channel.enableLights(true); 861 channel.setBypassDnd(true); 862 channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE); 863 channel.enableVibration(true); 864 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 865 channelMap.put(channel.getId(), channel); 866 NotificationChannel channel2 = 867 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 868 channelMap.put(channel2.getId(), channel2); 869 mHelper.createNotificationChannel(PKG, UID, channel, true); 870 mHelper.createNotificationChannel(PKG, UID, channel2, true); 871 872 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 873 874 // Returns only non-deleted channels 875 List<NotificationChannel> channels = 876 mHelper.getNotificationChannels(PKG, UID, false).getList(); 877 assertEquals(2, channels.size()); // Default channel + non-deleted channel 878 for (NotificationChannel nc : channels) { 879 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 880 compareChannels(channel2, nc); 881 } 882 } 883 884 // Returns deleted channels too 885 channels = mHelper.getNotificationChannels(PKG, UID, true).getList(); 886 assertEquals(3, channels.size()); // Includes default channel 887 for (NotificationChannel nc : channels) { 888 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 889 compareChannels(channelMap.get(nc.getId()), nc); 890 } 891 } 892 } 893 894 @Test 895 public void testGetDeletedChannelCount() throws Exception { 896 NotificationChannel channel = 897 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 898 NotificationChannel channel2 = 899 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 900 NotificationChannel channel3 = 901 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 902 mHelper.createNotificationChannel(PKG, UID, channel, true); 903 mHelper.createNotificationChannel(PKG, UID, channel2, true); 904 mHelper.createNotificationChannel(PKG, UID, channel3, true); 905 906 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 907 mHelper.deleteNotificationChannel(PKG, UID, channel3.getId()); 908 909 assertEquals(2, mHelper.getDeletedChannelCount(PKG, UID)); 910 assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID2)); 911 } 912 913 @Test 914 public void testCreateDeletedChannel() throws Exception { 915 long[] vibration = new long[]{100, 67, 145, 156}; 916 NotificationChannel channel = 917 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 918 channel.setVibrationPattern(vibration); 919 920 mHelper.createNotificationChannel(PKG, UID, channel, true); 921 mHelper.deleteNotificationChannel(PKG, UID, channel.getId()); 922 923 NotificationChannel newChannel = new NotificationChannel( 924 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 925 newChannel.setVibrationPattern(new long[]{100}); 926 927 mHelper.createNotificationChannel(PKG, UID, newChannel, true); 928 929 // No long deleted, using old settings 930 compareChannels(channel, 931 mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false)); 932 } 933 934 @Test 935 public void testOnlyHasDefaultChannel() throws Exception { 936 assertTrue(mHelper.onlyHasDefaultChannel(PKG, UID)); 937 assertFalse(mHelper.onlyHasDefaultChannel(UPDATED_PKG, UID2)); 938 939 mHelper.createNotificationChannel(PKG, UID, getChannel(), true); 940 assertFalse(mHelper.onlyHasDefaultChannel(PKG, UID)); 941 } 942 943 @Test 944 public void testCreateChannel_defaultChannelId() throws Exception { 945 try { 946 mHelper.createNotificationChannel(PKG, UID, new NotificationChannel( 947 NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true); 948 fail("Allowed to create default channel"); 949 } catch (IllegalArgumentException e) { 950 // pass 951 } 952 } 953 954 @Test 955 public void testCreateChannel_alreadyExists() throws Exception { 956 long[] vibration = new long[]{100, 67, 145, 156}; 957 NotificationChannel channel = 958 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 959 channel.setVibrationPattern(vibration); 960 961 mHelper.createNotificationChannel(PKG, UID, channel, true); 962 963 NotificationChannel newChannel = new NotificationChannel( 964 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 965 newChannel.setVibrationPattern(new long[]{100}); 966 967 mHelper.createNotificationChannel(PKG, UID, newChannel, true); 968 969 // Old settings not overridden 970 compareChannels(channel, 971 mHelper.getNotificationChannel(PKG, UID, newChannel.getId(), false)); 972 } 973 974 @Test 975 public void testCreateChannel_noOverrideSound() throws Exception { 976 Uri sound = new Uri.Builder().scheme("test").build(); 977 final NotificationChannel channel = new NotificationChannel("id2", "name2", 978 NotificationManager.IMPORTANCE_DEFAULT); 979 channel.setSound(sound, mAudioAttributes); 980 mHelper.createNotificationChannel(PKG, UID, channel, true); 981 assertEquals(sound, mHelper.getNotificationChannel( 982 PKG, UID, channel.getId(), false).getSound()); 983 } 984 985 @Test 986 public void testPermanentlyDeleteChannels() throws Exception { 987 NotificationChannel channel1 = 988 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 989 NotificationChannel channel2 = 990 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 991 992 mHelper.createNotificationChannel(PKG, UID, channel1, true); 993 mHelper.createNotificationChannel(PKG, UID, channel2, false); 994 995 mHelper.permanentlyDeleteNotificationChannels(PKG, UID); 996 997 // Only default channel remains 998 assertEquals(1, mHelper.getNotificationChannels(PKG, UID, true).getList().size()); 999 } 1000 1001 @Test 1002 public void testDeleteGroup() throws Exception { 1003 NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted"); 1004 NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted"); 1005 NotificationChannel nonGroupedNonDeletedChannel = 1006 new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH); 1007 NotificationChannel groupedButNotDeleted = 1008 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT); 1009 groupedButNotDeleted.setGroup("not"); 1010 NotificationChannel groupedAndDeleted = 1011 new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT); 1012 groupedAndDeleted.setGroup("totally"); 1013 1014 mHelper.createNotificationChannelGroup(PKG, UID, notDeleted, true); 1015 mHelper.createNotificationChannelGroup(PKG, UID, deleted, true); 1016 mHelper.createNotificationChannel(PKG, UID, nonGroupedNonDeletedChannel, true); 1017 mHelper.createNotificationChannel(PKG, UID, groupedAndDeleted, true); 1018 mHelper.createNotificationChannel(PKG, UID, groupedButNotDeleted, true); 1019 1020 mHelper.deleteNotificationChannelGroup(PKG, UID, deleted.getId()); 1021 1022 assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG, UID)); 1023 assertNotNull(mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG, UID)); 1024 1025 assertNull(mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), false)); 1026 compareChannels(groupedAndDeleted, 1027 mHelper.getNotificationChannel(PKG, UID, groupedAndDeleted.getId(), true)); 1028 1029 compareChannels(groupedButNotDeleted, 1030 mHelper.getNotificationChannel(PKG, UID, groupedButNotDeleted.getId(), false)); 1031 compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel( 1032 PKG, UID, nonGroupedNonDeletedChannel.getId(), false)); 1033 1034 // notDeleted 1035 assertEquals(1, mHelper.getNotificationChannelGroups(PKG, UID).size()); 1036 } 1037 1038 @Test 1039 public void testOnUserRemoved() throws Exception { 1040 int[] user0Uids = {98, 235, 16, 3782}; 1041 int[] user1Uids = new int[user0Uids.length]; 1042 for (int i = 0; i < user0Uids.length; i++) { 1043 user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i]; 1044 1045 final ApplicationInfo legacy = new ApplicationInfo(); 1046 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1047 when(mPm.getApplicationInfoAsUser(eq(PKG), anyInt(), anyInt())).thenReturn(legacy); 1048 1049 // create records with the default channel for all user 0 and user 1 uids 1050 mHelper.getImportance(PKG, user0Uids[i]); 1051 mHelper.getImportance(PKG, user1Uids[i]); 1052 } 1053 1054 mHelper.onUserRemoved(1); 1055 1056 // user 0 records remain 1057 for (int i = 0; i < user0Uids.length; i++) { 1058 assertEquals(1, 1059 mHelper.getNotificationChannels(PKG, user0Uids[i], false).getList().size()); 1060 } 1061 // user 1 records are gone 1062 for (int i = 0; i < user1Uids.length; i++) { 1063 assertEquals(0, 1064 mHelper.getNotificationChannels(PKG, user1Uids[i], false).getList().size()); 1065 } 1066 } 1067 1068 @Test 1069 public void testOnPackageChanged_packageRemoval() throws Exception { 1070 // Deleted 1071 NotificationChannel channel1 = 1072 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1073 mHelper.createNotificationChannel(PKG, UID, channel1, true); 1074 1075 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1076 1077 assertEquals(0, mHelper.getNotificationChannels(PKG, UID, true).getList().size()); 1078 1079 // Not deleted 1080 mHelper.createNotificationChannel(PKG, UID, channel1, true); 1081 1082 mHelper.onPackagesChanged(false, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1083 assertEquals(2, mHelper.getNotificationChannels(PKG, UID, false).getList().size()); 1084 } 1085 1086 @Test 1087 public void testOnPackageChanged_packageRemoval_importance() throws Exception { 1088 mHelper.setImportance(PKG, UID, NotificationManager.IMPORTANCE_HIGH); 1089 1090 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1091 1092 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID)); 1093 } 1094 1095 @Test 1096 public void testOnPackageChanged_packageRemoval_groups() throws Exception { 1097 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1098 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1099 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 1100 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 1101 1102 mHelper.onPackagesChanged(true, UserHandle.USER_SYSTEM, new String[]{PKG}, new int[]{UID}); 1103 1104 assertEquals(0, mHelper.getNotificationChannelGroups(PKG, UID, true).getList().size()); 1105 } 1106 1107 @Test 1108 public void testOnPackageChange_downgradeTargetSdk() throws Exception { 1109 // create channel as api 26 1110 mHelper.createNotificationChannel(UPDATED_PKG, UID2, getChannel(), true); 1111 1112 // install new app version targeting 25 1113 final ApplicationInfo legacy = new ApplicationInfo(); 1114 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1115 when(mPm.getApplicationInfoAsUser(eq(UPDATED_PKG), anyInt(), anyInt())).thenReturn(legacy); 1116 mHelper.onPackagesChanged( 1117 false, UserHandle.USER_SYSTEM, new String[]{UPDATED_PKG}, new int[]{UID2}); 1118 1119 // make sure the default channel was readded 1120 //assertEquals(2, mHelper.getNotificationChannels(UPDATED_PKG, UID2, false).getList().size()); 1121 assertNotNull(mHelper.getNotificationChannel( 1122 UPDATED_PKG, UID2, NotificationChannel.DEFAULT_CHANNEL_ID, false)); 1123 } 1124 1125 @Test 1126 public void testRecordDefaults() throws Exception { 1127 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, mHelper.getImportance(PKG, UID)); 1128 assertEquals(true, mHelper.canShowBadge(PKG, UID)); 1129 assertEquals(1, mHelper.getNotificationChannels(PKG, UID, false).getList().size()); 1130 } 1131 1132 @Test 1133 public void testCreateGroup() throws Exception { 1134 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1135 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1136 assertEquals(ncg, mHelper.getNotificationChannelGroups(PKG, UID).iterator().next()); 1137 } 1138 1139 @Test 1140 public void testCannotCreateChannel_badGroup() throws Exception { 1141 NotificationChannel channel1 = 1142 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1143 channel1.setGroup("garbage"); 1144 try { 1145 mHelper.createNotificationChannel(PKG, UID, channel1, true); 1146 fail("Created a channel with a bad group"); 1147 } catch (IllegalArgumentException e) { 1148 } 1149 } 1150 1151 @Test 1152 public void testCannotCreateChannel_goodGroup() throws Exception { 1153 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1154 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1155 NotificationChannel channel1 = 1156 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1157 channel1.setGroup(ncg.getId()); 1158 mHelper.createNotificationChannel(PKG, UID, channel1, true); 1159 1160 assertEquals(ncg.getId(), 1161 mHelper.getNotificationChannel(PKG, UID, channel1.getId(), false).getGroup()); 1162 } 1163 1164 @Test 1165 public void testGetChannelGroups() throws Exception { 1166 NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s"); 1167 mHelper.createNotificationChannelGroup(PKG, UID, unused, true); 1168 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1169 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1170 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 1171 mHelper.createNotificationChannelGroup(PKG, UID, ncg2, true); 1172 1173 NotificationChannel channel1 = 1174 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1175 channel1.setGroup(ncg.getId()); 1176 mHelper.createNotificationChannel(PKG, UID, channel1, true); 1177 NotificationChannel channel1a = 1178 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH); 1179 channel1a.setGroup(ncg.getId()); 1180 mHelper.createNotificationChannel(PKG, UID, channel1a, true); 1181 1182 NotificationChannel channel2 = 1183 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); 1184 channel2.setGroup(ncg2.getId()); 1185 mHelper.createNotificationChannel(PKG, UID, channel2, true); 1186 1187 NotificationChannel channel3 = 1188 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH); 1189 mHelper.createNotificationChannel(PKG, UID, channel3, true); 1190 1191 List<NotificationChannelGroup> actual = 1192 mHelper.getNotificationChannelGroups(PKG, UID, true).getList(); 1193 assertEquals(3, actual.size()); 1194 for (NotificationChannelGroup group : actual) { 1195 if (group.getId() == null) { 1196 assertEquals(2, group.getChannels().size()); // misc channel too 1197 assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()) 1198 || channel3.getId().equals(group.getChannels().get(1).getId())); 1199 } else if (group.getId().equals(ncg.getId())) { 1200 assertEquals(2, group.getChannels().size()); 1201 if (group.getChannels().get(0).getId().equals(channel1.getId())) { 1202 assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId())); 1203 } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) { 1204 assertTrue(group.getChannels().get(1).getId().equals(channel1.getId())); 1205 } else { 1206 fail("expected channel not found"); 1207 } 1208 } else if (group.getId().equals(ncg2.getId())) { 1209 assertEquals(1, group.getChannels().size()); 1210 assertEquals(channel2.getId(), group.getChannels().get(0).getId()); 1211 } 1212 } 1213 } 1214 1215 @Test 1216 public void testGetChannelGroups_noSideEffects() throws Exception { 1217 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 1218 mHelper.createNotificationChannelGroup(PKG, UID, ncg, true); 1219 1220 NotificationChannel channel1 = 1221 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1222 channel1.setGroup(ncg.getId()); 1223 mHelper.createNotificationChannel(PKG, UID, channel1, true); 1224 mHelper.getNotificationChannelGroups(PKG, UID, true).getList(); 1225 1226 channel1.setImportance(IMPORTANCE_LOW); 1227 mHelper.updateNotificationChannel(PKG, UID, channel1); 1228 1229 List<NotificationChannelGroup> actual = 1230 mHelper.getNotificationChannelGroups(PKG, UID, true).getList(); 1231 1232 assertEquals(2, actual.size()); 1233 for (NotificationChannelGroup group : actual) { 1234 if (Objects.equals(group.getId(), ncg.getId())) { 1235 assertEquals(1, group.getChannels().size()); 1236 } 1237 } 1238 } 1239 1240 @Test 1241 public void testCreateChannel_updateName() throws Exception { 1242 NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); 1243 mHelper.createNotificationChannel(PKG, UID, nc, true); 1244 NotificationChannel actual = mHelper.getNotificationChannel(PKG, UID, "id", false); 1245 assertEquals("hello", actual.getName()); 1246 1247 nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH); 1248 mHelper.createNotificationChannel(PKG, UID, nc, true); 1249 1250 actual = mHelper.getNotificationChannel(PKG, UID, "id", false); 1251 assertEquals("goodbye", actual.getName()); 1252 assertEquals(IMPORTANCE_DEFAULT, actual.getImportance()); 1253 } 1254 1255 @Test 1256 public void testDumpChannelsJson() throws Exception { 1257 final ApplicationInfo upgrade = new ApplicationInfo(); 1258 upgrade.targetSdkVersion = Build.VERSION_CODES.O; 1259 try { 1260 when(mPm.getApplicationInfoAsUser( 1261 anyString(), anyInt(), anyInt())).thenReturn(upgrade); 1262 } catch (PackageManager.NameNotFoundException e) { 1263 } 1264 ArrayMap<String, Integer> expectedChannels = new ArrayMap<>(); 1265 int numPackages = ThreadLocalRandom.current().nextInt(1, 5); 1266 for (int i = 0; i < numPackages; i++) { 1267 String pkgName = "pkg" + i; 1268 int numChannels = ThreadLocalRandom.current().nextInt(1, 10); 1269 for (int j = 0; j < numChannels; j++) { 1270 mHelper.createNotificationChannel(pkgName, UID, 1271 new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true); 1272 } 1273 expectedChannels.put(pkgName, numChannels); 1274 } 1275 1276 // delete the first channel of the first package 1277 String pkg = expectedChannels.keyAt(0); 1278 mHelper.deleteNotificationChannel("pkg" + 0, UID, "0"); 1279 // dump should not include deleted channels 1280 int count = expectedChannels.get(pkg); 1281 expectedChannels.put(pkg, count - 1); 1282 1283 JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter()); 1284 assertEquals(numPackages, actual.length()); 1285 for (int i = 0; i < numPackages; i++) { 1286 JSONObject object = actual.getJSONObject(i); 1287 assertTrue(expectedChannels.containsKey(object.get("packageName"))); 1288 assertEquals(expectedChannels.get(object.get("packageName")).intValue(), 1289 object.getInt("channelCount")); 1290 } 1291 } 1292 1293 @Test 1294 public void testBadgingOverrideTrue() throws Exception { 1295 Secure.putIntForUser(getContext().getContentResolver(), 1296 Secure.NOTIFICATION_BADGING, 1, 1297 USER.getIdentifier()); 1298 mHelper.updateBadgingEnabled(); // would be called by settings observer 1299 assertTrue(mHelper.badgingEnabled(USER)); 1300 } 1301 1302 @Test 1303 public void testBadgingOverrideFalse() throws Exception { 1304 Secure.putIntForUser(getContext().getContentResolver(), 1305 Secure.NOTIFICATION_BADGING, 0, 1306 USER.getIdentifier()); 1307 mHelper.updateBadgingEnabled(); // would be called by settings observer 1308 assertFalse(mHelper.badgingEnabled(USER)); 1309 } 1310 1311 @Test 1312 public void testBadgingForUserAll() throws Exception { 1313 try { 1314 mHelper.badgingEnabled(UserHandle.ALL); 1315 } catch (Exception e) { 1316 fail("just don't throw"); 1317 } 1318 } 1319 1320 @Test 1321 public void testBadgingOverrideUserIsolation() throws Exception { 1322 Secure.putIntForUser(getContext().getContentResolver(), 1323 Secure.NOTIFICATION_BADGING, 0, 1324 USER.getIdentifier()); 1325 Secure.putIntForUser(getContext().getContentResolver(), 1326 Secure.NOTIFICATION_BADGING, 1, 1327 USER2.getIdentifier()); 1328 mHelper.updateBadgingEnabled(); // would be called by settings observer 1329 assertFalse(mHelper.badgingEnabled(USER)); 1330 assertTrue(mHelper.badgingEnabled(USER2)); 1331 } 1332} 1333