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