1 /* 2 * Copyright (C) 2018 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 */ 16 package com.android.server.notification; 17 18 import static android.app.AppOpsManager.MODE_ALLOWED; 19 import static android.app.AppOpsManager.MODE_DEFAULT; 20 import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; 21 import static android.app.Notification.VISIBILITY_PRIVATE; 22 import static android.app.Notification.VISIBILITY_SECRET; 23 import static android.app.NotificationChannel.ALLOW_BUBBLE_ON; 24 import static android.app.NotificationChannel.CONVERSATION_CHANNEL_ID_FORMAT; 25 import static android.app.NotificationChannel.DEFAULT_ALLOW_BUBBLE; 26 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; 27 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE; 28 import static android.app.NotificationChannel.USER_LOCKED_LIGHTS; 29 import static android.app.NotificationChannel.USER_LOCKED_PRIORITY; 30 import static android.app.NotificationChannel.USER_LOCKED_SHOW_BADGE; 31 import static android.app.NotificationChannel.USER_LOCKED_SOUND; 32 import static android.app.NotificationChannel.USER_LOCKED_VIBRATION; 33 import static android.app.NotificationChannel.USER_LOCKED_VISIBILITY; 34 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; 35 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; 36 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; 37 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 38 import static android.app.NotificationManager.IMPORTANCE_HIGH; 39 import static android.app.NotificationManager.IMPORTANCE_LOW; 40 import static android.app.NotificationManager.IMPORTANCE_MAX; 41 import static android.app.NotificationManager.IMPORTANCE_NONE; 42 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; 43 import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE; 44 import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION; 45 import static android.media.AudioAttributes.USAGE_NOTIFICATION; 46 import static android.os.UserHandle.USER_ALL; 47 import static android.os.UserHandle.USER_SYSTEM; 48 49 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; 50 import static com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.NotificationFlags.PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS; 51 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED; 52 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED; 53 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED; 54 import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL; 55 import static com.android.server.notification.Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA; 56 import static com.android.server.notification.NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER; 57 import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE; 58 import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT; 59 import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; 60 import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID; 61 62 import static com.google.common.truth.Truth.assertThat; 63 64 import static junit.framework.Assert.assertNull; 65 import static junit.framework.Assert.fail; 66 67 import static org.junit.Assert.assertEquals; 68 import static org.junit.Assert.assertFalse; 69 import static org.junit.Assert.assertNotNull; 70 import static org.junit.Assert.assertThrows; 71 import static org.junit.Assert.assertTrue; 72 import static org.mockito.ArgumentMatchers.any; 73 import static org.mockito.ArgumentMatchers.anyInt; 74 import static org.mockito.ArgumentMatchers.anyString; 75 import static org.mockito.ArgumentMatchers.eq; 76 import static org.mockito.Mockito.clearInvocations; 77 import static org.mockito.Mockito.doAnswer; 78 import static org.mockito.Mockito.doReturn; 79 import static org.mockito.Mockito.mock; 80 import static org.mockito.Mockito.never; 81 import static org.mockito.Mockito.reset; 82 import static org.mockito.Mockito.times; 83 import static org.mockito.Mockito.verify; 84 import static org.mockito.Mockito.verifyZeroInteractions; 85 import static org.mockito.Mockito.when; 86 87 import android.app.AppOpsManager; 88 import android.app.Notification; 89 import android.app.NotificationChannel; 90 import android.app.NotificationChannelGroup; 91 import android.app.NotificationManager; 92 import android.content.AttributionSource; 93 import android.content.ContentProvider; 94 import android.content.ContentResolver; 95 import android.content.Context; 96 import android.content.IContentProvider; 97 import android.content.pm.ApplicationInfo; 98 import android.content.pm.PackageInfo; 99 import android.content.pm.PackageManager; 100 import android.content.pm.Signature; 101 import android.content.pm.UserInfo; 102 import android.content.res.Resources; 103 import android.graphics.Color; 104 import android.media.AudioAttributes; 105 import android.net.Uri; 106 import android.os.AsyncTask; 107 import android.os.Build; 108 import android.os.Bundle; 109 import android.os.Parcel; 110 import android.os.Process; 111 import android.os.RemoteCallback; 112 import android.os.RemoteException; 113 import android.os.UserHandle; 114 import android.os.UserManager; 115 import android.permission.PermissionManager; 116 import android.platform.test.annotations.EnableFlags; 117 import android.platform.test.flag.junit.FlagsParameterization; 118 import android.platform.test.flag.junit.SetFlagsRule; 119 import android.provider.Settings; 120 import android.provider.Settings.Global; 121 import android.provider.Settings.Secure; 122 import android.service.notification.ConversationChannelWrapper; 123 import android.service.notification.nano.RankingHelperProto; 124 import android.testing.TestableContentResolver; 125 import android.text.format.DateUtils; 126 import android.util.ArrayMap; 127 import android.util.ArraySet; 128 import android.util.IntArray; 129 import android.util.Pair; 130 import android.util.StatsEvent; 131 import android.util.StatsEventTestUtils; 132 import android.util.Xml; 133 import android.util.proto.ProtoOutputStream; 134 135 import androidx.test.InstrumentationRegistry; 136 import androidx.test.filters.SmallTest; 137 import androidx.test.runner.AndroidJUnit4; 138 139 import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags; 140 import com.android.internal.config.sysui.TestableFlagResolver; 141 import com.android.modules.utils.TypedXmlPullParser; 142 import com.android.modules.utils.TypedXmlSerializer; 143 import com.android.os.AtomsProto; 144 import com.android.os.AtomsProto.PackageNotificationChannelPreferences; 145 import com.android.os.AtomsProto.PackageNotificationPreferences; 146 import com.android.server.UiServiceTestCase; 147 import com.android.server.notification.PermissionHelper.PackagePermission; 148 149 import platform.test.runner.parameterized.ParameterizedAndroidJunit4; 150 import platform.test.runner.parameterized.Parameters; 151 152 import com.google.common.collect.ImmutableList; 153 import com.google.common.collect.ImmutableSet; 154 import com.google.protobuf.InvalidProtocolBufferException; 155 156 import org.json.JSONArray; 157 import org.json.JSONObject; 158 import org.junit.After; 159 import org.junit.Before; 160 import org.junit.Rule; 161 import org.junit.Test; 162 import org.junit.runner.RunWith; 163 import org.mockito.Mock; 164 import org.mockito.MockitoAnnotations; 165 166 import java.io.BufferedInputStream; 167 import java.io.BufferedOutputStream; 168 import java.io.ByteArrayInputStream; 169 import java.io.ByteArrayOutputStream; 170 import java.io.FileNotFoundException; 171 import java.io.PrintWriter; 172 import java.io.StringWriter; 173 import java.time.Clock; 174 import java.time.Duration; 175 import java.util.ArrayList; 176 import java.util.Arrays; 177 import java.util.HashMap; 178 import java.util.LinkedList; 179 import java.util.List; 180 import java.util.Map; 181 import java.util.Objects; 182 import java.util.Set; 183 import java.util.concurrent.CountDownLatch; 184 import java.util.concurrent.ThreadLocalRandom; 185 186 @SmallTest 187 @RunWith(ParameterizedAndroidJunit4.class) 188 public class PreferencesHelperTest extends UiServiceTestCase { 189 private static final int UID_HEADLESS = 1000000; 190 private static final UserHandle USER = UserHandle.of(0); 191 private static final String SYSTEM_PKG = "android"; 192 private static final int SYSTEM_UID = 1000; 193 private static final UserHandle USER2 = UserHandle.of(10); 194 private static final String TEST_AUTHORITY = "test"; 195 private static final Uri SOUND_URI = 196 Uri.parse("content://" + TEST_AUTHORITY + "/internal/audio/media/10"); 197 private static final Uri CANONICAL_SOUND_URI = 198 Uri.parse("content://" + TEST_AUTHORITY 199 + "/internal/audio/media/10?title=Test&canonical=1"); 200 201 private static final Uri ANDROID_RES_SOUND_URI = 202 Uri.parse("android.resource://" + TEST_AUTHORITY + "/raw/test"); 203 204 private static final Uri FILE_SOUND_URI = 205 Uri.parse("file://" + TEST_AUTHORITY + "/product/media/test.ogg"); 206 207 private static final Uri DEFAULT_SOUND_URI = Uri.parse( 208 "content://settings/system/notification_sound"); 209 210 @Mock PermissionHelper mPermissionHelper; 211 @Mock RankingHandler mHandler; 212 @Mock PackageManager mPm; 213 IContentProvider mTestIContentProvider; 214 @Mock Context mContext; 215 @Mock ZenModeHelper mMockZenModeHelper; 216 @Mock AppOpsManager mAppOpsManager; 217 @Mock ManagedServices.UserProfiles mUserProfiles; 218 @Mock PermissionManager mPermissionManager; 219 220 private NotificationManager.Policy mTestNotificationPolicy; 221 222 private PreferencesHelper mHelper; 223 // fresh object for testing xml reading 224 private PreferencesHelper mXmlHelper; 225 private AudioAttributes mAudioAttributes; 226 private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake(); 227 228 @Rule 229 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT); 230 231 @Mock 232 Clock mClock; 233 234 @Parameters(name = "{0}") getParams()235 public static List<FlagsParameterization> getParams() { 236 return FlagsParameterization.allCombinationsOf( 237 FLAG_PERSIST_INCOMPLETE_RESTORE_DATA); 238 } 239 PreferencesHelperTest(FlagsParameterization flags)240 public PreferencesHelperTest(FlagsParameterization flags) { 241 mSetFlagsRule.setFlagsParameterization(flags); 242 } 243 244 @Before setUp()245 public void setUp() throws Exception { 246 MockitoAnnotations.initMocks(this); 247 248 final ApplicationInfo legacy = new ApplicationInfo(); 249 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 250 final ApplicationInfo upgrade = new ApplicationInfo(); 251 upgrade.targetSdkVersion = Build.VERSION_CODES.O; 252 when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy); 253 when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(upgrade); 254 when(mPm.getApplicationInfoAsUser(eq(PKG_P), anyInt(), anyInt())).thenReturn(upgrade); 255 when(mPm.getApplicationInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(upgrade); 256 when(mPm.getPackageUidAsUser(eq(PKG_N_MR1), anyInt())).thenReturn(UID_N_MR1); 257 when(mPm.getPackageUidAsUser(eq(PKG_O), anyInt())).thenReturn(UID_O); 258 when(mPm.getPackageUidAsUser(eq(PKG_P), anyInt())).thenReturn(UID_P); 259 when(mPm.getPackageUidAsUser(eq(SYSTEM_PKG), anyInt())).thenReturn(SYSTEM_UID); 260 PackageInfo info = mock(PackageInfo.class); 261 info.signatures = new Signature[] {mock(Signature.class)}; 262 when(mPm.getPackageInfoAsUser(eq(SYSTEM_PKG), anyInt(), anyInt())).thenReturn(info); 263 when(mPm.getPackageInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())) 264 .thenReturn(mock(PackageInfo.class)); 265 when(mContext.getResources()).thenReturn( 266 InstrumentationRegistry.getContext().getResources()); 267 when(mContext.getContentResolver()).thenReturn( 268 InstrumentationRegistry.getContext().getContentResolver()); 269 when(mPm.getPermissionFlags(any(), any(), any())) 270 .thenReturn(PackageManager.FLAG_PERMISSION_USER_SET); 271 when(mContext.getPackageManager()).thenReturn(mPm); 272 when(mContext.getApplicationInfo()).thenReturn(legacy); 273 // most tests assume badging is enabled 274 TestableContentResolver contentResolver = getContext().getContentResolver(); 275 contentResolver.setFallbackToExisting(false); 276 Secure.putIntForUser(contentResolver, 277 Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID_N_MR1)); 278 Secure.putIntForUser(contentResolver, Secure.NOTIFICATION_BUBBLES, 1, 279 UserHandle.getUserId(UID_N_MR1)); 280 281 ContentProvider testContentProvider = mock(ContentProvider.class); 282 mTestIContentProvider = mock(IContentProvider.class, invocation -> { 283 throw new UnsupportedOperationException("unimplemented mock method"); 284 }); 285 doAnswer(invocation -> { 286 AttributionSource attributionSource = invocation.getArgument(0); 287 Uri uri = invocation.getArgument(1); 288 RemoteCallback cb = invocation.getArgument(2); 289 IContentProvider mock = (IContentProvider) (invocation.getMock()); 290 AsyncTask.SERIAL_EXECUTOR.execute(() -> { 291 final Bundle bundle = new Bundle(); 292 try { 293 bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, 294 mock.canonicalize(attributionSource, uri)); 295 } catch (RemoteException e) { /* consume */ } 296 cb.sendResult(bundle); 297 }); 298 return null; 299 }).when(mTestIContentProvider).canonicalizeAsync(any(), any(), any()); 300 doAnswer(invocation -> { 301 AttributionSource attributionSource = invocation.getArgument(0); 302 Uri uri = invocation.getArgument(1); 303 RemoteCallback cb = invocation.getArgument(2); 304 IContentProvider mock = (IContentProvider) (invocation.getMock()); 305 AsyncTask.SERIAL_EXECUTOR.execute(() -> { 306 final Bundle bundle = new Bundle(); 307 try { 308 bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, 309 mock.uncanonicalize(attributionSource, uri)); 310 } catch (RemoteException e) { /* consume */ } 311 cb.sendResult(bundle); 312 }); 313 return null; 314 }).when(mTestIContentProvider).uncanonicalizeAsync(any(), any(), any()); 315 doAnswer(invocation -> { 316 Uri uri = invocation.getArgument(0); 317 RemoteCallback cb = invocation.getArgument(1); 318 IContentProvider mock = (IContentProvider) (invocation.getMock()); 319 AsyncTask.SERIAL_EXECUTOR.execute(() -> { 320 final Bundle bundle = new Bundle(); 321 try { 322 bundle.putString(ContentResolver.REMOTE_CALLBACK_RESULT, mock.getType(uri)); 323 } catch (RemoteException e) { /* consume */ } 324 cb.sendResult(bundle); 325 }); 326 return null; 327 }).when(mTestIContentProvider).getTypeAsync(any(), any()); 328 329 when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider); 330 contentResolver.addProvider(TEST_AUTHORITY, testContentProvider); 331 332 doReturn(CANONICAL_SOUND_URI) 333 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI)); 334 doReturn(CANONICAL_SOUND_URI) 335 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI)); 336 doReturn(SOUND_URI) 337 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI)); 338 339 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 340 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); 341 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 342 when(mAppOpsManager.noteOpNoThrow(anyInt(), anyInt(), 343 anyString(), eq(null), anyString())).thenReturn(MODE_DEFAULT); 344 345 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 346 appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false)); 347 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(true, false)); 348 appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false)); 349 350 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 351 .thenReturn(appPermissions); 352 353 IntArray currentProfileIds = IntArray.wrap(new int[]{0}); 354 if (UserManager.isHeadlessSystemUserMode()) { 355 currentProfileIds.add(UserHandle.getUserId(UID_HEADLESS)); 356 } 357 when(mUserProfiles.getCurrentProfileIds()).thenReturn(currentProfileIds); 358 when(mClock.millis()).thenReturn(System.currentTimeMillis()); 359 360 mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 361 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 362 false, mClock); 363 mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 364 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 365 false, mClock); 366 resetZenModeHelper(); 367 368 mAudioAttributes = new AudioAttributes.Builder() 369 .setContentType(AudioAttributes.CONTENT_TYPE_UNKNOWN) 370 .setUsage(AudioAttributes.USAGE_NOTIFICATION_RINGTONE) 371 .setFlags(AudioAttributes.FLAG_AUDIBILITY_ENFORCED) 372 .build(); 373 374 // make sure that the settings for review notification permissions are unset to begin with 375 Settings.Global.putInt(mContext.getContentResolver(), 376 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 377 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN); 378 } 379 380 @After tearDown()381 public void tearDown() { 382 SystemUiSystemPropertiesFlags.TEST_RESOLVER = null; 383 } 384 writeXmlAndPurge( String pkg, int uid, boolean forBackup, int userId, String... channelIds)385 private ByteArrayOutputStream writeXmlAndPurge( 386 String pkg, int uid, boolean forBackup, int userId, String... channelIds) 387 throws Exception { 388 TypedXmlSerializer serializer = Xml.newFastSerializer(); 389 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 390 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 391 serializer.startDocument(null, true); 392 mHelper.writeXml(serializer, forBackup, userId); 393 serializer.endDocument(); 394 serializer.flush(); 395 for (String channelId : channelIds) { 396 mHelper.permanentlyDeleteNotificationChannel(pkg, uid, channelId); 397 } 398 return baos; 399 } 400 loadStreamXml(ByteArrayOutputStream stream, boolean forRestore, int userId)401 private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore, int userId) 402 throws Exception { 403 loadByteArrayXml(stream.toByteArray(), forRestore, userId); 404 } 405 loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)406 private void loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId) 407 throws Exception { 408 TypedXmlPullParser parser = Xml.newFastPullParser(); 409 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null); 410 parser.nextTag(); 411 mXmlHelper.readXml(parser, forRestore, userId); 412 } 413 compareChannels(NotificationChannel expected, NotificationChannel actual)414 private void compareChannels(NotificationChannel expected, NotificationChannel actual) { 415 assertEquals(expected.getId(), actual.getId()); 416 assertEquals(expected.getName(), actual.getName()); 417 assertEquals(expected.getDescription(), actual.getDescription()); 418 assertEquals(expected.shouldVibrate(), actual.shouldVibrate()); 419 assertEquals(expected.shouldShowLights(), actual.shouldShowLights()); 420 assertEquals(expected.getImportance(), actual.getImportance()); 421 assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility()); 422 assertEquals(expected.getSound(), actual.getSound()); 423 assertEquals(expected.canBypassDnd(), actual.canBypassDnd()); 424 assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern())); 425 assertEquals(expected.getVibrationEffect(), actual.getVibrationEffect()); 426 assertEquals(expected.getGroup(), actual.getGroup()); 427 assertEquals(expected.getAudioAttributes(), actual.getAudioAttributes()); 428 assertEquals(expected.getLightColor(), actual.getLightColor()); 429 assertEquals(expected.getParentChannelId(), actual.getParentChannelId()); 430 assertEquals(expected.getConversationId(), actual.getConversationId()); 431 assertEquals(expected.isDemoted(), actual.isDemoted()); 432 } 433 compareChannelsParentChild(NotificationChannel parent, NotificationChannel actual, String conversationId)434 private void compareChannelsParentChild(NotificationChannel parent, 435 NotificationChannel actual, String conversationId) { 436 assertEquals(parent.getName(), actual.getName()); 437 assertEquals(parent.getDescription(), actual.getDescription()); 438 assertEquals(parent.shouldVibrate(), actual.shouldVibrate()); 439 assertEquals(parent.shouldShowLights(), actual.shouldShowLights()); 440 assertEquals(parent.getImportance(), actual.getImportance()); 441 assertEquals(parent.getLockscreenVisibility(), actual.getLockscreenVisibility()); 442 assertEquals(parent.getSound(), actual.getSound()); 443 assertEquals(parent.canBypassDnd(), actual.canBypassDnd()); 444 assertTrue(Arrays.equals(parent.getVibrationPattern(), actual.getVibrationPattern())); 445 assertEquals(parent.getVibrationEffect(), actual.getVibrationEffect()); 446 assertEquals(parent.getGroup(), actual.getGroup()); 447 assertEquals(parent.getAudioAttributes(), actual.getAudioAttributes()); 448 assertEquals(parent.getLightColor(), actual.getLightColor()); 449 assertEquals(parent.getId(), actual.getParentChannelId()); 450 assertEquals(conversationId, actual.getConversationId()); 451 } 452 compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual)453 private void compareGroups(NotificationChannelGroup expected, NotificationChannelGroup actual) { 454 assertEquals(expected.getId(), actual.getId()); 455 assertEquals(expected.getName(), actual.getName()); 456 assertEquals(expected.getDescription(), actual.getDescription()); 457 assertEquals(expected.isBlocked(), actual.isBlocked()); 458 } 459 getChannel()460 private NotificationChannel getChannel() { 461 return new NotificationChannel("id", "name", IMPORTANCE_LOW); 462 } 463 findChannel(List<NotificationChannel> channels, String id)464 private NotificationChannel findChannel(List<NotificationChannel> channels, String id) { 465 for (NotificationChannel channel : channels) { 466 if (channel.getId().equals(id)) { 467 return channel; 468 } 469 } 470 return null; 471 } 472 resetZenModeHelper()473 private void resetZenModeHelper() { 474 reset(mMockZenModeHelper); 475 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 476 } 477 setUpPackageWithUid(String packageName, int uid)478 private void setUpPackageWithUid(String packageName, int uid) throws Exception { 479 when(mPm.getApplicationInfoAsUser(eq(packageName), anyInt(), anyInt())) 480 .thenReturn(new ApplicationInfo()); 481 when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 482 } 483 testThreadSafety(Runnable operationToTest, int nThreads, int nRunsPerThread)484 private static void testThreadSafety(Runnable operationToTest, int nThreads, 485 int nRunsPerThread) throws Exception { 486 final CountDownLatch startLatch = new CountDownLatch(1); 487 final CountDownLatch doneLatch = new CountDownLatch(nThreads); 488 489 for (int i = 0; i < nThreads; i++) { 490 Runnable threadRunnable = () -> { 491 try { 492 startLatch.await(); 493 for (int j = 0; j < nRunsPerThread; j++) { 494 operationToTest.run(); 495 } 496 } catch (InterruptedException e) { 497 e.printStackTrace(); 498 } finally { 499 doneLatch.countDown(); 500 } 501 }; 502 new Thread(threadRunnable, "Test Thread #" + i).start(); 503 } 504 505 // Ready set go 506 startLatch.countDown(); 507 508 // Wait for all test threads to be done. 509 doneLatch.await(); 510 } 511 512 @Test testWriteXml_onlyBackupsTargetUser()513 public void testWriteXml_onlyBackupsTargetUser() throws Exception { 514 // Setup package notifications. 515 String package0 = "test.package.user0"; 516 int uid0 = 1001; 517 setUpPackageWithUid(package0, uid0); 518 NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH); 519 assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false, 520 uid0, false)); 521 522 String package10 = "test.package.user10"; 523 int uid10 = 1001001; 524 setUpPackageWithUid(package10, uid10); 525 NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH); 526 assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false, 527 uid10, false)); 528 529 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 530 appPermissions.put(new Pair<>(uid0, package0), new Pair<>(false, false)); 531 appPermissions.put(new Pair<>(uid10, package10), new Pair<>(true, false)); 532 533 when(mPermissionHelper.getNotificationPermissionValues(10)) 534 .thenReturn(appPermissions); 535 536 ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10); 537 538 // Reset state. 539 mHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0}); 540 mHelper.onPackagesChanged(true, 10, new String[] {package10}, new int[] {uid10}); 541 542 // Parse backup data. 543 loadStreamXml(baos, true, 0); 544 loadStreamXml(baos, true, 10); 545 546 assertEquals(channel10, 547 mXmlHelper.getNotificationChannel(package10, uid10, channel10.getId(), false)); 548 assertNull(mXmlHelper.getNotificationChannel(package0, uid0, channel0.getId(), false)); 549 } 550 551 @Test testReadXml_onlyRestoresTargetUser()552 public void testReadXml_onlyRestoresTargetUser() throws Exception { 553 // Setup package in user 0. 554 String package0 = "test.package.user0"; 555 int uid0 = 1001; 556 setUpPackageWithUid(package0, uid0); 557 NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH); 558 assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false, 559 uid0, false)); 560 561 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 562 appPermissions.put(new Pair<>(uid0, package0), new Pair<>(true, false)); 563 564 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 565 .thenReturn(appPermissions); 566 567 ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0); 568 569 // Reset state. 570 mXmlHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0}); 571 572 // Restore should convert the uid according to the target user. 573 int expectedUid = 1001001; 574 setUpPackageWithUid(package0, expectedUid); 575 // Parse backup data. 576 loadStreamXml(baos, true, 10); 577 578 assertEquals(channel0, 579 mXmlHelper.getNotificationChannel(package0, expectedUid, channel0.getId(), false)); 580 assertNull(mXmlHelper.getNotificationChannel(package0, uid0, channel0.getId(), false)); 581 } 582 583 @Test testChannelXml()584 public void testChannelXml() throws Exception { 585 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 586 ncg.setBlocked(true); 587 ncg.setDescription("group desc"); 588 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 589 NotificationChannel channel1 = 590 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 591 NotificationChannel channel2 = 592 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 593 channel2.setDescription("descriptions for all"); 594 channel2.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 595 channel2.enableLights(true); 596 channel2.setBypassDnd(true); 597 channel2.setLockscreenVisibility(VISIBILITY_SECRET); 598 channel2.enableVibration(true); 599 channel2.setGroup(ncg.getId()); 600 channel2.setVibrationPattern(new long[]{100, 67, 145, 156}); 601 channel2.setLightColor(Color.BLUE); 602 channel2.setConversationId("id1", "conversation"); 603 channel2.setDemoted(true); 604 605 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 606 UID_N_MR1, false); 607 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 608 UID_N_MR1, false); 609 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 610 UID_N_MR1, false)); 611 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, 612 UID_N_MR1, false)); 613 614 mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); 615 616 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, 617 UserHandle.USER_ALL, channel1.getId(), channel2.getId(), 618 NotificationChannel.DEFAULT_CHANNEL_ID); 619 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{ 620 UID_N_MR1}); 621 622 loadStreamXml(baos, false, UserHandle.USER_ALL); 623 624 assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 625 assertEquals(channel1, 626 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false)); 627 compareChannels(channel2, 628 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false)); 629 630 List<NotificationChannelGroup> actualGroups = mXmlHelper.getNotificationChannelGroups( 631 PKG_N_MR1, UID_N_MR1, false, true, false, true, null).getList(); 632 boolean foundNcg = false; 633 for (NotificationChannelGroup actual : actualGroups) { 634 if (ncg.getId().equals(actual.getId())) { 635 foundNcg = true; 636 compareGroups(ncg, actual); 637 } else if (ncg2.getId().equals(actual.getId())) { 638 compareGroups(ncg2, actual); 639 } 640 } 641 assertTrue(foundNcg); 642 643 boolean foundChannel2Group = false; 644 for (NotificationChannelGroup actual : actualGroups) { 645 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) { 646 foundChannel2Group = true; 647 break; 648 } 649 } 650 assertTrue(foundChannel2Group); 651 } 652 653 @Test testChannelXmlForBackup()654 public void testChannelXmlForBackup() throws Exception { 655 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 656 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 657 NotificationChannel channel1 = 658 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 659 NotificationChannel channel2 = 660 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 661 channel2.setDescription("descriptions for all"); 662 channel2.setSound(CANONICAL_SOUND_URI, mAudioAttributes); 663 channel2.enableLights(true); 664 channel2.setBypassDnd(true); 665 channel2.setLockscreenVisibility(VISIBILITY_SECRET); 666 channel2.enableVibration(false); 667 channel2.setGroup(ncg.getId()); 668 channel2.setLightColor(Color.BLUE); 669 NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); 670 channel3.enableVibration(true); 671 672 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 673 UID_N_MR1, false); 674 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 675 UID_N_MR1, false); 676 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 677 UID_N_MR1, false); 678 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, 679 SYSTEM_UID, true); 680 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, 681 SYSTEM_UID, true); 682 mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, 683 UID_N_MR1, false); 684 685 mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); 686 mHelper.setInvalidMessageSent(PKG_P, UID_P); 687 mHelper.setValidMessageSent(PKG_P, UID_P); 688 mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true); 689 mHelper.setValidBubbleSent(PKG_P, UID_P); 690 691 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 692 USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(), 693 NotificationChannel.DEFAULT_CHANNEL_ID); 694 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1, PKG_O}, 695 new int[]{UID_N_MR1, UID_O}); 696 697 mHelper.setShowBadge(PKG_O, UID_O, true); 698 699 loadStreamXml(baos, true, USER_SYSTEM); 700 701 assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 702 assertTrue(mXmlHelper.hasSentInvalidMsg(PKG_P, UID_P)); 703 assertFalse(mXmlHelper.hasSentInvalidMsg(PKG_N_MR1, UID_N_MR1)); 704 assertTrue(mXmlHelper.hasSentValidMsg(PKG_P, UID_P)); 705 assertTrue(mXmlHelper.didUserEverDemoteInvalidMsgApp(PKG_P, UID_P)); 706 assertTrue(mXmlHelper.hasSentValidBubble(PKG_P, UID_P)); 707 assertEquals(channel1, 708 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false)); 709 compareChannels(channel2, 710 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false)); 711 compareChannels(channel3, 712 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false)); 713 714 List<NotificationChannelGroup> actualGroups = mXmlHelper.getNotificationChannelGroups( 715 PKG_N_MR1, UID_N_MR1, false, true, false, true, null).getList(); 716 boolean foundNcg = false; 717 for (NotificationChannelGroup actual : actualGroups) { 718 if (ncg.getId().equals(actual.getId())) { 719 foundNcg = true; 720 compareGroups(ncg, actual); 721 } else if (ncg2.getId().equals(actual.getId())) { 722 compareGroups(ncg2, actual); 723 } 724 } 725 assertTrue(foundNcg); 726 727 boolean foundChannel2Group = false; 728 for (NotificationChannelGroup actual : actualGroups) { 729 if (channel2.getGroup().equals(actual.getChannels().get(0).getGroup())) { 730 foundChannel2Group = true; 731 break; 732 } 733 } 734 assertTrue(foundChannel2Group); 735 } 736 737 @Test testReadXml_oldXml_migrates()738 public void testReadXml_oldXml_migrates() throws Exception { 739 mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 740 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 741 /* showReviewPermissionsNotification= */ true, mClock); 742 743 String xml = "<ranking version=\"2\">\n" 744 + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1 745 + "\" show_badge=\"true\">\n" 746 + "<channel id=\"idn\" name=\"name\" importance=\"2\" />\n" 747 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n" 748 + "</package>\n" 749 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" importance=\"0\">\n" 750 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n" 751 + "</package>\n" 752 + "<package name=\"" + PKG_P + "\" uid=\"" + UID_P + "\" importance=\"2\">\n" 753 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n" 754 + "</package>\n" 755 + "</ranking>\n"; 756 757 loadByteArrayXml(xml.getBytes(), false, USER_SYSTEM); 758 759 // expected values 760 NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW); 761 idn.setSound(null, new AudioAttributes.Builder() 762 .setUsage(USAGE_NOTIFICATION) 763 .setContentType(CONTENT_TYPE_SONIFICATION) 764 .setFlags(0) 765 .build()); 766 idn.setShowBadge(false); 767 NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW); 768 ido.setShowBadge(true); 769 ido.setSound(null, new AudioAttributes.Builder() 770 .setUsage(USAGE_NOTIFICATION) 771 .setContentType(CONTENT_TYPE_SONIFICATION) 772 .setFlags(0) 773 .build()); 774 NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH); 775 idp.lockFields(2); 776 idp.setSound(null, new AudioAttributes.Builder() 777 .setUsage(USAGE_NOTIFICATION) 778 .setContentType(CONTENT_TYPE_SONIFICATION) 779 .setFlags(0) 780 .build()); 781 782 // verify data 783 assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 784 785 assertEquals(idn, 786 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false)); 787 compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false)); 788 compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false)); 789 790 // verify that we also write a state for review_permissions_notification to eventually 791 // show a notification 792 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW, 793 Settings.Global.getInt(mContext.getContentResolver(), 794 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 795 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 796 } 797 798 @Test testReadXml_oldXml_backup_migratesWhenPkgInstalled()799 public void testReadXml_oldXml_backup_migratesWhenPkgInstalled() throws Exception { 800 when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(UNKNOWN_UID); 801 when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(UNKNOWN_UID); 802 when(mPm.getPackageUidAsUser("pkg3", USER_SYSTEM)).thenReturn(UNKNOWN_UID); 803 when(mPm.getApplicationInfoAsUser(eq("pkg1"), anyInt(), anyInt())).thenThrow( 804 new PackageManager.NameNotFoundException()); 805 when(mPm.getApplicationInfoAsUser(eq("pkg2"), anyInt(), anyInt())).thenThrow( 806 new PackageManager.NameNotFoundException()); 807 when(mPm.getApplicationInfoAsUser(eq("pkg3"), anyInt(), anyInt())).thenThrow( 808 new PackageManager.NameNotFoundException()); 809 810 String xml = "<ranking version=\"2\">\n" 811 + "<package name=\"pkg1\" show_badge=\"true\">\n" 812 + "<channel id=\"idn\" name=\"name\" importance=\"2\" />\n" 813 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n" 814 + "</package>\n" 815 + "<package name=\"pkg2\" importance=\"0\">\n" 816 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n" 817 + "</package>\n" 818 + "<package name=\"pkg3\" importance=\"2\">\n" 819 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n" 820 + "</package>\n" 821 + "</ranking>\n"; 822 NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW); 823 idn.setSound(null, new AudioAttributes.Builder() 824 .setUsage(USAGE_NOTIFICATION) 825 .setContentType(CONTENT_TYPE_SONIFICATION) 826 .setFlags(0) 827 .build()); 828 idn.setShowBadge(false); 829 NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW); 830 ido.setShowBadge(true); 831 ido.setSound(null, new AudioAttributes.Builder() 832 .setUsage(USAGE_NOTIFICATION) 833 .setContentType(CONTENT_TYPE_SONIFICATION) 834 .setFlags(0) 835 .build()); 836 NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH); 837 idp.lockFields(2); 838 idp.setSound(null, new AudioAttributes.Builder() 839 .setUsage(USAGE_NOTIFICATION) 840 .setContentType(CONTENT_TYPE_SONIFICATION) 841 .setFlags(0) 842 .build()); 843 844 // Notifications enabled, not user set 845 PackagePermission pkg1Expected = new PackagePermission("pkg1", 0, true, false); 846 // Notifications not enabled, so user set 847 PackagePermission pkg2Expected = new PackagePermission("pkg2", 0, false, true); 848 // Notifications enabled, user set b/c channel modified 849 PackagePermission pkg3Expected = new PackagePermission("pkg3", 0, true, true); 850 851 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 852 853 verify(mPermissionHelper, never()).setNotificationPermission(any()); 854 855 when(mPm.getPackageUidAsUser("pkg1", USER_SYSTEM)).thenReturn(11); 856 when(mPm.getPackageUidAsUser("pkg2", USER_SYSTEM)).thenReturn(12); 857 when(mPm.getPackageUidAsUser("pkg3", USER_SYSTEM)).thenReturn(13); 858 859 mXmlHelper.onPackagesChanged( 860 false, 0, new String[]{"pkg1", "pkg2", "pkg3"}, new int[] {11, 12, 13}); 861 862 assertTrue(mXmlHelper.canShowBadge("pkg1", 11)); 863 864 assertEquals(idn, mXmlHelper.getNotificationChannel("pkg1", 11, idn.getId(), false)); 865 compareChannels(ido, mXmlHelper.getNotificationChannel("pkg2", 12, ido.getId(), false)); 866 compareChannels(idp, mXmlHelper.getNotificationChannel("pkg3", 13, idp.getId(), false)); 867 868 verify(mPermissionHelper).setNotificationPermission(pkg1Expected); 869 verify(mPermissionHelper).setNotificationPermission(pkg2Expected); 870 verify(mPermissionHelper).setNotificationPermission(pkg3Expected); 871 } 872 873 @Test testReadXml_newXml_noMigration_showPermissionNotification()874 public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception { 875 mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 876 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 877 /* showReviewPermissionsNotification= */ true, mClock); 878 879 String xml = "<ranking version=\"3\">\n" 880 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" 881 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n" 882 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n" 883 + "</package>\n" 884 + "<package name=\"" + PKG_O + "\" >\n" 885 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n" 886 + "</package>\n" 887 + "<package name=\"" + PKG_P + "\" >\n" 888 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n" 889 + "</package>\n" 890 + "</ranking>\n"; 891 NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW); 892 idn.setSound(null, new AudioAttributes.Builder() 893 .setUsage(USAGE_NOTIFICATION) 894 .setContentType(CONTENT_TYPE_SONIFICATION) 895 .setFlags(0) 896 .build()); 897 idn.setShowBadge(false); 898 NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW); 899 ido.setShowBadge(true); 900 ido.setSound(null, new AudioAttributes.Builder() 901 .setUsage(USAGE_NOTIFICATION) 902 .setContentType(CONTENT_TYPE_SONIFICATION) 903 .setFlags(0) 904 .build()); 905 NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH); 906 idp.lockFields(2); 907 idp.setSound(null, new AudioAttributes.Builder() 908 .setUsage(USAGE_NOTIFICATION) 909 .setContentType(CONTENT_TYPE_SONIFICATION) 910 .setFlags(0) 911 .build()); 912 913 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 914 915 assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 916 917 assertEquals(idn, 918 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false)); 919 compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false)); 920 compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false)); 921 922 verify(mPermissionHelper, never()).setNotificationPermission(any()); 923 924 // verify that we do, however, write a state for review_permissions_notification to 925 // eventually show a notification, since this XML version is older than the notification 926 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW, 927 Settings.Global.getInt(mContext.getContentResolver(), 928 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 929 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 930 } 931 932 @Test testReadXml_newXml_permissionNotificationOff()933 public void testReadXml_newXml_permissionNotificationOff() throws Exception { 934 mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 935 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 936 /* showReviewPermissionsNotification= */ false, mClock); 937 938 String xml = "<ranking version=\"3\">\n" 939 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" 940 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n" 941 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n" 942 + "</package>\n" 943 + "<package name=\"" + PKG_O + "\" >\n" 944 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n" 945 + "</package>\n" 946 + "<package name=\"" + PKG_P + "\" >\n" 947 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n" 948 + "</package>\n" 949 + "</ranking>\n"; 950 NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW); 951 idn.setSound(null, new AudioAttributes.Builder() 952 .setUsage(USAGE_NOTIFICATION) 953 .setContentType(CONTENT_TYPE_SONIFICATION) 954 .setFlags(0) 955 .build()); 956 idn.setShowBadge(false); 957 NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW); 958 ido.setShowBadge(true); 959 ido.setSound(null, new AudioAttributes.Builder() 960 .setUsage(USAGE_NOTIFICATION) 961 .setContentType(CONTENT_TYPE_SONIFICATION) 962 .setFlags(0) 963 .build()); 964 NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH); 965 idp.lockFields(2); 966 idp.setSound(null, new AudioAttributes.Builder() 967 .setUsage(USAGE_NOTIFICATION) 968 .setContentType(CONTENT_TYPE_SONIFICATION) 969 .setFlags(0) 970 .build()); 971 972 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 973 974 assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 975 976 assertEquals(idn, 977 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false)); 978 compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false)); 979 compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false)); 980 981 verify(mPermissionHelper, never()).setNotificationPermission(any()); 982 983 // while this is the same case as above, if the permission helper is set to not show the 984 // review permissions notification it should not write anything to the settings int 985 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN, 986 Settings.Global.getInt(mContext.getContentResolver(), 987 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 988 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 989 } 990 991 @Test testReadXml_newXml_noMigration_noPermissionNotification()992 public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception { 993 mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 994 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 995 /* showReviewPermissionsNotification= */ true, mClock); 996 997 String xml = "<ranking version=\"4\">\n" 998 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" 999 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n" 1000 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" />\n" 1001 + "</package>\n" 1002 + "<package name=\"" + PKG_O + "\" >\n" 1003 + "<channel id=\"ido\" name=\"name2\" importance=\"2\" show_badge=\"true\"/>\n" 1004 + "</package>\n" 1005 + "<package name=\"" + PKG_P + "\" >\n" 1006 + "<channel id=\"idp\" name=\"name3\" importance=\"4\" locked=\"2\" />\n" 1007 + "</package>\n" 1008 + "</ranking>\n"; 1009 NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW); 1010 idn.setSound(null, new AudioAttributes.Builder() 1011 .setUsage(USAGE_NOTIFICATION) 1012 .setContentType(CONTENT_TYPE_SONIFICATION) 1013 .setFlags(0) 1014 .build()); 1015 idn.setShowBadge(false); 1016 NotificationChannel ido = new NotificationChannel("ido", "name2", IMPORTANCE_LOW); 1017 ido.setShowBadge(true); 1018 ido.setSound(null, new AudioAttributes.Builder() 1019 .setUsage(USAGE_NOTIFICATION) 1020 .setContentType(CONTENT_TYPE_SONIFICATION) 1021 .setFlags(0) 1022 .build()); 1023 NotificationChannel idp = new NotificationChannel("idp", "name3", IMPORTANCE_HIGH); 1024 idp.lockFields(2); 1025 idp.setSound(null, new AudioAttributes.Builder() 1026 .setUsage(USAGE_NOTIFICATION) 1027 .setContentType(CONTENT_TYPE_SONIFICATION) 1028 .setFlags(0) 1029 .build()); 1030 1031 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 1032 1033 assertTrue(mXmlHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 1034 1035 assertEquals(idn, 1036 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, idn.getId(), false)); 1037 compareChannels(ido, mXmlHelper.getNotificationChannel(PKG_O, UID_O, ido.getId(), false)); 1038 compareChannels(idp, mXmlHelper.getNotificationChannel(PKG_P, UID_P, idp.getId(), false)); 1039 1040 verify(mPermissionHelper, never()).setNotificationPermission(any()); 1041 1042 // this XML is new enough, we should not be attempting to show a notification or anything 1043 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN, 1044 Settings.Global.getInt(mContext.getContentResolver(), 1045 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 1046 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 1047 } 1048 1049 @Test testReadXml_oldXml_migration_NoUid()1050 public void testReadXml_oldXml_migration_NoUid() throws Exception { 1051 when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID); 1052 String xml = "<ranking version=\"2\">\n" 1053 + "<package name=\"something\" show_badge=\"true\">\n" 1054 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n" 1055 + "</package>\n" 1056 + "</ranking>\n"; 1057 NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW); 1058 idn.setSound(null, new AudioAttributes.Builder() 1059 .setUsage(USAGE_NOTIFICATION) 1060 .setContentType(CONTENT_TYPE_SONIFICATION) 1061 .setFlags(0) 1062 .build()); 1063 idn.setShowBadge(false); 1064 1065 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 1066 verify(mPermissionHelper, never()).setNotificationPermission(any()); 1067 1068 when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234); 1069 final ApplicationInfo app = new ApplicationInfo(); 1070 app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 1071 when(mPm.getApplicationInfoAsUser( 1072 eq("something"), anyInt(), eq(USER_SYSTEM))).thenReturn(app); 1073 1074 mXmlHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234}); 1075 1076 verify(mPermissionHelper, times(1)).setNotificationPermission(any()); 1077 } 1078 1079 @Test testReadXml_newXml_noMigration_NoUid()1080 public void testReadXml_newXml_noMigration_NoUid() throws Exception { 1081 when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(UNKNOWN_UID); 1082 String xml = "<ranking version=\"3\">\n" 1083 + "<package name=\"something\" show_badge=\"true\">\n" 1084 + "<channel id=\"idn\" name=\"name\" importance=\"2\"/>\n" 1085 + "</package>\n" 1086 + "</ranking>\n"; 1087 NotificationChannel idn = new NotificationChannel("idn", "name", IMPORTANCE_LOW); 1088 idn.setSound(null, new AudioAttributes.Builder() 1089 .setUsage(USAGE_NOTIFICATION) 1090 .setContentType(CONTENT_TYPE_SONIFICATION) 1091 .setFlags(0) 1092 .build()); 1093 idn.setShowBadge(false); 1094 1095 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 1096 1097 when(mPm.getPackageUidAsUser("something", USER_SYSTEM)).thenReturn(1234); 1098 final ApplicationInfo app = new ApplicationInfo(); 1099 app.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 1100 when(mPm.getApplicationInfoAsUser(eq("something"), anyInt(), anyInt())).thenReturn(app); 1101 1102 mXmlHelper.onPackagesChanged(false, 0, new String[] {"something"}, new int[] {1234}); 1103 1104 verify(mPermissionHelper, never()).setNotificationPermission(any()); 1105 } 1106 1107 @Test testChannelXmlForNonBackup_postMigration()1108 public void testChannelXmlForNonBackup_postMigration() throws Exception { 1109 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 1110 appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); 1111 appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); 1112 appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false)); 1113 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); 1114 appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false)); 1115 1116 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 1117 .thenReturn(appPermissions); 1118 1119 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 1120 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 1121 NotificationChannel channel1 = 1122 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1123 channel1.setSound(null, null); 1124 NotificationChannel channel2 = 1125 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1126 channel2.setDescription("descriptions for all"); 1127 channel2.setSound(null, null); 1128 channel2.enableLights(true); 1129 channel2.setBypassDnd(true); 1130 channel2.setLockscreenVisibility(VISIBILITY_SECRET); 1131 channel2.enableVibration(false); 1132 channel2.setGroup(ncg.getId()); 1133 channel2.setLightColor(Color.BLUE); 1134 NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); 1135 channel3.enableVibration(true); 1136 1137 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 1138 UID_N_MR1, false); 1139 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 1140 UID_N_MR1, false); 1141 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 1142 UID_N_MR1, false); 1143 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, 1144 SYSTEM_UID, true); 1145 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, 1146 SYSTEM_UID, true); 1147 mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, 1148 UID_N_MR1, false); 1149 1150 mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); 1151 mHelper.setInvalidMessageSent(PKG_P, UID_P); 1152 mHelper.setValidMessageSent(PKG_P, UID_P); 1153 mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true); 1154 1155 ByteArrayOutputStream baos = writeXmlAndPurge( 1156 PKG_N_MR1, UID_N_MR1, false, USER_SYSTEM); 1157 String expected = "<ranking version=\"4\">\n" 1158 + "<package name=\"com.example.o\" show_badge=\"true\" " 1159 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" " 1160 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble" 1161 + "=\"false\" uid=\"10002\">\n" 1162 + "<channel id=\"id\" name=\"name\" importance=\"2\" " 1163 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1164 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n" 1165 + "</package>\n" 1166 + "<package name=\"com.example.n_mr1\" show_badge=\"true\" " 1167 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" " 1168 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble" 1169 + "=\"false\" uid=\"10001\">\n" 1170 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n" 1171 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n" 1172 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" " 1173 + "orig_imp=\"4\" />\n" 1174 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" " 1175 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" " 1176 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n" 1177 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" " 1178 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1179 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" " 1180 + "orig_imp=\"4\" />\n" 1181 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" " 1182 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1183 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" 1184 + "</package>\n" 1185 + "<package name=\"com.example.p\" show_badge=\"true\" " 1186 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\"" 1187 + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" uid=\"10003\" />\n" 1188 + "</ranking>"; 1189 assertThat(baos.toString()).contains(expected); 1190 } 1191 1192 @Test testChannelXmlForBackup_postMigration()1193 public void testChannelXmlForBackup_postMigration() throws Exception { 1194 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 1195 appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); 1196 appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); 1197 appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false)); 1198 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); 1199 appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false)); 1200 1201 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 1202 .thenReturn(appPermissions); 1203 1204 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 1205 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 1206 NotificationChannel channel1 = 1207 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1208 channel1.setSound(null, null); 1209 NotificationChannel channel2 = 1210 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1211 channel2.setDescription("descriptions for all"); 1212 channel2.setSound(null, null); 1213 channel2.enableLights(true); 1214 channel2.setBypassDnd(true); 1215 channel2.setLockscreenVisibility(VISIBILITY_SECRET); 1216 channel2.enableVibration(false); 1217 channel2.setGroup(ncg.getId()); 1218 channel2.setLightColor(Color.BLUE); 1219 NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); 1220 channel3.enableVibration(true); 1221 1222 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 1223 UID_N_MR1, false); 1224 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 1225 UID_N_MR1, false); 1226 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 1227 UID_N_MR1, false); 1228 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, 1229 SYSTEM_UID, true); 1230 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, 1231 SYSTEM_UID, true); 1232 mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, 1233 UID_N_MR1, false); 1234 1235 mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); 1236 mHelper.setInvalidMessageSent(PKG_P, UID_P); 1237 mHelper.setValidMessageSent(PKG_P, UID_P); 1238 mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true); 1239 1240 ByteArrayOutputStream baos = writeXmlAndPurge( 1241 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM); 1242 String expected = "<ranking version=\"4\">\n" 1243 // Importance 0 because off in permissionhelper 1244 + "<package name=\"com.example.o\" importance=\"0\" show_badge=\"true\" " 1245 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" " 1246 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble" 1247 + "=\"false\">\n" 1248 + "<channel id=\"id\" name=\"name\" importance=\"2\" " 1249 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1250 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n" 1251 + "</package>\n" 1252 // Importance default because on in permission helper 1253 + "<package name=\"com.example.n_mr1\" importance=\"3\" show_badge=\"true\" " 1254 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" " 1255 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble" 1256 + "=\"false\">\n" 1257 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n" 1258 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n" 1259 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" " 1260 + "orig_imp=\"4\" />\n" 1261 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" " 1262 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" " 1263 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n" 1264 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" " 1265 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1266 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" " 1267 + "orig_imp=\"4\" />\n" 1268 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" " 1269 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1270 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" 1271 + "</package>\n" 1272 // Importance default because on in permission helper 1273 + "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" " 1274 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\"" 1275 + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" />\n" 1276 // Packages that exist solely in permissionhelper 1277 + "<package name=\"first\" importance=\"3\" />\n" 1278 + "<package name=\"third\" importance=\"0\" />\n" 1279 + "</ranking>"; 1280 assertThat(baos.toString()).contains(expected); 1281 } 1282 1283 @Test testChannelXmlForBackup_postMigration_noExternal()1284 public void testChannelXmlForBackup_postMigration_noExternal() throws Exception { 1285 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 1286 appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false)); 1287 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); 1288 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 1289 .thenReturn(appPermissions); 1290 1291 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 1292 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 1293 NotificationChannel channel1 = 1294 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1295 channel1.setSound(null, null); 1296 NotificationChannel channel2 = 1297 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 1298 channel2.setDescription("descriptions for all"); 1299 channel2.setSound(null, null); 1300 channel2.enableLights(true); 1301 channel2.setBypassDnd(true); 1302 channel2.setLockscreenVisibility(VISIBILITY_SECRET); 1303 channel2.enableVibration(false); 1304 channel2.setGroup(ncg.getId()); 1305 channel2.setLightColor(Color.BLUE); 1306 NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH); 1307 channel3.enableVibration(true); 1308 1309 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 1310 UID_N_MR1, false); 1311 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 1312 UID_N_MR1, false); 1313 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 1314 UID_N_MR1, false); 1315 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, 1316 SYSTEM_UID, true); 1317 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, 1318 SYSTEM_UID, true); 1319 mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, 1320 UID_N_MR1, false); 1321 1322 mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true); 1323 mHelper.setInvalidMessageSent(PKG_P, UID_P); 1324 mHelper.setValidMessageSent(PKG_P, UID_P); 1325 mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true); 1326 1327 ByteArrayOutputStream baos = writeXmlAndPurge( 1328 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM); 1329 String expected = "<ranking version=\"4\">\n" 1330 // Importance 0 because off in permissionhelper 1331 + "<package name=\"com.example.o\" importance=\"0\" show_badge=\"true\" " 1332 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" " 1333 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble" 1334 + "=\"false\">\n" 1335 + "<channel id=\"id\" name=\"name\" importance=\"2\" " 1336 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1337 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" orig_imp=\"2\" />\n" 1338 + "</package>\n" 1339 // Importance 0 because missing from permission helper 1340 + "<package name=\"com.example.n_mr1\" importance=\"0\" show_badge=\"true\" " 1341 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"false\" " 1342 + "sent_valid_msg=\"false\" user_demote_msg_app=\"false\" sent_valid_bubble" 1343 + "=\"false\">\n" 1344 + "<channelGroup id=\"1\" name=\"bye\" blocked=\"false\" locked=\"0\" />\n" 1345 + "<channelGroup id=\"2\" name=\"hello\" blocked=\"false\" locked=\"0\" />\n" 1346 + "<channel id=\"id1\" name=\"name1\" importance=\"4\" show_badge=\"true\" " 1347 + "orig_imp=\"4\" />\n" 1348 + "<channel id=\"id2\" name=\"name2\" desc=\"descriptions for all\" " 1349 + "importance=\"2\" priority=\"2\" visibility=\"-1\" lights=\"true\" " 1350 + "light_color=\"-16776961\" show_badge=\"true\" group=\"1\" orig_imp=\"2\" />\n" 1351 + "<channel id=\"id3\" name=\"NAM3\" importance=\"4\" " 1352 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1353 + "content_type=\"4\" flags=\"0\" vibration_enabled=\"true\" show_badge=\"true\" " 1354 + "orig_imp=\"4\" />\n" 1355 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" " 1356 + "sound=\"content://settings/system/notification_sound\" usage=\"5\" " 1357 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" 1358 + "</package>\n" 1359 // Importance default because on in permission helper 1360 + "<package name=\"com.example.p\" importance=\"3\" show_badge=\"true\" " 1361 + "app_user_locked_fields=\"0\" sent_invalid_msg=\"true\" sent_valid_msg=\"true\"" 1362 + " user_demote_msg_app=\"true\" sent_valid_bubble=\"false\" />\n" 1363 + "</ranking>"; 1364 assertThat(baos.toString()).contains(expected); 1365 } 1366 1367 @Test testChannelXmlForBackup_postMigration_noLocalSettings()1368 public void testChannelXmlForBackup_postMigration_noLocalSettings() throws Exception { 1369 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 1370 appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); 1371 appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); 1372 appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false)); 1373 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); 1374 appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false)); 1375 1376 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 1377 .thenReturn(appPermissions); 1378 1379 ByteArrayOutputStream baos = writeXmlAndPurge( 1380 PKG_N_MR1, UID_N_MR1, true, USER_SYSTEM); 1381 String expected = "<ranking version=\"4\">\n" 1382 // Packages that exist solely in permissionhelper 1383 + "<package name=\"" + PKG_P + "\" importance=\"3\" />\n" 1384 + "<package name=\"" + PKG_O + "\" importance=\"0\" />\n" 1385 + "<package name=\"" + PKG_N_MR1 + "\" importance=\"3\" />\n" 1386 + "<package name=\"first\" importance=\"3\" />\n" 1387 + "<package name=\"third\" importance=\"0\" />\n" 1388 + "</ranking>"; 1389 assertThat(baos.toString()).contains(expected); 1390 } 1391 1392 @Test testBackupXml_backupCanonicalizedSoundUri()1393 public void testBackupXml_backupCanonicalizedSoundUri() throws Exception { 1394 NotificationChannel channel = 1395 new NotificationChannel("id", "name", IMPORTANCE_LOW); 1396 channel.setSound(SOUND_URI, mAudioAttributes); 1397 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 1398 UID_N_MR1, false); 1399 1400 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1401 USER_SYSTEM, channel.getId()); 1402 1403 // Testing that in restore we are given the canonical version 1404 loadStreamXml(baos, true, USER_SYSTEM); 1405 verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI)); 1406 } 1407 1408 @Test testRestoreXml_withExistentCanonicalizedSoundUri()1409 public void testRestoreXml_withExistentCanonicalizedSoundUri() throws Exception { 1410 Uri localUri = Uri.parse("content://" + TEST_AUTHORITY + "/local/url"); 1411 Uri canonicalBasedOnLocal = localUri.buildUpon() 1412 .appendQueryParameter("title", "Test") 1413 .appendQueryParameter("canonical", "1") 1414 .build(); 1415 doReturn(canonicalBasedOnLocal) 1416 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI)); 1417 doReturn(localUri) 1418 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI)); 1419 doReturn(localUri) 1420 .when(mTestIContentProvider).uncanonicalize(any(), eq(canonicalBasedOnLocal)); 1421 doReturn(canonicalBasedOnLocal) 1422 .when(mTestIContentProvider).canonicalize(any(), eq(localUri)); 1423 1424 NotificationChannel channel = 1425 new NotificationChannel("id", "name", IMPORTANCE_LOW); 1426 channel.setSound(SOUND_URI, mAudioAttributes); 1427 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 1428 UID_N_MR1, false); 1429 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1430 USER_SYSTEM, channel.getId()); 1431 1432 loadStreamXml(baos, true, USER_SYSTEM); 1433 1434 NotificationChannel actualChannel = mXmlHelper.getNotificationChannel( 1435 PKG_N_MR1, UID_N_MR1, channel.getId(), false); 1436 assertEquals(canonicalBasedOnLocal, actualChannel.getSound()); 1437 } 1438 1439 @Test testRestoreXml_withNonExistentCanonicalizedSoundUri()1440 public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception { 1441 Thread.sleep(3000); 1442 doReturn(null) 1443 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI)); 1444 doReturn(null) 1445 .when(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI)); 1446 1447 NotificationChannel channel = 1448 new NotificationChannel("id", "name", IMPORTANCE_LOW); 1449 channel.setSound(SOUND_URI, mAudioAttributes); 1450 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 1451 UID_N_MR1, false); 1452 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1453 USER_SYSTEM, channel.getId()); 1454 1455 loadStreamXml(baos, true, USER_SYSTEM); 1456 1457 NotificationChannel actualChannel = mXmlHelper.getNotificationChannel( 1458 PKG_N_MR1, UID_N_MR1, channel.getId(), false); 1459 assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound()); 1460 } 1461 1462 /** 1463 * Test sound Uri restore retry behavior when channel is restored before package 1464 * and then package is installed. 1465 */ 1466 @Test testRestoreXml_withNonExistentCanonicalizedSoundUriAndMissingPackage()1467 public void testRestoreXml_withNonExistentCanonicalizedSoundUriAndMissingPackage() 1468 throws Exception { 1469 // canonicalization returns CANONICAL_SOUND_URI for getSoundForBackup (backup part) 1470 doReturn(CANONICAL_SOUND_URI) 1471 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI)); 1472 1473 NotificationChannel channel = 1474 new NotificationChannel("id", "name", IMPORTANCE_LOW); 1475 channel.setSound(SOUND_URI, mAudioAttributes); 1476 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 1477 UID_N_MR1, false); 1478 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1479 USER_SYSTEM, channel.getId()); 1480 1481 // canonicalization / uncanonicalization returns null for the restore part 1482 doReturn(null) 1483 .when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI)); 1484 doReturn(null) 1485 .when(mTestIContentProvider).uncanonicalize(any(), any()); 1486 1487 // simulate package not installed 1488 when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UNKNOWN_UID); 1489 when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenThrow( 1490 new PackageManager.NameNotFoundException()); 1491 1492 loadStreamXml(baos, true, USER_SYSTEM); 1493 1494 // 1st restore pass fails 1495 NotificationChannel actualChannel = mXmlHelper.getNotificationChannel( 1496 PKG_N_MR1, UNKNOWN_UID, channel.getId(), false); 1497 // sound is CANONICAL_SOUND_URI, unchanged from backup 1498 assertEquals(CANONICAL_SOUND_URI, actualChannel.getSound()); 1499 // sound is flagged as not restored 1500 assertFalse(actualChannel.isSoundRestored()); 1501 1502 // package is "installed" 1503 when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UID_N_MR1); 1504 1505 // Trigger 2nd restore pass 1506 mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_N_MR1}, 1507 new int[]{UID_N_MR1}); 1508 1509 // sound is flagged as restored and set to default URI 1510 assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound()); 1511 assertTrue(actualChannel.isSoundRestored()); 1512 } 1513 1514 @Test 1515 @EnableFlags(Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA) testRestoreXml_delayedRestore()1516 public void testRestoreXml_delayedRestore() throws Exception { 1517 // simulate package not installed 1518 when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UNKNOWN_UID); 1519 when(mPm.getApplicationInfoAsUser(eq(PKG_R), anyInt(), anyInt())).thenThrow( 1520 new PackageManager.NameNotFoundException()); 1521 when(mClock.millis()).thenReturn(System.currentTimeMillis()); 1522 1523 String id = "id"; 1524 String xml = "<ranking version=\"1\">\n" 1525 + "<package name=\"" + PKG_R + "\" show_badge=\"true\">\n" 1526 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" " 1527 + "show_badge=\"true\" />\n" 1528 + "</package>\n" 1529 + "</ranking>\n"; 1530 1531 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 1532 1533 // settings are not available with real uid because pkg is not installed 1534 assertThat(mXmlHelper.getNotificationChannel(PKG_R, UID_P, id, false)).isNull(); 1535 // but the settings are in memory with unknown_uid 1536 assertThat(mXmlHelper.getNotificationChannel(PKG_R, UNKNOWN_UID, id, false)).isNotNull(); 1537 1538 // package is "installed" 1539 when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UID_P); 1540 1541 // Trigger 2nd restore pass 1542 mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_R}, 1543 new int[]{UID_P}); 1544 1545 NotificationChannel channel = mXmlHelper.getNotificationChannel(PKG_R, UID_P, id, 1546 false); 1547 assertThat(channel.getImportance()).isEqualTo(2); 1548 assertThat(channel.canShowBadge()).isTrue(); 1549 assertThat(channel.canBypassDnd()).isFalse(); 1550 1551 // removed from 'pending install' set 1552 assertThat(mXmlHelper.getNotificationChannel(PKG_R, UNKNOWN_UID, id,false)).isNull(); 1553 } 1554 1555 @Test 1556 @EnableFlags(Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA) testRestoreXml_delayedRestore_afterReboot()1557 public void testRestoreXml_delayedRestore_afterReboot() throws Exception { 1558 // load restore data 1559 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 1560 appPermissions.put(new Pair<>(UID_R, PKG_R), new Pair<>(true, false)); 1561 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 1562 .thenReturn(appPermissions); 1563 1564 // simulate package not installed 1565 when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UNKNOWN_UID); 1566 when(mPm.getApplicationInfoAsUser(eq(PKG_R), anyInt(), anyInt())).thenThrow( 1567 new PackageManager.NameNotFoundException()); 1568 when(mClock.millis()).thenReturn(System.currentTimeMillis()); 1569 1570 String id = "id"; 1571 String xml = "<ranking version=\"1\">\n" 1572 + "<package name=\"" + PKG_R + "\" show_badge=\"true\">\n" 1573 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" " 1574 + "show_badge=\"true\" />\n" 1575 + "</package>\n" 1576 + "</ranking>\n"; 1577 1578 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 1579 1580 // simulate write to disk 1581 TypedXmlSerializer serializer = Xml.newFastSerializer(); 1582 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1583 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 1584 serializer.startDocument(null, true); 1585 mXmlHelper.writeXml(serializer, false, USER_SYSTEM); 1586 serializer.endDocument(); 1587 serializer.flush(); 1588 1589 // simulate load after reboot 1590 mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 1591 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 1592 false, mClock); 1593 loadByteArrayXml(baos.toByteArray(), false, USER_ALL); 1594 1595 // Trigger 2nd restore pass 1596 when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UID_R); 1597 mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_R}, 1598 new int[]{UID_R}); 1599 1600 NotificationChannel channel = mXmlHelper.getNotificationChannel(PKG_R, UID_R, id, 1601 false); 1602 assertThat(channel.getImportance()).isEqualTo(2); 1603 assertThat(channel.canShowBadge()).isTrue(); 1604 assertThat(channel.canBypassDnd()).isFalse(); 1605 } 1606 1607 @Test 1608 @EnableFlags(Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA) testRestoreXml_delayedRestore_packageMissingAfterTwoDays()1609 public void testRestoreXml_delayedRestore_packageMissingAfterTwoDays() throws Exception { 1610 // load restore data 1611 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 1612 appPermissions.put(new Pair<>(UID_R, PKG_R), new Pair<>(true, false)); 1613 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 1614 .thenReturn(appPermissions); 1615 1616 // simulate package not installed 1617 when(mPm.getPackageUidAsUser(PKG_R, USER_SYSTEM)).thenReturn(UNKNOWN_UID); 1618 when(mPm.getApplicationInfoAsUser(eq(PKG_R), anyInt(), anyInt())).thenThrow( 1619 new PackageManager.NameNotFoundException()); 1620 1621 String id = "id"; 1622 String xml = "<ranking version=\"1\">\n" 1623 + "<package name=\"" + PKG_R + "\" show_badge=\"true\">\n" 1624 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" " 1625 + "show_badge=\"true\" />\n" 1626 + "</package>\n" 1627 + "</ranking>\n"; 1628 1629 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 1630 1631 // simulate write to disk 1632 TypedXmlSerializer serializer = Xml.newFastSerializer(); 1633 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 1634 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 1635 serializer.startDocument(null, true); 1636 mXmlHelper.writeXml(serializer, false, USER_SYSTEM); 1637 serializer.endDocument(); 1638 serializer.flush(); 1639 1640 // advance time by 2 days 1641 when(mClock.millis()).thenReturn( 1642 Duration.ofDays(2).toMillis() + System.currentTimeMillis()); 1643 1644 // simulate load after reboot 1645 mXmlHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper, 1646 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 1647 false, mClock); 1648 loadByteArrayXml(xml.getBytes(), false, USER_ALL); 1649 1650 // Trigger 2nd restore pass 1651 mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_R}, 1652 new int[]{UID_P}); 1653 1654 // verify the 2nd restore pass failed because the restore data had been removed 1655 assertThat(mXmlHelper.getNotificationChannel(PKG_R, UNKNOWN_UID, id, false)).isNull(); 1656 } 1657 1658 /** 1659 * Although we don't make backups with uncanonicalized uris anymore, we used to, so we have to 1660 * handle its restore properly. 1661 */ 1662 @Test testRestoreXml_withUncanonicalizedNonLocalSoundUri()1663 public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception { 1664 // Not a local uncanonicalized uri, simulating that it fails to exist locally 1665 doReturn(null) 1666 .when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI)); 1667 String id = "id"; 1668 String backupWithUncanonicalizedSoundUri = "<ranking version=\"1\">\n" 1669 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" 1670 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" " 1671 + "sound=\"" + SOUND_URI + "\" " 1672 + "usage=\"6\" content_type=\"0\" flags=\"1\" show_badge=\"true\" />\n" 1673 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" " 1674 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" 1675 + "</package>\n" 1676 + "</ranking>\n"; 1677 1678 loadByteArrayXml( 1679 backupWithUncanonicalizedSoundUri.getBytes(), true, USER_SYSTEM); 1680 1681 NotificationChannel actualChannel = 1682 mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false); 1683 1684 assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound()); 1685 assertTrue(actualChannel.isSoundRestored()); 1686 } 1687 1688 @Test testBackupRestoreXml_withNullSoundUri()1689 public void testBackupRestoreXml_withNullSoundUri() throws Exception { 1690 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 1691 appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false)); 1692 1693 when(mPermissionHelper.getNotificationPermissionValues(USER_SYSTEM)) 1694 .thenReturn(appPermissions); 1695 1696 NotificationChannel channel = 1697 new NotificationChannel("id", "name", IMPORTANCE_LOW); 1698 channel.setSound(null, mAudioAttributes); 1699 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 1700 UID_N_MR1, false); 1701 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1702 USER_SYSTEM, channel.getId()); 1703 1704 loadStreamXml(baos, true, USER_SYSTEM); 1705 1706 NotificationChannel actualChannel = mXmlHelper.getNotificationChannel( 1707 PKG_N_MR1, UID_N_MR1, channel.getId(), false); 1708 assertEquals(null, actualChannel.getSound()); 1709 } 1710 1711 @Test testBackupRestoreXml_withAndroidResourceSoundUri()1712 public void testBackupRestoreXml_withAndroidResourceSoundUri() throws Exception { 1713 // Mock ContentResolver.getResourceId: 1714 // throw exception on restore 1st pass => simulate app not installed yet 1715 // then return a valid resource on package update => sim. app installed 1716 ContentResolver contentResolver = mock(ContentResolver.class); 1717 when(mContext.getContentResolver()).thenReturn(contentResolver); 1718 ContentResolver.OpenResourceIdResult resId = mock( 1719 ContentResolver.OpenResourceIdResult.class); 1720 when(contentResolver.getResourceId(ANDROID_RES_SOUND_URI)).thenReturn(resId).thenThrow( 1721 new FileNotFoundException("")).thenReturn(resId); 1722 1723 mHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper, 1724 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 1725 false, mClock); 1726 mXmlHelper = new PreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper, 1727 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles, 1728 false, mClock); 1729 1730 NotificationChannel channel = 1731 new NotificationChannel("id", "name", IMPORTANCE_LOW); 1732 channel.setSound(ANDROID_RES_SOUND_URI, mAudioAttributes); 1733 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 1734 UID_N_MR1, false); 1735 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1736 USER_SYSTEM, channel.getId()); 1737 1738 // simulate package not installed 1739 when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UNKNOWN_UID); 1740 when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenThrow( 1741 new PackageManager.NameNotFoundException()); 1742 1743 loadStreamXml(baos, true, USER_SYSTEM); 1744 1745 NotificationChannel actualChannel = mXmlHelper.getNotificationChannel( 1746 PKG_N_MR1, UNKNOWN_UID, channel.getId(), false); 1747 // sound is ANDROID_RES_SOUND_URI, unchanged from backup 1748 assertEquals(ANDROID_RES_SOUND_URI, actualChannel.getSound()); 1749 // sound is flagged as not restored 1750 assertFalse(actualChannel.isSoundRestored()); 1751 1752 // package is "installed" 1753 when(mPm.getPackageUidAsUser(PKG_N_MR1, USER_SYSTEM)).thenReturn(UID_N_MR1); 1754 1755 // Trigger 2nd restore pass 1756 mXmlHelper.onPackagesChanged(false, USER_SYSTEM, new String[]{PKG_N_MR1}, 1757 new int[]{UID_N_MR1}); 1758 1759 // sound is flagged as restored 1760 assertEquals(ANDROID_RES_SOUND_URI, actualChannel.getSound()); 1761 assertTrue(actualChannel.isSoundRestored()); 1762 } 1763 1764 @Test testBackupRestoreXml_withFileResourceSoundUri()1765 public void testBackupRestoreXml_withFileResourceSoundUri() throws Exception { 1766 NotificationChannel channel = 1767 new NotificationChannel("id", "name", IMPORTANCE_LOW); 1768 channel.setSound(FILE_SOUND_URI, mAudioAttributes); 1769 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 1770 UID_N_MR1, false); 1771 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1772 USER_SYSTEM, channel.getId()); 1773 1774 loadStreamXml(baos, true, USER_SYSTEM); 1775 1776 NotificationChannel actualChannel = mXmlHelper.getNotificationChannel( 1777 PKG_N_MR1, UID_N_MR1, channel.getId(), false); 1778 // sound is FILE_SOUND_URI, unchanged from backup 1779 assertEquals(FILE_SOUND_URI, actualChannel.getSound()); 1780 // sound is flagged as restored 1781 assertTrue(actualChannel.isSoundRestored()); 1782 } 1783 1784 @Test testChannelXml_backup()1785 public void testChannelXml_backup() throws Exception { 1786 NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye"); 1787 NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello"); 1788 NotificationChannel channel1 = 1789 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 1790 NotificationChannel channel2 = 1791 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH); 1792 NotificationChannel channel3 = 1793 new NotificationChannel("id3", "name3", IMPORTANCE_LOW); 1794 channel3.setGroup(ncg.getId()); 1795 1796 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 1797 UID_N_MR1, false); 1798 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 1799 UID_N_MR1, false); 1800 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 1801 UID_N_MR1, false); 1802 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, 1803 SYSTEM_UID, true); 1804 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, 1805 UID_N_MR1, false); 1806 1807 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), 1808 UID_N_MR1, false); 1809 mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg.getId(), 1810 UID_N_MR1, false); 1811 assertEquals(channel2, 1812 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false)); 1813 1814 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, 1815 USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(), 1816 NotificationChannel.DEFAULT_CHANNEL_ID); 1817 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{ 1818 UID_N_MR1}); 1819 1820 TypedXmlPullParser parser = Xml.newFastPullParser(); 1821 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 1822 null); 1823 parser.nextTag(); 1824 mHelper.readXml(parser, true, USER_SYSTEM); 1825 1826 assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false)); 1827 assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false)); 1828 assertNull(mHelper.getNotificationChannelGroup(ncg.getId(), PKG_N_MR1, UID_N_MR1)); 1829 assertEquals(channel2, 1830 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false)); 1831 } 1832 1833 @Test testChannelXml_defaultChannelLegacyApp_noUserSettings()1834 public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception { 1835 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, 1836 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID); 1837 1838 loadStreamXml(baos, false, UserHandle.USER_ALL); 1839 1840 final NotificationChannel updated = mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, 1841 NotificationChannel.DEFAULT_CHANNEL_ID, false); 1842 assertEquals(NotificationManager.IMPORTANCE_UNSPECIFIED, updated.getImportance()); 1843 assertFalse(updated.canBypassDnd()); 1844 assertEquals(VISIBILITY_NO_OVERRIDE, updated.getLockscreenVisibility()); 1845 assertEquals(0, updated.getUserLockedFields()); 1846 } 1847 1848 @Test testChannelXml_defaultChannelUpdatedApp_userSettings()1849 public void testChannelXml_defaultChannelUpdatedApp_userSettings() throws Exception { 1850 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1, 1851 UID_N_MR1, 1852 NotificationChannel.DEFAULT_CHANNEL_ID, false); 1853 defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW); 1854 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true, 1855 UID_N_MR1, false); 1856 1857 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, 1858 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID); 1859 1860 loadStreamXml(baos, false, UserHandle.USER_ALL); 1861 1862 assertEquals(NotificationManager.IMPORTANCE_LOW, mXmlHelper.getNotificationChannel( 1863 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false) 1864 .getImportance()); 1865 } 1866 1867 @Test testChannelXml_upgradeCreateDefaultChannel()1868 public void testChannelXml_upgradeCreateDefaultChannel() throws Exception { 1869 final String preupgradeXml = "<ranking version=\"1\">\n" 1870 + "<package name=\"" + PKG_N_MR1 1871 + "\" importance=\"" + NotificationManager.IMPORTANCE_HIGH 1872 + "\" priority=\"" + Notification.PRIORITY_MAX + "\" visibility=\"" 1873 + VISIBILITY_SECRET + "\"" + " uid=\"" + UID_N_MR1 + "\" />\n" 1874 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" visibility=\"" 1875 + VISIBILITY_PRIVATE + "\" />\n" 1876 + "</ranking>"; 1877 TypedXmlPullParser parser = Xml.newFastPullParser(); 1878 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), 1879 null); 1880 parser.nextTag(); 1881 mHelper.readXml(parser, false, UserHandle.USER_ALL); 1882 1883 final NotificationChannel updated1 = 1884 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false); 1885 assertEquals(NotificationManager.IMPORTANCE_HIGH, updated1.getImportance()); 1886 assertTrue(updated1.canBypassDnd()); 1887 assertEquals(VISIBILITY_SECRET, updated1.getLockscreenVisibility()); 1888 assertEquals(NotificationChannel.USER_LOCKED_IMPORTANCE 1889 | USER_LOCKED_PRIORITY 1890 | USER_LOCKED_VISIBILITY, 1891 updated1.getUserLockedFields()); 1892 1893 // No Default Channel created for updated packages 1894 assertEquals(null, mHelper.getNotificationChannel(PKG_O, UID_O, 1895 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 1896 } 1897 1898 @Test testChannelXml_upgradeDeletesDefaultChannel()1899 public void testChannelXml_upgradeDeletesDefaultChannel() throws Exception { 1900 final NotificationChannel defaultChannel = mHelper.getNotificationChannel( 1901 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false); 1902 assertTrue(defaultChannel != null); 1903 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, 1904 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID); 1905 // Load package at higher sdk. 1906 final ApplicationInfo upgraded = new ApplicationInfo(); 1907 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 1908 when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded); 1909 loadStreamXml(baos, false, UserHandle.USER_ALL); 1910 1911 // Default Channel should be gone. 1912 assertEquals(null, mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, 1913 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 1914 } 1915 1916 @Test testDeletesDefaultChannelAfterChannelIsCreated()1917 public void testDeletesDefaultChannelAfterChannelIsCreated() throws Exception { 1918 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1919 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false, 1920 UID_N_MR1, false); 1921 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, 1922 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); 1923 1924 // Load package at higher sdk. 1925 final ApplicationInfo upgraded = new ApplicationInfo(); 1926 upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1; 1927 when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded); 1928 loadStreamXml(baos, false, UserHandle.USER_ALL); 1929 1930 // Default Channel should be gone. 1931 assertEquals(null, mXmlHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, 1932 NotificationChannel.DEFAULT_CHANNEL_ID, false)); 1933 } 1934 1935 @Test testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels()1936 public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception { 1937 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, 1938 UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas"); 1939 mXmlHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1940 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false, 1941 UID_N_MR1, false); 1942 1943 loadStreamXml(baos, false, UserHandle.USER_ALL); 1944 1945 // Should still have the newly created channel that wasn't in the xml. 1946 assertTrue(mXmlHelper.getNotificationChannel( 1947 PKG_N_MR1, UID_N_MR1, "bananas", false) != null); 1948 } 1949 1950 @Test testCreateChannel_badImportance()1951 public void testCreateChannel_badImportance() throws Exception { 1952 try { 1953 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1954 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), 1955 true, false, UID_N_MR1, false); 1956 fail("Was allowed to create a channel with invalid importance"); 1957 } catch (IllegalArgumentException e) { 1958 // yay 1959 } 1960 try { 1961 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1962 new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), 1963 true, false, UID_N_MR1, false); 1964 fail("Was allowed to create a channel with invalid importance"); 1965 } catch (IllegalArgumentException e) { 1966 // yay 1967 } 1968 try { 1969 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1970 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), 1971 true, false, UID_N_MR1, false); 1972 fail("Was allowed to create a channel with invalid importance"); 1973 } catch (IllegalArgumentException e) { 1974 // yay 1975 } 1976 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1977 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE), true, false, 1978 UID_N_MR1, false)); 1979 assertFalse(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1980 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false, 1981 UID_N_MR1, false)); 1982 } 1983 1984 @Test testUpdateChannel_downgradeImportance()1985 public void testUpdateChannel_downgradeImportance() { 1986 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1987 new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT), 1988 true, false, UID_N_MR1, false); 1989 1990 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1991 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false, 1992 UID_N_MR1, false)); 1993 } 1994 1995 @Test testUpdateChannel_upgradeImportance_ignored()1996 public void testUpdateChannel_upgradeImportance_ignored() { 1997 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 1998 new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT), 1999 true, false, UID_N_MR1, false); 2000 2001 assertFalse(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 2002 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX), true, false, 2003 UID_N_MR1, false)); 2004 } 2005 2006 @Test testUpdateChannel_badImportance()2007 public void testUpdateChannel_badImportance() { 2008 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 2009 new NotificationChannel("bananas", "bananas", IMPORTANCE_DEFAULT), 2010 true, false, UID_N_MR1, false); 2011 2012 assertThrows(IllegalArgumentException.class, 2013 () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 2014 new NotificationChannel("bananas", "bananas", IMPORTANCE_NONE - 1), true, 2015 false, UID_N_MR1, false)); 2016 2017 assertThrows(IllegalArgumentException.class, 2018 () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 2019 new NotificationChannel("bananas", "bananas", IMPORTANCE_UNSPECIFIED), true, 2020 false, UID_N_MR1, false)); 2021 2022 assertThrows(IllegalArgumentException.class, 2023 () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, 2024 new NotificationChannel("bananas", "bananas", IMPORTANCE_MAX + 1), true, 2025 false, UID_N_MR1, false)); 2026 } 2027 2028 @Test testUpdate()2029 public void testUpdate() throws Exception { 2030 // no fields locked by user 2031 final NotificationChannel channel = 2032 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2033 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 2034 channel.enableLights(true); 2035 channel.setBypassDnd(true); 2036 channel.setLockscreenVisibility(VISIBILITY_SECRET); 2037 2038 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false, 2039 SYSTEM_UID, true)); 2040 2041 // same id, try to update all fields 2042 final NotificationChannel channel2 = 2043 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 2044 channel2.setSound(new Uri.Builder().scheme("test2").build(), mAudioAttributes); 2045 channel2.enableLights(false); 2046 channel2.setBypassDnd(false); 2047 channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC); 2048 2049 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, 2050 SYSTEM_UID, true); 2051 2052 // all fields should be changed 2053 assertEquals(channel2, 2054 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false)); 2055 2056 verify(mHandler, times(1)).requestSort(); 2057 } 2058 2059 @Test testUpdate_preUpgrade_updatesAppFields()2060 public void testUpdate_preUpgrade_updatesAppFields() throws Exception { 2061 assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 2062 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1)); 2063 assertEquals(VISIBILITY_NO_OVERRIDE, 2064 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1)); 2065 2066 NotificationChannel defaultChannel = mHelper.getNotificationChannel( 2067 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false); 2068 2069 defaultChannel.setShowBadge(false); 2070 defaultChannel.setImportance(IMPORTANCE_NONE); 2071 defaultChannel.setBypassDnd(true); 2072 defaultChannel.setLockscreenVisibility(VISIBILITY_SECRET); 2073 2074 mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1); 2075 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true, 2076 SYSTEM_UID, true); 2077 2078 // ensure app level fields are changed 2079 assertFalse(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 2080 assertEquals(Notification.PRIORITY_MAX, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1)); 2081 assertEquals(VISIBILITY_SECRET, mHelper.getPackageVisibility(PKG_N_MR1, 2082 UID_N_MR1)); 2083 } 2084 2085 @Test testUpdate_postUpgrade_noUpdateAppFields()2086 public void testUpdate_postUpgrade_noUpdateAppFields() throws Exception { 2087 final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2088 2089 mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false, 2090 SYSTEM_UID, true); 2091 assertTrue(mHelper.canShowBadge(PKG_O, UID_O)); 2092 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O)); 2093 assertEquals(VISIBILITY_NO_OVERRIDE, 2094 mHelper.getPackageVisibility(PKG_O, UID_O)); 2095 2096 channel.setShowBadge(false); 2097 channel.setImportance(IMPORTANCE_NONE); 2098 channel.setBypassDnd(true); 2099 channel.setLockscreenVisibility(VISIBILITY_SECRET); 2100 2101 mHelper.updateNotificationChannel(PKG_O, UID_O, channel, true, 2102 SYSTEM_UID, true); 2103 2104 // ensure app level fields are not changed 2105 assertTrue(mHelper.canShowBadge(PKG_O, UID_O)); 2106 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_O, UID_O)); 2107 assertEquals(VISIBILITY_NO_OVERRIDE, 2108 mHelper.getPackageVisibility(PKG_O, UID_O)); 2109 } 2110 2111 @Test testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels()2112 public void testUpdate_preUpgrade_noUpdateAppFieldsWithMultipleChannels() throws Exception { 2113 final NotificationChannel channel = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2114 2115 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, false, false, 2116 SYSTEM_UID, true); 2117 assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 2118 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1)); 2119 assertEquals(VISIBILITY_NO_OVERRIDE, 2120 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1)); 2121 2122 channel.setShowBadge(false); 2123 channel.setImportance(IMPORTANCE_NONE); 2124 channel.setBypassDnd(true); 2125 channel.setLockscreenVisibility(VISIBILITY_SECRET); 2126 2127 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, 2128 SYSTEM_UID, true); 2129 2130 NotificationChannel defaultChannel = mHelper.getNotificationChannel( 2131 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false); 2132 2133 defaultChannel.setShowBadge(false); 2134 defaultChannel.setImportance(IMPORTANCE_NONE); 2135 defaultChannel.setBypassDnd(true); 2136 defaultChannel.setLockscreenVisibility(VISIBILITY_SECRET); 2137 2138 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true, 2139 SYSTEM_UID, true); 2140 2141 // ensure app level fields are not changed 2142 assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 2143 assertEquals(Notification.PRIORITY_DEFAULT, mHelper.getPackagePriority(PKG_N_MR1, UID_N_MR1)); 2144 assertEquals(VISIBILITY_NO_OVERRIDE, 2145 mHelper.getPackageVisibility(PKG_N_MR1, UID_N_MR1)); 2146 } 2147 2148 @Test testGetNotificationChannel_ReturnsNullForUnknownChannel()2149 public void testGetNotificationChannel_ReturnsNullForUnknownChannel() throws Exception { 2150 assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "garbage", false)); 2151 } 2152 2153 @Test testCreateChannel_CannotChangeHiddenFields()2154 public void testCreateChannel_CannotChangeHiddenFields() { 2155 final NotificationChannel channel = 2156 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH); 2157 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 2158 channel.enableLights(true); 2159 channel.setBypassDnd(true); 2160 channel.setLockscreenVisibility(VISIBILITY_SECRET); 2161 channel.setShowBadge(true); 2162 channel.setAllowBubbles(false); 2163 channel.setImportantConversation(true); 2164 int lockMask = 0; 2165 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 2166 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 2167 } 2168 channel.lockFields(lockMask); 2169 2170 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2171 UID_N_MR1, false)); 2172 2173 NotificationChannel savedChannel = 2174 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false); 2175 2176 assertEquals(channel.getName(), savedChannel.getName()); 2177 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 2178 assertFalse(savedChannel.canBypassDnd()); 2179 assertFalse(VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 2180 assertFalse(channel.isImportantConversation()); 2181 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 2182 assertEquals(channel.canBubble(), savedChannel.canBubble()); 2183 2184 verify(mHandler, never()).requestSort(); 2185 } 2186 2187 @Test testCreateChannel_CannotChangeHiddenFieldsAssistant()2188 public void testCreateChannel_CannotChangeHiddenFieldsAssistant() { 2189 final NotificationChannel channel = 2190 new NotificationChannel("id2", "name2", IMPORTANCE_HIGH); 2191 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 2192 channel.enableLights(true); 2193 channel.setBypassDnd(true); 2194 channel.setLockscreenVisibility(VISIBILITY_SECRET); 2195 channel.setShowBadge(true); 2196 channel.setAllowBubbles(false); 2197 int lockMask = 0; 2198 for (int i = 0; i < NotificationChannel.LOCKABLE_FIELDS.length; i++) { 2199 lockMask |= NotificationChannel.LOCKABLE_FIELDS[i]; 2200 } 2201 channel.lockFields(lockMask); 2202 2203 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2204 UID_N_MR1, false); 2205 2206 NotificationChannel savedChannel = 2207 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false); 2208 2209 assertEquals(channel.getName(), savedChannel.getName()); 2210 assertEquals(channel.shouldShowLights(), savedChannel.shouldShowLights()); 2211 assertFalse(savedChannel.canBypassDnd()); 2212 assertFalse(VISIBILITY_SECRET == savedChannel.getLockscreenVisibility()); 2213 assertEquals(channel.canShowBadge(), savedChannel.canShowBadge()); 2214 assertEquals(channel.canBubble(), savedChannel.canBubble()); 2215 } 2216 2217 @Test testClearLockedFields()2218 public void testClearLockedFields() { 2219 final NotificationChannel channel = getChannel(); 2220 mHelper.clearLockedFieldsLocked(channel); 2221 assertEquals(0, channel.getUserLockedFields()); 2222 2223 channel.lockFields(USER_LOCKED_PRIORITY 2224 | NotificationChannel.USER_LOCKED_IMPORTANCE); 2225 mHelper.clearLockedFieldsLocked(channel); 2226 assertEquals(0, channel.getUserLockedFields()); 2227 } 2228 2229 @Test testLockFields_soundAndVibration()2230 public void testLockFields_soundAndVibration() { 2231 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, 2232 UID_N_MR1, false); 2233 2234 final NotificationChannel update1 = getChannel(); 2235 update1.setSound(new Uri.Builder().scheme("test").build(), 2236 new AudioAttributes.Builder().build()); 2237 update1.lockFields(USER_LOCKED_PRIORITY); 2238 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); 2239 assertEquals(USER_LOCKED_PRIORITY 2240 | USER_LOCKED_SOUND, 2241 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) 2242 .getUserLockedFields()); 2243 2244 NotificationChannel update2 = getChannel(); 2245 update2.enableVibration(true); 2246 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true); 2247 assertEquals(USER_LOCKED_PRIORITY 2248 | USER_LOCKED_SOUND 2249 | USER_LOCKED_VIBRATION, 2250 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false) 2251 .getUserLockedFields()); 2252 } 2253 2254 @Test testLockFields_vibrationAndLights()2255 public void testLockFields_vibrationAndLights() { 2256 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, 2257 SYSTEM_UID, true); 2258 2259 final NotificationChannel update1 = getChannel(); 2260 update1.setVibrationPattern(new long[]{7945, 46 ,246}); 2261 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); 2262 assertEquals(USER_LOCKED_VIBRATION, 2263 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) 2264 .getUserLockedFields()); 2265 2266 final NotificationChannel update2 = getChannel(); 2267 update2.enableLights(true); 2268 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true); 2269 assertEquals(USER_LOCKED_VIBRATION 2270 | USER_LOCKED_LIGHTS, 2271 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false) 2272 .getUserLockedFields()); 2273 } 2274 2275 @Test testLockFields_lightsAndImportance()2276 public void testLockFields_lightsAndImportance() { 2277 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, 2278 UID_N_MR1, false); 2279 2280 final NotificationChannel update1 = getChannel(); 2281 update1.setLightColor(Color.GREEN); 2282 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); 2283 assertEquals(USER_LOCKED_LIGHTS, 2284 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) 2285 .getUserLockedFields()); 2286 2287 final NotificationChannel update2 = getChannel(); 2288 update2.setImportance(IMPORTANCE_DEFAULT); 2289 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, 2290 SYSTEM_UID, true); 2291 assertEquals(USER_LOCKED_LIGHTS 2292 | NotificationChannel.USER_LOCKED_IMPORTANCE, 2293 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false) 2294 .getUserLockedFields()); 2295 } 2296 2297 @Test testLockFields_visibilityAndDndAndBadge()2298 public void testLockFields_visibilityAndDndAndBadge() { 2299 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, 2300 UID_N_MR1, false); 2301 assertEquals(0, 2302 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false) 2303 .getUserLockedFields()); 2304 2305 final NotificationChannel update1 = getChannel(); 2306 update1.setBypassDnd(true); 2307 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update1, true, SYSTEM_UID, true); 2308 assertEquals(USER_LOCKED_PRIORITY, 2309 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update1.getId(), false) 2310 .getUserLockedFields()); 2311 2312 final NotificationChannel update2 = getChannel(); 2313 update2.setLockscreenVisibility(VISIBILITY_SECRET); 2314 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update2, true, SYSTEM_UID, true); 2315 assertEquals(USER_LOCKED_PRIORITY 2316 | USER_LOCKED_VISIBILITY, 2317 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update2.getId(), false) 2318 .getUserLockedFields()); 2319 2320 final NotificationChannel update3 = getChannel(); 2321 update3.setShowBadge(false); 2322 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update3, true, SYSTEM_UID, true); 2323 assertEquals(USER_LOCKED_PRIORITY 2324 | USER_LOCKED_VISIBILITY 2325 | USER_LOCKED_SHOW_BADGE, 2326 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update3.getId(), false) 2327 .getUserLockedFields()); 2328 } 2329 2330 @Test testLockFields_allowBubble()2331 public void testLockFields_allowBubble() { 2332 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, 2333 UID_N_MR1, false); 2334 assertEquals(0, 2335 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel().getId(), false) 2336 .getUserLockedFields()); 2337 2338 final NotificationChannel update = getChannel(); 2339 update.setAllowBubbles(true); 2340 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, 2341 SYSTEM_UID, true); 2342 assertEquals(USER_LOCKED_ALLOW_BUBBLE, 2343 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, update.getId(), false) 2344 .getUserLockedFields()); 2345 } 2346 2347 @Test testDeleteNonExistentChannel()2348 public void testDeleteNonExistentChannel() throws Exception { 2349 mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, "does not exist", 2350 UID_N_MR1, false); 2351 } 2352 2353 @Test testDoubleDeleteChannel()2354 public void testDoubleDeleteChannel() throws Exception { 2355 NotificationChannel channel = getChannel(); 2356 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2357 UID_N_MR1, false); 2358 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), 2359 UID_N_MR1, false); 2360 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), 2361 UID_N_MR1, false); 2362 assertEquals(2, mLogger.getCalls().size()); 2363 assertEquals( 2364 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED, 2365 mLogger.get(0).event); 2366 assertEquals( 2367 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_DELETED, 2368 mLogger.get(1).event); 2369 // No log for the second delete of the same channel. 2370 } 2371 2372 @Test testGetDeletedChannel()2373 public void testGetDeletedChannel() throws Exception { 2374 NotificationChannel channel = getChannel(); 2375 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 2376 channel.enableLights(true); 2377 channel.setBypassDnd(true); 2378 channel.setLockscreenVisibility(VISIBILITY_SECRET); 2379 channel.enableVibration(true); 2380 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 2381 2382 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2383 UID_N_MR1, false); 2384 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), 2385 UID_N_MR1, false); 2386 2387 // Does not return deleted channel 2388 NotificationChannel response = 2389 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), false); 2390 assertNull(response); 2391 2392 // Returns deleted channel 2393 response = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true); 2394 compareChannels(channel, response); 2395 assertTrue(response.isDeleted()); 2396 } 2397 2398 @Test testGetDeletedChannels()2399 public void testGetDeletedChannels() throws Exception { 2400 Map<String, NotificationChannel> channelMap = new HashMap<>(); 2401 NotificationChannel channel = 2402 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2403 channel.setSound(new Uri.Builder().scheme("test").build(), mAudioAttributes); 2404 channel.enableLights(true); 2405 channel.setBypassDnd(true); 2406 channel.setLockscreenVisibility(VISIBILITY_PRIVATE); 2407 channel.enableVibration(true); 2408 channel.setVibrationPattern(new long[]{100, 67, 145, 156}); 2409 channelMap.put(channel.getId(), channel); 2410 NotificationChannel channel2 = 2411 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 2412 channelMap.put(channel2.getId(), channel2); 2413 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2414 UID_N_MR1, false); 2415 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, 2416 UID_N_MR1, false); 2417 2418 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), 2419 UID_N_MR1, false); 2420 2421 // Returns only non-deleted channels 2422 List<NotificationChannel> channels = 2423 mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList(); 2424 assertEquals(2, channels.size()); // Default channel + non-deleted channel 2425 for (NotificationChannel nc : channels) { 2426 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 2427 compareChannels(channel2, nc); 2428 } 2429 } 2430 2431 // Returns deleted channels too 2432 channels = mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList(); 2433 assertEquals(3, channels.size()); // Includes default channel 2434 for (NotificationChannel nc : channels) { 2435 if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(nc.getId())) { 2436 compareChannels(channelMap.get(nc.getId()), nc); 2437 } 2438 } 2439 } 2440 2441 @Test testGetDeletedChannelCount()2442 public void testGetDeletedChannelCount() throws Exception { 2443 NotificationChannel channel = 2444 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2445 NotificationChannel channel2 = 2446 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_HIGH); 2447 NotificationChannel channel3 = 2448 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_HIGH); 2449 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2450 UID_N_MR1, false); 2451 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, 2452 UID_N_MR1, false); 2453 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, 2454 UID_N_MR1, false); 2455 2456 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), 2457 UID_N_MR1, false); 2458 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), 2459 UID_N_MR1, false); 2460 2461 assertEquals(2, mHelper.getDeletedChannelCount(PKG_N_MR1, UID_N_MR1)); 2462 assertEquals(0, mHelper.getDeletedChannelCount("pkg2", UID_O)); 2463 } 2464 2465 @Test testGetBlockedChannelCount()2466 public void testGetBlockedChannelCount() throws Exception { 2467 NotificationChannel channel = 2468 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2469 NotificationChannel channel2 = 2470 new NotificationChannel("id4", "a", NotificationManager.IMPORTANCE_NONE); 2471 NotificationChannel channel3 = 2472 new NotificationChannel("id5", "a", NotificationManager.IMPORTANCE_NONE); 2473 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2474 UID_N_MR1, false); 2475 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, 2476 UID_N_MR1, false); 2477 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, 2478 UID_N_MR1, false); 2479 2480 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), 2481 UID_N_MR1, false); 2482 2483 assertEquals(1, mHelper.getBlockedChannelCount(PKG_N_MR1, UID_N_MR1)); 2484 assertEquals(0, mHelper.getBlockedChannelCount("pkg2", UID_O)); 2485 } 2486 2487 @Test testGetChannelsBypassingDndCount_noChannelsBypassing()2488 public void testGetChannelsBypassingDndCount_noChannelsBypassing() throws Exception { 2489 assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, 2490 UID_N_MR1).getList().size()); 2491 } 2492 2493 @Test testGetChannelsBypassingDnd_noChannelsForUidBypassing()2494 public void testGetChannelsBypassingDnd_noChannelsForUidBypassing() 2495 throws Exception { 2496 int uid = 222; 2497 NotificationChannel channel = new NotificationChannel("id", "name", 2498 NotificationManager.IMPORTANCE_MAX); 2499 channel.setBypassDnd(true); 2500 mHelper.createNotificationChannel(PKG_N_MR1, 111, channel, true, true, 2501 111, false); 2502 2503 assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, 2504 uid).getList().size()); 2505 } 2506 2507 @Test testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked()2508 public void testGetChannelsBypassingDndCount_oneChannelBypassing_groupBlocked() { 2509 int uid = UID_N_MR1; 2510 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 2511 NotificationChannel channel1 = new NotificationChannel("id1", "name1", 2512 NotificationManager.IMPORTANCE_MAX); 2513 channel1.setBypassDnd(true); 2514 channel1.setGroup(ncg.getId()); 2515 mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ true, 2516 uid, false); 2517 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true, 2518 uid, false); 2519 2520 assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, 2521 uid).getList().size()); 2522 2523 // disable group 2524 ncg.setBlocked(true); 2525 mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, ncg, /* fromTargetApp */ false, 2526 SYSTEM_UID, true); 2527 assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, 2528 uid).getList().size()); 2529 } 2530 2531 @Test testGetChannelsBypassingDndCount_multipleChannelsBypassing()2532 public void testGetChannelsBypassingDndCount_multipleChannelsBypassing() { 2533 int uid = UID_N_MR1; 2534 NotificationChannel channel1 = new NotificationChannel("id1", "name1", 2535 NotificationManager.IMPORTANCE_MAX); 2536 NotificationChannel channel2 = new NotificationChannel("id2", "name2", 2537 NotificationManager.IMPORTANCE_MAX); 2538 NotificationChannel channel3 = new NotificationChannel("id3", "name3", 2539 NotificationManager.IMPORTANCE_MAX); 2540 channel1.setBypassDnd(true); 2541 channel2.setBypassDnd(true); 2542 channel3.setBypassDnd(true); 2543 // has DND access, so can set bypassDnd attribute 2544 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel1, true, /*has DND access*/ true, 2545 uid, false); 2546 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, 2547 uid, false); 2548 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel3, true, true, 2549 uid, false); 2550 assertEquals(3, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, 2551 uid).getList().size()); 2552 2553 // setBypassDnd false for some channels 2554 channel1.setBypassDnd(false); 2555 channel2.setBypassDnd(false); 2556 assertEquals(1, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, 2557 uid).getList().size()); 2558 2559 // setBypassDnd false for rest of the channels 2560 channel3.setBypassDnd(false); 2561 assertEquals(0, mHelper.getNotificationChannelsBypassingDnd(PKG_N_MR1, 2562 uid).getList().size()); 2563 } 2564 2565 @Test testCreateAndDeleteCanChannelsBypassDnd_localSettings()2566 public void testCreateAndDeleteCanChannelsBypassDnd_localSettings() { 2567 int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; 2568 when(mPermissionHelper.hasPermission(uid)).thenReturn(true); 2569 2570 // create notification channel that can't bypass dnd 2571 // expected result: areChannelsBypassingDnd = false 2572 // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false 2573 NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); 2574 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, 2575 uid, false); 2576 assertFalse(mHelper.areChannelsBypassingDnd()); 2577 verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt()); 2578 resetZenModeHelper(); 2579 2580 // create notification channel that can bypass dnd 2581 // expected result: areChannelsBypassingDnd = true 2582 NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2583 channel2.setBypassDnd(true); 2584 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, 2585 uid, false); 2586 assertTrue(mHelper.areChannelsBypassingDnd()); 2587 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2588 resetZenModeHelper(); 2589 2590 // delete channels 2591 mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false); 2592 assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND 2593 verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt()); 2594 resetZenModeHelper(); 2595 2596 mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false); 2597 assertFalse(mHelper.areChannelsBypassingDnd()); 2598 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2599 resetZenModeHelper(); 2600 } 2601 2602 @Test testCreateAndUpdateChannelsBypassingDnd_permissionHelper()2603 public void testCreateAndUpdateChannelsBypassingDnd_permissionHelper() { 2604 int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; 2605 when(mPermissionHelper.hasPermission(uid)).thenReturn(true); 2606 2607 // create notification channel that can't bypass dnd 2608 // expected result: areChannelsBypassingDnd = false 2609 // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false 2610 NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); 2611 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, 2612 uid, false); 2613 assertFalse(mHelper.areChannelsBypassingDnd()); 2614 verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt()); 2615 resetZenModeHelper(); 2616 2617 // Recreate a channel & now the app has dnd access granted and can set the bypass dnd field 2618 NotificationChannel update = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); 2619 update.setBypassDnd(true); 2620 mHelper.createNotificationChannel(PKG_N_MR1, uid, update, true, true, 2621 uid, false); 2622 2623 assertTrue(mHelper.areChannelsBypassingDnd()); 2624 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2625 resetZenModeHelper(); 2626 } 2627 2628 @Test testCreateAndDeleteCanChannelsBypassDnd_permissionHelper()2629 public void testCreateAndDeleteCanChannelsBypassDnd_permissionHelper() { 2630 int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; 2631 when(mPermissionHelper.hasPermission(uid)).thenReturn(true); 2632 2633 // create notification channel that can't bypass dnd 2634 // expected result: areChannelsBypassingDnd = false 2635 // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false 2636 NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); 2637 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, 2638 uid, false); 2639 assertFalse(mHelper.areChannelsBypassingDnd()); 2640 verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt()); 2641 resetZenModeHelper(); 2642 2643 // create notification channel that can bypass dnd, using local app level settings 2644 // expected result: areChannelsBypassingDnd = true 2645 NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2646 channel2.setBypassDnd(true); 2647 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, 2648 uid, false); 2649 assertTrue(mHelper.areChannelsBypassingDnd()); 2650 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2651 resetZenModeHelper(); 2652 2653 // delete channels 2654 mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel.getId(), uid, false); 2655 assertTrue(mHelper.areChannelsBypassingDnd()); // channel2 can still bypass DND 2656 verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt()); 2657 resetZenModeHelper(); 2658 2659 mHelper.deleteNotificationChannel(PKG_N_MR1, uid, channel2.getId(), uid, false); 2660 assertFalse(mHelper.areChannelsBypassingDnd()); 2661 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2662 resetZenModeHelper(); 2663 } 2664 2665 @Test testBlockedGroupDoesNotBypassDnd()2666 public void testBlockedGroupDoesNotBypassDnd() { 2667 int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; 2668 when(mPermissionHelper.hasPermission(uid)).thenReturn(true); 2669 2670 // start in a 'allowed to bypass dnd state' 2671 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 2672 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); 2673 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 2674 mHelper.syncChannelsBypassingDnd(); 2675 2676 // create notification channel that can bypass dnd, but app is blocked 2677 // expected result: areChannelsBypassingDnd = false 2678 NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); 2679 group.setBlocked(true); 2680 mHelper.createNotificationChannelGroup(PKG_N_MR1, uid, group, false, 2681 SYSTEM_UID, true); 2682 NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2683 channel2.setGroup("group"); 2684 channel2.setBypassDnd(true); 2685 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, 2686 uid, false); 2687 assertFalse(mHelper.areChannelsBypassingDnd()); 2688 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2689 resetZenModeHelper(); 2690 } 2691 2692 @Test testBlockedAppsDoNotBypassDnd_localSettings()2693 public void testBlockedAppsDoNotBypassDnd_localSettings() { 2694 int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; 2695 when(mPermissionHelper.hasPermission(uid)).thenReturn(false); 2696 2697 // start in a 'allowed to bypass dnd state' 2698 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 2699 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); 2700 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 2701 mHelper.syncChannelsBypassingDnd(); 2702 2703 // create notification channel that can bypass dnd, but app is blocked 2704 // expected result: areChannelsBypassingDnd = false 2705 NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2706 channel2.setBypassDnd(true); 2707 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, 2708 uid, false); 2709 assertFalse(mHelper.areChannelsBypassingDnd()); 2710 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2711 resetZenModeHelper(); 2712 } 2713 2714 @Test testBlockedAppsDoNotBypassDnd_permissionHelper()2715 public void testBlockedAppsDoNotBypassDnd_permissionHelper() { 2716 int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; 2717 when(mPermissionHelper.hasPermission(uid)).thenReturn(false); 2718 2719 // start in a 'allowed to bypass dnd state' 2720 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 2721 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); 2722 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 2723 mHelper.syncChannelsBypassingDnd(); 2724 2725 // create notification channel that can bypass dnd, but app is blocked 2726 // expected result: areChannelsBypassingDnd = false 2727 NotificationChannel channel2 = new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2728 channel2.setBypassDnd(true); 2729 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel2, true, true, 2730 uid, false); 2731 assertFalse(mHelper.areChannelsBypassingDnd()); 2732 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2733 resetZenModeHelper(); 2734 } 2735 2736 @Test testUpdateCanChannelsBypassDnd()2737 public void testUpdateCanChannelsBypassDnd() { 2738 int uid = UserManager.isHeadlessSystemUserMode() ? UID_HEADLESS : UID_N_MR1; 2739 when(mPermissionHelper.hasPermission(uid)).thenReturn(true); 2740 2741 // create notification channel that can't bypass dnd 2742 // expected result: areChannelsBypassingDnd = false 2743 // setNotificationPolicy isn't called since areChannelsBypassingDnd was already false 2744 NotificationChannel channel = new NotificationChannel("id1", "name1", IMPORTANCE_LOW); 2745 mHelper.createNotificationChannel(PKG_N_MR1, uid, channel, true, false, 2746 uid, false); 2747 assertFalse(mHelper.areChannelsBypassingDnd()); 2748 verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt()); 2749 resetZenModeHelper(); 2750 2751 // update channel so it CAN bypass dnd: 2752 // expected result: areChannelsBypassingDnd = true 2753 channel.setBypassDnd(true); 2754 mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true); 2755 assertTrue(mHelper.areChannelsBypassingDnd()); 2756 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2757 resetZenModeHelper(); 2758 2759 // update channel so it can't bypass dnd: 2760 // expected result: areChannelsBypassingDnd = false 2761 channel.setBypassDnd(false); 2762 mHelper.updateNotificationChannel(PKG_N_MR1, uid, channel, true, SYSTEM_UID, true); 2763 assertFalse(mHelper.areChannelsBypassingDnd()); 2764 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2765 resetZenModeHelper(); 2766 } 2767 2768 @Test testSetupNewZenModeHelper_canBypass()2769 public void testSetupNewZenModeHelper_canBypass() { 2770 // start notification policy off with mAreChannelsBypassingDnd = true, but 2771 // RankingHelper should change to false 2772 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 2773 NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND, 0); 2774 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 2775 mHelper.syncChannelsBypassingDnd(); 2776 assertFalse(mHelper.areChannelsBypassingDnd()); 2777 verify(mMockZenModeHelper, times(1)).setNotificationPolicy(any(), anyInt(), anyInt()); 2778 resetZenModeHelper(); 2779 } 2780 2781 @Test testSetupNewZenModeHelper_cannotBypass()2782 public void testSetupNewZenModeHelper_cannotBypass() { 2783 // start notification policy off with mAreChannelsBypassingDnd = false 2784 mTestNotificationPolicy = new NotificationManager.Policy(0, 0, 0, 0, 0, 0); 2785 when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy); 2786 assertFalse(mHelper.areChannelsBypassingDnd()); 2787 verify(mMockZenModeHelper, never()).setNotificationPolicy(any(), anyInt(), anyInt()); 2788 resetZenModeHelper(); 2789 } 2790 2791 @Test syncChannelsBypassingDnd_includesProfilesOfCurrentUser()2792 public void syncChannelsBypassingDnd_includesProfilesOfCurrentUser() throws Exception { 2793 when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0, 10})); 2794 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true); 2795 ApplicationInfo appInfo = new ApplicationInfo(); 2796 appInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE; 2797 when(mPm.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn(appInfo); 2798 2799 NotificationChannel withBypass = new NotificationChannel("1", "with", IMPORTANCE_DEFAULT); 2800 withBypass.setBypassDnd(true); 2801 NotificationChannel withoutBypass = new NotificationChannel("2", "without", 2802 IMPORTANCE_DEFAULT); 2803 withoutBypass.setBypassDnd(false); 2804 mHelper.createNotificationChannel("com.example", UserHandle.getUid(0, 444), withoutBypass, 2805 false, false, Process.SYSTEM_UID, true); 2806 mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass, 2807 false, false, Process.SYSTEM_UID, true); 2808 2809 mHelper.syncChannelsBypassingDnd(); 2810 2811 assertThat(mHelper.areChannelsBypassingDnd()).isTrue(); 2812 } 2813 2814 @Test syncChannelsBypassingDnd_excludesOtherUsers()2815 public void syncChannelsBypassingDnd_excludesOtherUsers() throws Exception { 2816 when(mUserProfiles.getCurrentProfileIds()).thenReturn(IntArray.wrap(new int[] {0})); 2817 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(true); 2818 ApplicationInfo appInfo = new ApplicationInfo(); 2819 appInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE; 2820 when(mPm.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn(appInfo); 2821 2822 NotificationChannel withBypass = new NotificationChannel("1", "with", IMPORTANCE_DEFAULT); 2823 withBypass.setBypassDnd(true); 2824 NotificationChannel withoutBypass = new NotificationChannel("2", "without", 2825 IMPORTANCE_DEFAULT); 2826 withoutBypass.setBypassDnd(false); 2827 mHelper.createNotificationChannel("com.example", UserHandle.getUid(0, 444), withoutBypass, 2828 false, false, Process.SYSTEM_UID, true); 2829 mHelper.createNotificationChannel("com.example", UserHandle.getUid(10, 444), withBypass, 2830 false, false, Process.SYSTEM_UID, true); 2831 2832 mHelper.syncChannelsBypassingDnd(); 2833 2834 assertThat(mHelper.areChannelsBypassingDnd()).isFalse(); 2835 } 2836 2837 @Test testOnlyHasDefaultChannel()2838 public void testOnlyHasDefaultChannel() throws Exception { 2839 assertTrue(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1)); 2840 assertFalse(mHelper.onlyHasDefaultChannel(PKG_O, UID_O)); 2841 2842 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, getChannel(), true, false, 2843 UID_N_MR1, false); 2844 assertFalse(mHelper.onlyHasDefaultChannel(PKG_N_MR1, UID_N_MR1)); 2845 } 2846 2847 @Test testCreateDeletedChannel()2848 public void testCreateDeletedChannel() throws Exception { 2849 long[] vibration = new long[]{100, 67, 145, 156}; 2850 NotificationChannel channel = 2851 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2852 channel.setVibrationPattern(vibration); 2853 2854 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2855 UID_N_MR1, false); 2856 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), 2857 UID_N_MR1, false); 2858 2859 NotificationChannel newChannel = new NotificationChannel( 2860 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 2861 newChannel.setVibrationPattern(new long[]{100}); 2862 2863 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel, true, false, 2864 UID_N_MR1, false); 2865 2866 // No long deleted, using old settings 2867 compareChannels(channel, 2868 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false)); 2869 } 2870 2871 @Test testCreateChannel_defaultChannelId()2872 public void testCreateChannel_defaultChannelId() throws Exception { 2873 try { 2874 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, new NotificationChannel( 2875 NotificationChannel.DEFAULT_CHANNEL_ID, "ha", IMPORTANCE_HIGH), true, false, 2876 UID_N_MR1, false); 2877 fail("Allowed to create default channel"); 2878 } catch (IllegalArgumentException e) { 2879 // pass 2880 } 2881 } 2882 2883 @Test testCreateChannel_alreadyExists()2884 public void testCreateChannel_alreadyExists() throws Exception { 2885 long[] vibration = new long[]{100, 67, 145, 156}; 2886 NotificationChannel channel = 2887 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2888 channel.setVibrationPattern(vibration); 2889 2890 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2891 UID_N_MR1, false)); 2892 2893 NotificationChannel newChannel = new NotificationChannel( 2894 channel.getId(), channel.getName(), NotificationManager.IMPORTANCE_HIGH); 2895 newChannel.setVibrationPattern(new long[]{100}); 2896 newChannel.setAllowBubbles(!channel.canBubble()); 2897 newChannel.setLightColor(Color.BLUE); 2898 newChannel.setSound(Uri.EMPTY, null); 2899 newChannel.setShowBadge(!channel.canShowBadge()); 2900 2901 assertFalse(mHelper.createNotificationChannel( 2902 PKG_N_MR1, UID_N_MR1, newChannel, true, false, 2903 UID_N_MR1, false)); 2904 2905 // Old settings not overridden 2906 compareChannels(channel, 2907 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, newChannel.getId(), false)); 2908 2909 assertEquals(1, mLogger.getCalls().size()); 2910 assertEquals( 2911 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED, 2912 mLogger.get(0).event); 2913 } 2914 2915 @Test testCreateChannel_noOverrideSound()2916 public void testCreateChannel_noOverrideSound() throws Exception { 2917 Uri sound = new Uri.Builder().scheme("test").build(); 2918 final NotificationChannel channel = new NotificationChannel("id2", "name2", 2919 NotificationManager.IMPORTANCE_DEFAULT); 2920 channel.setSound(sound, mAudioAttributes); 2921 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 2922 UID_N_MR1, false); 2923 assertEquals(sound, mHelper.getNotificationChannel( 2924 PKG_N_MR1, UID_N_MR1, channel.getId(), false).getSound()); 2925 } 2926 2927 @Test testPermanentlyDeleteChannels()2928 public void testPermanentlyDeleteChannels() throws Exception { 2929 NotificationChannel channel1 = 2930 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 2931 NotificationChannel channel2 = 2932 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 2933 2934 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 2935 UID_N_MR1, false); 2936 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, false, false, 2937 UID_N_MR1, false); 2938 2939 mHelper.permanentlyDeleteNotificationChannels(PKG_N_MR1, UID_N_MR1); 2940 2941 // Only default channel remains 2942 assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, true).getList().size()); 2943 } 2944 2945 @Test testDeleteGroup()2946 public void testDeleteGroup() throws Exception { 2947 NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted"); 2948 NotificationChannelGroup deleted = new NotificationChannelGroup("totally", "deleted"); 2949 NotificationChannel nonGroupedNonDeletedChannel = 2950 new NotificationChannel("no group", "so not deleted", IMPORTANCE_HIGH); 2951 NotificationChannel groupedButNotDeleted = 2952 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT); 2953 groupedButNotDeleted.setGroup("not"); 2954 NotificationChannel groupedAndDeleted = 2955 new NotificationChannel("deleted", "belongs to deleted", IMPORTANCE_DEFAULT); 2956 groupedAndDeleted.setGroup("totally"); 2957 2958 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true, 2959 UID_N_MR1, false); 2960 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted, true, 2961 UID_N_MR1, false); 2962 mHelper.createNotificationChannel( 2963 PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel, true, false, 2964 UID_N_MR1, false); 2965 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedAndDeleted, true, false, 2966 UID_N_MR1, false); 2967 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, groupedButNotDeleted, true, false, 2968 UID_N_MR1, false); 2969 2970 mHelper.deleteNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, deleted.getId(), 2971 UID_N_MR1, false); 2972 2973 assertNull(mHelper.getNotificationChannelGroup(deleted.getId(), PKG_N_MR1, UID_N_MR1)); 2974 assertNotNull( 2975 mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1)); 2976 2977 assertNull(mHelper.getNotificationChannel( 2978 PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), false)); 2979 compareChannels(groupedAndDeleted, mHelper.getNotificationChannel( 2980 PKG_N_MR1, UID_N_MR1, groupedAndDeleted.getId(), true)); 2981 2982 compareChannels(groupedButNotDeleted, mHelper.getNotificationChannel( 2983 PKG_N_MR1, UID_N_MR1, groupedButNotDeleted.getId(), false)); 2984 compareChannels(nonGroupedNonDeletedChannel, mHelper.getNotificationChannel( 2985 PKG_N_MR1, UID_N_MR1, nonGroupedNonDeletedChannel.getId(), false)); 2986 2987 // notDeleted 2988 assertEquals(1, mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).size()); 2989 2990 verify(mHandler, never()).requestSort(); 2991 2992 assertEquals(7, mLogger.getCalls().size()); 2993 assertEquals( 2994 NotificationChannelLogger.NotificationChannelEvent 2995 .NOTIFICATION_CHANNEL_GROUP_DELETED, 2996 mLogger.get(5).event); // Next-to-last log is the deletion of the channel group. 2997 assertEquals( 2998 NotificationChannelLogger.NotificationChannelEvent 2999 .NOTIFICATION_CHANNEL_DELETED, 3000 mLogger.get(6).event); // Final log is the deletion of the channel. 3001 } 3002 3003 @Test testGetNotificationChannelGroup()3004 public void testGetNotificationChannelGroup() throws Exception { 3005 NotificationChannelGroup notDeleted = new NotificationChannelGroup("not", "deleted"); 3006 NotificationChannel base = 3007 new NotificationChannel("not deleted", "belongs to notDeleted", IMPORTANCE_DEFAULT); 3008 base.setGroup("not"); 3009 NotificationChannel convo = 3010 new NotificationChannel("convo", "belongs to notDeleted", IMPORTANCE_DEFAULT); 3011 convo.setGroup("not"); 3012 convo.setConversationId("not deleted", "banana"); 3013 3014 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true, 3015 UID_N_MR1, false); 3016 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, base, true, false, 3017 UID_N_MR1, false); 3018 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, convo, true, false, 3019 UID_N_MR1, false); 3020 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, notDeleted, true, 3021 UID_N_MR1, false); 3022 3023 NotificationChannelGroup g 3024 = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1); 3025 Parcel parcel = Parcel.obtain(); 3026 g.writeToParcel(parcel, 0); 3027 parcel.setDataPosition(0); 3028 3029 NotificationChannelGroup g2 3030 = mHelper.getNotificationChannelGroup(notDeleted.getId(), PKG_N_MR1, UID_N_MR1); 3031 Parcel parcel2 = Parcel.obtain(); 3032 g2.writeToParcel(parcel2, 0); 3033 parcel2.setDataPosition(0); 3034 } 3035 3036 @Test testOnUserRemoved()3037 public void testOnUserRemoved() throws Exception { 3038 int[] user0Uids = {98, 235, 16, 3782}; 3039 int[] user1Uids = new int[user0Uids.length]; 3040 for (int i = 0; i < user0Uids.length; i++) { 3041 user1Uids[i] = UserHandle.PER_USER_RANGE + user0Uids[i]; 3042 3043 final ApplicationInfo legacy = new ApplicationInfo(); 3044 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 3045 when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(legacy); 3046 3047 // create records with the default channel for all user 0 and user 1 uids 3048 mHelper.canShowBadge(PKG_N_MR1, user0Uids[i]); 3049 mHelper.canShowBadge(PKG_N_MR1, user1Uids[i]); 3050 } 3051 3052 mHelper.onUserRemoved(1); 3053 3054 // user 0 records remain 3055 for (int i = 0; i < user0Uids.length; i++) { 3056 assertEquals(1, 3057 mHelper.getNotificationChannels(PKG_N_MR1, user0Uids[i], false).getList().size()); 3058 } 3059 // user 1 records are gone 3060 for (int i = 0; i < user1Uids.length; i++) { 3061 assertEquals(0, 3062 mHelper.getNotificationChannels(PKG_N_MR1, user1Uids[i], false).getList().size()); 3063 } 3064 } 3065 3066 @Test testOnPackageChanged_packageRemoval()3067 public void testOnPackageChanged_packageRemoval() throws Exception { 3068 // Deleted 3069 NotificationChannel channel1 = 3070 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 3071 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 3072 UID_N_MR1, false); 3073 3074 assertTrue(mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, 3075 new int[]{UID_N_MR1})); 3076 3077 assertEquals(0, mHelper.getNotificationChannels( 3078 PKG_N_MR1, UID_N_MR1, true).getList().size()); 3079 3080 // Not deleted 3081 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 3082 UID_N_MR1, false); 3083 3084 assertFalse(mHelper.onPackagesChanged(false, USER_SYSTEM, 3085 new String[]{PKG_N_MR1}, new int[]{UID_N_MR1})); 3086 assertEquals(2, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size()); 3087 } 3088 3089 @Test testOnPackageChanged_packageRemoval_groups()3090 public void testOnPackageChanged_packageRemoval_groups() throws Exception { 3091 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 3092 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 3093 UID_N_MR1, false); 3094 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 3095 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 3096 UID_N_MR1, false); 3097 3098 mHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_N_MR1}, new int[]{ 3099 UID_N_MR1}); 3100 3101 assertEquals(0, mHelper.getNotificationChannelGroups( 3102 PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList().size()); 3103 } 3104 3105 @Test testOnPackageChange_downgradeTargetSdk()3106 public void testOnPackageChange_downgradeTargetSdk() throws Exception { 3107 // create channel as api 26 3108 mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, 3109 UID_N_MR1, false); 3110 3111 // install new app version targeting 25 3112 final ApplicationInfo legacy = new ApplicationInfo(); 3113 legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1; 3114 when(mPm.getApplicationInfoAsUser(eq(PKG_O), anyInt(), anyInt())).thenReturn(legacy); 3115 mHelper.onPackagesChanged( 3116 false, USER_SYSTEM, new String[]{PKG_O}, new int[]{UID_O}); 3117 3118 // make sure the default channel was readded 3119 //assertEquals(2, mHelper.getNotificationChannels(PKG_O, UID_O, false).getList().size()); 3120 assertNotNull(mHelper.getNotificationChannel( 3121 PKG_O, UID_O, NotificationChannel.DEFAULT_CHANNEL_ID, false)); 3122 } 3123 3124 @Test testClearData()3125 public void testClearData() { 3126 ArraySet<Pair<String, Integer>> pkgPair = new ArraySet<>(); 3127 pkgPair.add(new Pair<>(PKG_O, UID_O)); 3128 mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, 3129 UID_O, false); 3130 mHelper.createNotificationChannelGroup( 3131 PKG_O, UID_O, new NotificationChannelGroup("1", "bye"), true, 3132 UID_O, false); 3133 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, pkgPair); 3134 mHelper.setNotificationDelegate(PKG_O, UID_O, "", 1); 3135 mHelper.setBubblesAllowed(PKG_O, UID_O, DEFAULT_BUBBLE_PREFERENCE); 3136 mHelper.setShowBadge(PKG_O, UID_O, false); 3137 mHelper.setAppImportanceLocked(PKG_O, UID_O); 3138 3139 mHelper.clearData(PKG_O, UID_O); 3140 3141 assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), DEFAULT_BUBBLE_PREFERENCE); 3142 assertTrue(mHelper.canShowBadge(PKG_O, UID_O)); 3143 assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); 3144 assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); 3145 assertEquals(0, mHelper.getNotificationChannels(PKG_O, UID_O, true).getList().size()); 3146 assertEquals(0, mHelper.getNotificationChannelGroups(PKG_O, UID_O).size()); 3147 3148 NotificationChannel channel = getChannel(); 3149 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, 3150 UID_O, false); 3151 3152 assertTrue(channel.isImportanceLockedByCriticalDeviceFunction()); 3153 } 3154 3155 @Test testRecordDefaults()3156 public void testRecordDefaults() throws Exception { 3157 assertEquals(true, mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1)); 3158 assertEquals(1, mHelper.getNotificationChannels(PKG_N_MR1, UID_N_MR1, false).getList().size()); 3159 } 3160 3161 @Test testCreateGroup()3162 public void testCreateGroup() { 3163 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 3164 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 3165 UID_N_MR1, false); 3166 assertEquals(ncg, 3167 mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1).iterator().next()); 3168 verify(mHandler, never()).requestSort(); 3169 assertEquals(1, mLogger.getCalls().size()); 3170 assertEquals( 3171 NotificationChannelLogger.NotificationChannelEvent 3172 .NOTIFICATION_CHANNEL_GROUP_CREATED, 3173 mLogger.get(0).event); 3174 } 3175 3176 @Test testCannotCreateChannel_badGroup()3177 public void testCannotCreateChannel_badGroup() { 3178 NotificationChannel channel1 = 3179 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 3180 channel1.setGroup("garbage"); 3181 try { 3182 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 3183 UID_N_MR1, false); 3184 fail("Created a channel with a bad group"); 3185 } catch (IllegalArgumentException e) { 3186 } 3187 assertEquals(0, mLogger.getCalls().size()); 3188 } 3189 3190 @Test testCannotCreateChannel_goodGroup()3191 public void testCannotCreateChannel_goodGroup() { 3192 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 3193 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 3194 UID_N_MR1, false); 3195 NotificationChannel channel1 = 3196 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 3197 channel1.setGroup(ncg.getId()); 3198 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 3199 UID_N_MR1, false); 3200 3201 assertEquals(ncg.getId(), mHelper.getNotificationChannel( 3202 PKG_N_MR1, UID_N_MR1, channel1.getId(), false).getGroup()); 3203 } 3204 3205 @Test testGetChannelGroups()3206 public void testGetChannelGroups() { 3207 NotificationChannelGroup unused = new NotificationChannelGroup("unused", "s"); 3208 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, unused, true, 3209 UID_N_MR1, false); 3210 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 3211 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 3212 UID_N_MR1, false); 3213 NotificationChannelGroup ncg2 = new NotificationChannelGroup("group2", "name2"); 3214 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg2, true, 3215 UID_N_MR1, false); 3216 3217 NotificationChannel channel1 = 3218 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 3219 channel1.setGroup(ncg.getId()); 3220 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 3221 UID_N_MR1, false); 3222 NotificationChannel channel1a = 3223 new NotificationChannel("id1a", "name1", NotificationManager.IMPORTANCE_HIGH); 3224 channel1a.setGroup(ncg.getId()); 3225 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1a, true, false, 3226 UID_N_MR1, false); 3227 3228 NotificationChannel channel2 = 3229 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); 3230 channel2.setGroup(ncg2.getId()); 3231 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, 3232 UID_N_MR1, false); 3233 3234 NotificationChannel channel3 = 3235 new NotificationChannel("id3", "name1", NotificationManager.IMPORTANCE_HIGH); 3236 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, 3237 UID_N_MR1, false); 3238 3239 List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups( 3240 PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList(); 3241 assertEquals(3, actual.size()); 3242 for (NotificationChannelGroup group : actual) { 3243 if (group.getId() == null) { 3244 assertEquals(2, group.getChannels().size()); // misc channel too 3245 assertTrue(channel3.getId().equals(group.getChannels().get(0).getId()) 3246 || channel3.getId().equals(group.getChannels().get(1).getId())); 3247 } else if (group.getId().equals(ncg.getId())) { 3248 assertEquals(2, group.getChannels().size()); 3249 if (group.getChannels().get(0).getId().equals(channel1.getId())) { 3250 assertTrue(group.getChannels().get(1).getId().equals(channel1a.getId())); 3251 } else if (group.getChannels().get(0).getId().equals(channel1a.getId())) { 3252 assertTrue(group.getChannels().get(1).getId().equals(channel1.getId())); 3253 } else { 3254 fail("expected channel not found"); 3255 } 3256 } else if (group.getId().equals(ncg2.getId())) { 3257 assertEquals(1, group.getChannels().size()); 3258 assertEquals(channel2.getId(), group.getChannels().get(0).getId()); 3259 } 3260 } 3261 } 3262 3263 @Test testGetChannelGroups_noSideEffects()3264 public void testGetChannelGroups_noSideEffects() { 3265 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 3266 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 3267 UID_N_MR1, false); 3268 3269 NotificationChannel channel1 = 3270 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 3271 channel1.setGroup(ncg.getId()); 3272 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 3273 UID_N_MR1, false); 3274 mHelper.getNotificationChannelGroups(PKG_N_MR1, UID_N_MR1, true, true, false, true, null) 3275 .getList(); 3276 3277 channel1.setImportance(IMPORTANCE_LOW); 3278 mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, 3279 UID_N_MR1, false); 3280 3281 List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups( 3282 PKG_N_MR1, UID_N_MR1, true, true, false, true, null).getList(); 3283 3284 assertEquals(2, actual.size()); 3285 for (NotificationChannelGroup group : actual) { 3286 if (Objects.equals(group.getId(), ncg.getId())) { 3287 assertEquals(1, group.getChannels().size()); 3288 } 3289 } 3290 } 3291 3292 @Test testGetChannelGroups_includeEmptyGroups()3293 public void testGetChannelGroups_includeEmptyGroups() { 3294 NotificationChannelGroup ncg = new NotificationChannelGroup("group1", "name1"); 3295 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true, 3296 UID_N_MR1, false); 3297 NotificationChannelGroup ncgEmpty = new NotificationChannelGroup("group2", "name2"); 3298 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncgEmpty, true, 3299 UID_N_MR1, false); 3300 3301 NotificationChannel channel1 = 3302 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 3303 channel1.setGroup(ncg.getId()); 3304 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, false, 3305 UID_N_MR1, false); 3306 3307 List<NotificationChannelGroup> actual = mHelper.getNotificationChannelGroups( 3308 PKG_N_MR1, UID_N_MR1, false, false, true, true, null).getList(); 3309 3310 assertEquals(2, actual.size()); 3311 for (NotificationChannelGroup group : actual) { 3312 if (Objects.equals(group.getId(), ncg.getId())) { 3313 assertEquals(1, group.getChannels().size()); 3314 } 3315 if (Objects.equals(group.getId(), ncgEmpty.getId())) { 3316 assertEquals(0, group.getChannels().size()); 3317 } 3318 } 3319 } 3320 3321 @Test testCreateChannel_updateName()3322 public void testCreateChannel_updateName() { 3323 NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); 3324 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, 3325 UID_N_MR1, false)); 3326 NotificationChannel actual = 3327 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); 3328 assertEquals("hello", actual.getName()); 3329 3330 nc = new NotificationChannel("id", "goodbye", IMPORTANCE_HIGH); 3331 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, 3332 UID_N_MR1, false)); 3333 3334 actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); 3335 assertEquals("goodbye", actual.getName()); 3336 assertEquals(IMPORTANCE_DEFAULT, actual.getImportance()); 3337 3338 verify(mHandler, times(1)).requestSort(); 3339 } 3340 3341 @Test testCreateChannel_addToGroup()3342 public void testCreateChannel_addToGroup() { 3343 NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); 3344 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, 3345 UID_N_MR1, false); 3346 NotificationChannel nc = new NotificationChannel("id", "hello", IMPORTANCE_DEFAULT); 3347 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, 3348 UID_N_MR1, false)); 3349 NotificationChannel actual = 3350 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); 3351 assertNull(actual.getGroup()); 3352 3353 nc = new NotificationChannel("id", "hello", IMPORTANCE_HIGH); 3354 nc.setGroup(group.getId()); 3355 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, nc, true, false, 3356 UID_N_MR1, false)); 3357 3358 actual = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "id", false); 3359 assertNotNull(actual.getGroup()); 3360 assertEquals(IMPORTANCE_DEFAULT, actual.getImportance()); 3361 3362 verify(mHandler, times(1)).requestSort(); 3363 assertEquals(3, mLogger.getCalls().size()); 3364 assertEquals( 3365 NotificationChannelLogger.NotificationChannelEvent 3366 .NOTIFICATION_CHANNEL_GROUP_CREATED, 3367 mLogger.get(0).event); 3368 assertEquals( 3369 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED, 3370 mLogger.get(1).event); 3371 assertEquals( 3372 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED, 3373 mLogger.get(2).event); 3374 } 3375 3376 @Test testDumpChannelsJson()3377 public void testDumpChannelsJson() throws Exception { 3378 final ApplicationInfo upgrade = new ApplicationInfo(); 3379 upgrade.targetSdkVersion = Build.VERSION_CODES.O; 3380 try { 3381 when(mPm.getApplicationInfoAsUser( 3382 anyString(), anyInt(), anyInt())).thenReturn(upgrade); 3383 } catch (PackageManager.NameNotFoundException e) { 3384 } 3385 ArrayMap<String, Integer> expectedChannels = new ArrayMap<>(); 3386 int numPackages = ThreadLocalRandom.current().nextInt(1, 5); 3387 for (int i = 0; i < numPackages; i++) { 3388 String pkgName = "pkg" + i; 3389 int numChannels = ThreadLocalRandom.current().nextInt(1, 10); 3390 for (int j = 0; j < numChannels; j++) { 3391 mHelper.createNotificationChannel(pkgName, UID_N_MR1, 3392 new NotificationChannel("" + j, "a", IMPORTANCE_HIGH), true, false, 3393 UID_N_MR1, false); 3394 } 3395 expectedChannels.put(pkgName, numChannels); 3396 } 3397 3398 // delete the first channel of the first package 3399 String pkg = expectedChannels.keyAt(0); 3400 mHelper.deleteNotificationChannel("pkg" + 0, UID_N_MR1, "0", 3401 UID_N_MR1, false); 3402 // dump should not include deleted channels 3403 int count = expectedChannels.get(pkg); 3404 expectedChannels.put(pkg, count - 1); 3405 3406 JSONArray actual = mHelper.dumpChannelsJson(new NotificationManagerService.DumpFilter()); 3407 assertEquals(numPackages, actual.length()); 3408 for (int i = 0; i < numPackages; i++) { 3409 JSONObject object = actual.getJSONObject(i); 3410 assertTrue(expectedChannels.containsKey(object.get("packageName"))); 3411 assertEquals(expectedChannels.get(object.get("packageName")).intValue(), 3412 object.getInt("channelCount")); 3413 } 3414 } 3415 3416 @Test testDumpJson_postPermissionMigration()3417 public void testDumpJson_postPermissionMigration() throws Exception { 3418 // when getting a json dump, we want to verify that: 3419 // - all notification importance info should come from the permission, even if the data 3420 // isn't there yet but is present in package preferences 3421 // - if there are permissions granted or denied from packages PreferencesHelper doesn't 3422 // know about, those should still be included 3423 3424 // package permissions map to be passed in 3425 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 3426 appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs 3427 appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); // not in local prefs 3428 appPermissions.put(new Pair<>(UID_P, PKG_P), new Pair<>(true, false)); // in local prefs 3429 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs 3430 3431 NotificationChannel channel1 = 3432 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 3433 NotificationChannel channel2 = 3434 new NotificationChannel("id2", "name2", IMPORTANCE_LOW); 3435 NotificationChannel channel3 = new NotificationChannel("id3", "name3", IMPORTANCE_HIGH); 3436 3437 mHelper.createNotificationChannel(PKG_P, UID_P, channel1, true, false, 3438 UID_P, false); 3439 mHelper.createNotificationChannel(PKG_P, UID_P, channel2, false, false, 3440 UID_P, false); 3441 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, false, false, 3442 UID_N_MR1, false); 3443 mHelper.createNotificationChannel(PKG_O, UID_O, getChannel(), true, false, 3444 UID_N_MR1, false); 3445 3446 // in the json array, all of the individual package preferences are simply elements in the 3447 // values array. this set is to collect expected outputs for each of our packages. 3448 // the key/value pairs are: (userId, package name) -> expected importance 3449 ArrayMap<Pair<Integer, String>, String> expected = new ArrayMap<>(); 3450 3451 // packages that only exist via the app permissions; should be present 3452 expected.put(new Pair<>(UserHandle.getUserId(1), "first"), "DEFAULT"); 3453 expected.put(new Pair<>(UserHandle.getUserId(3), "third"), "NONE"); 3454 3455 // packages that exist in both app permissions & local preferences 3456 expected.put(new Pair<>(UserHandle.getUserId(UID_P), PKG_P), "DEFAULT"); 3457 expected.put(new Pair<>(UserHandle.getUserId(UID_O), PKG_O), "NONE"); 3458 3459 // package that only exists in local preferences; expect no importance output 3460 expected.put(new Pair<>(UserHandle.getUserId(UID_N_MR1), PKG_N_MR1), null); 3461 3462 JSONArray actual = (JSONArray) mHelper.dumpJson( 3463 new NotificationManagerService.DumpFilter(), appPermissions) 3464 .get("PackagePreferencess"); 3465 assertThat(actual.length()).isEqualTo(expected.size()); 3466 for (int i = 0; i < actual.length(); i++) { 3467 JSONObject pkgInfo = actual.getJSONObject(i); 3468 Pair<Integer, String> pkgKey = 3469 new Pair<>(pkgInfo.getInt("userId"), pkgInfo.getString("packageName")); 3470 assertTrue(expected.containsKey(pkgKey)); 3471 if (pkgInfo.has("importance")) { 3472 assertThat(pkgInfo.getString("importance")).isEqualTo(expected.get(pkgKey)); 3473 } else { 3474 assertThat(expected.get(pkgKey)).isNull(); 3475 } 3476 } 3477 } 3478 3479 @Test testDumpJson_givenNullInput_postMigration()3480 public void testDumpJson_givenNullInput_postMigration() throws Exception { 3481 // simple test just to make sure nothing dies if we pass in null input even post migration 3482 // for some reason, even though in practice this should not be how one calls this method 3483 3484 // some packages exist 3485 mHelper.canShowBadge(PKG_O, UID_O); 3486 mHelper.canShowBadge(PKG_P, UID_P); 3487 3488 JSONArray actual = (JSONArray) mHelper.dumpJson( 3489 new NotificationManagerService.DumpFilter(), null) 3490 .get("PackagePreferencess"); 3491 3492 // there should still be info for the packages 3493 assertThat(actual.length()).isEqualTo(2); 3494 3495 // but they should not have importance info because the migration is enabled and it got 3496 // no info 3497 for (int i = 0; i < actual.length(); i++) { 3498 assertFalse(actual.getJSONObject(i).has("importance")); 3499 } 3500 } 3501 3502 @Test testDumpBansJson_postPermissionMigration()3503 public void testDumpBansJson_postPermissionMigration() throws Exception { 3504 // confirm that the package bans that are in the output include all packages that 3505 // have their permission set to false, and not based on PackagePreferences importance 3506 3507 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 3508 appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs 3509 appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); // not in local prefs 3510 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs 3511 3512 mHelper.canShowBadge(PKG_O, UID_O); 3513 3514 // expected output 3515 ArraySet<Pair<Integer, String>> expected = new ArraySet<>(); 3516 expected.add(new Pair<>(UserHandle.getUserId(3), "third")); 3517 expected.add(new Pair<>(UserHandle.getUserId(UID_O), PKG_O)); 3518 3519 // make sure that's the only thing in the package ban output 3520 JSONArray actual = mHelper.dumpBansJson( 3521 new NotificationManagerService.DumpFilter(), appPermissions); 3522 assertThat(actual.length()).isEqualTo(expected.size()); 3523 3524 for (int i = 0; i < actual.length(); i++) { 3525 JSONObject ban = actual.getJSONObject(i); 3526 assertTrue(expected.contains( 3527 new Pair<>(ban.getInt("userId"), ban.getString("packageName")))); 3528 } 3529 } 3530 3531 @Test testDumpBansJson_givenNullInput()3532 public void testDumpBansJson_givenNullInput() throws Exception { 3533 // no one should do this, but... 3534 3535 JSONArray actual = mHelper.dumpBansJson( 3536 new NotificationManagerService.DumpFilter(), null); 3537 assertThat(actual.length()).isEqualTo(0); 3538 } 3539 3540 @Test testDumpString_postPermissionMigration()3541 public void testDumpString_postPermissionMigration() { 3542 // confirm that the string resulting from dumpImpl contains only importances from permission 3543 3544 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 3545 appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs 3546 appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, true)); // not in local prefs 3547 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs 3548 3549 // local package preferences 3550 mHelper.canShowBadge(PKG_O, UID_O); 3551 mHelper.canShowBadge(PKG_P, UID_P); 3552 3553 // get dump output as a string so we can inspect the contents later 3554 StringWriter sw = new StringWriter(); 3555 PrintWriter pw = new PrintWriter(sw); 3556 mHelper.dump(pw, "", new NotificationManagerService.DumpFilter(), appPermissions); 3557 pw.flush(); 3558 String actual = sw.toString(); 3559 3560 // expected (substring) output for each preference via permissions 3561 ArrayList<String> expected = new ArrayList<>(); 3562 expected.add("first (1) importance=DEFAULT userSet=false"); 3563 expected.add("third (3) importance=NONE userSet=true"); 3564 expected.add(PKG_O + " (" + UID_O + ") importance=NONE userSet=false"); 3565 expected.add(PKG_P + " (" + UID_P + ")"); 3566 3567 // make sure we don't have package preference info 3568 ArrayList<String> notExpected = new ArrayList<>(); 3569 notExpected.add(PKG_O + " (" + UID_O + ") importance=HIGH"); 3570 notExpected.add(PKG_P + " (" + UID_P + ") importance="); // no importance for PKG_P 3571 3572 for (String exp : expected) { 3573 assertTrue(actual.contains(exp)); 3574 } 3575 3576 for (String notExp : notExpected) { 3577 assertFalse(actual.contains(notExp)); 3578 } 3579 } 3580 3581 @Test testDumpString_givenNullInput()3582 public void testDumpString_givenNullInput() { 3583 // test that this doesn't choke on null input 3584 3585 // local package preferences 3586 mHelper.canShowBadge(PKG_O, UID_O); 3587 mHelper.canShowBadge(PKG_P, UID_P); 3588 3589 // get dump output 3590 StringWriter sw = new StringWriter(); 3591 PrintWriter pw = new PrintWriter(sw); 3592 mHelper.dump(pw, "", new NotificationManagerService.DumpFilter(), null); 3593 pw.flush(); 3594 String actual = sw.toString(); 3595 3596 // nobody gets any importance 3597 assertFalse(actual.contains("importance=")); 3598 } 3599 3600 @Test testDumpProto_postPermissionMigration()3601 public void testDumpProto_postPermissionMigration() throws Exception { 3602 // test that dumping to proto gets the importances from the right place 3603 3604 // permissions -- these should take precedence 3605 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 3606 appPermissions.put(new Pair<>(1, "first"), new Pair<>(true, false)); // not in local prefs 3607 appPermissions.put(new Pair<>(3, "third"), new Pair<>(false, false)); // not in local prefs 3608 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, false)); // in local prefs 3609 3610 // local package preferences 3611 mHelper.canShowBadge(PKG_O, UID_O); 3612 mHelper.canShowBadge(PKG_P, UID_P); 3613 3614 // expected output: all the packages, but only the ones provided via appPermissions 3615 // should have importance set (aka not PKG_P) 3616 // map format: (uid, package name) -> importance (int) 3617 ArrayMap<Pair<Integer, String>, Integer> expected = new ArrayMap<>(); 3618 expected.put(new Pair<>(1, "first"), IMPORTANCE_DEFAULT); 3619 expected.put(new Pair<>(3, "third"), IMPORTANCE_NONE); 3620 expected.put(new Pair<>(UID_O, PKG_O), IMPORTANCE_NONE); 3621 3622 // unfortunately, due to how nano protos work, there's no distinction between unset 3623 // fields and default-value fields, so we have no choice here but to check for a value of 0. 3624 // at least we can make sure the local importance for PKG_P in this test is not 0 (NONE). 3625 expected.put(new Pair<>(UID_P, PKG_P), 0); 3626 3627 // get the proto output and inspect its contents 3628 ProtoOutputStream proto = new ProtoOutputStream(); 3629 mHelper.dump(proto, new NotificationManagerService.DumpFilter(), appPermissions); 3630 3631 RankingHelperProto actual = RankingHelperProto.parseFrom(proto.getBytes()); 3632 assertThat(actual.records.length).isEqualTo(expected.size()); 3633 for (int i = 0; i < actual.records.length; i++) { 3634 RankingHelperProto.RecordProto record = actual.records[i]; 3635 Pair<Integer, String> pkgKey = new Pair<>(record.uid, record.package_); 3636 assertTrue(expected.containsKey(pkgKey)); 3637 assertThat(record.importance).isEqualTo(expected.get(pkgKey)); 3638 } 3639 } 3640 3641 @Test testBadgingOverrideTrue()3642 public void testBadgingOverrideTrue() throws Exception { 3643 Secure.putIntForUser(getContext().getContentResolver(), 3644 Secure.NOTIFICATION_BADGING, 1, 3645 USER.getIdentifier()); 3646 mHelper.updateBadgingEnabled(); // would be called by settings observer 3647 assertTrue(mHelper.badgingEnabled(USER)); 3648 } 3649 3650 @Test testBadgingOverrideFalse()3651 public void testBadgingOverrideFalse() throws Exception { 3652 Secure.putIntForUser(getContext().getContentResolver(), 3653 Secure.NOTIFICATION_BADGING, 0, 3654 USER.getIdentifier()); 3655 mHelper.updateBadgingEnabled(); // would be called by settings observer 3656 assertFalse(mHelper.badgingEnabled(USER)); 3657 } 3658 3659 @Test testBadgingForUserAll()3660 public void testBadgingForUserAll() throws Exception { 3661 try { 3662 mHelper.badgingEnabled(UserHandle.ALL); 3663 } catch (Exception e) { 3664 fail("just don't throw"); 3665 } 3666 } 3667 3668 @Test testBadgingOverrideUserIsolation()3669 public void testBadgingOverrideUserIsolation() throws Exception { 3670 Secure.putIntForUser(getContext().getContentResolver(), 3671 Secure.NOTIFICATION_BADGING, 0, 3672 USER.getIdentifier()); 3673 Secure.putIntForUser(getContext().getContentResolver(), 3674 Secure.NOTIFICATION_BADGING, 1, 3675 USER2.getIdentifier()); 3676 mHelper.updateBadgingEnabled(); // would be called by settings observer 3677 assertFalse(mHelper.badgingEnabled(USER)); 3678 assertTrue(mHelper.badgingEnabled(USER2)); 3679 } 3680 3681 @Test testBubblesOverrideTrue()3682 public void testBubblesOverrideTrue() { 3683 Secure.putIntForUser(getContext().getContentResolver(), 3684 Secure.NOTIFICATION_BUBBLES, 1, 3685 USER.getIdentifier()); 3686 mHelper.updateBubblesEnabled(); // would be called by settings observer 3687 assertTrue(mHelper.bubblesEnabled(USER)); 3688 } 3689 3690 @Test testBubblesOverrideFalse()3691 public void testBubblesOverrideFalse() { 3692 Secure.putIntForUser(getContext().getContentResolver(), 3693 Secure.NOTIFICATION_BUBBLES, 0, 3694 USER.getIdentifier()); 3695 mHelper.updateBubblesEnabled(); // would be called by settings observer 3696 assertFalse(mHelper.bubblesEnabled(USER)); 3697 } 3698 3699 @Test testBubblesOverrideUserIsolation()3700 public void testBubblesOverrideUserIsolation() throws Exception { 3701 Secure.putIntForUser(getContext().getContentResolver(), 3702 Secure.NOTIFICATION_BUBBLES, 0, 3703 USER.getIdentifier()); 3704 Secure.putIntForUser(getContext().getContentResolver(), 3705 Secure.NOTIFICATION_BUBBLES, 1, 3706 USER2.getIdentifier()); 3707 mHelper.updateBubblesEnabled(); // would be called by settings observer 3708 assertFalse(mHelper.bubblesEnabled(USER)); 3709 assertTrue(mHelper.bubblesEnabled(USER2)); 3710 } 3711 3712 @Test testShowQSMediaOverrideTrue()3713 public void testShowQSMediaOverrideTrue() { 3714 Global.putInt(getContext().getContentResolver(), 3715 Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 1); 3716 mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer 3717 assertTrue(mHelper.isMediaNotificationFilteringEnabled()); 3718 } 3719 3720 @Test testShowQSMediaOverrideFalse()3721 public void testShowQSMediaOverrideFalse() { 3722 Global.putInt(getContext().getContentResolver(), 3723 Global.SHOW_MEDIA_ON_QUICK_SETTINGS, 0); 3724 mHelper.updateMediaNotificationFilteringEnabled(); // would be called by settings observer 3725 assertFalse(mHelper.isMediaNotificationFilteringEnabled()); 3726 } 3727 3728 @Test testOnLocaleChanged_updatesDefaultChannels()3729 public void testOnLocaleChanged_updatesDefaultChannels() throws Exception { 3730 String newLabel = "bananas!"; 3731 final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1, 3732 UID_N_MR1, 3733 NotificationChannel.DEFAULT_CHANNEL_ID, false); 3734 assertFalse(newLabel.equals(defaultChannel.getName())); 3735 3736 Resources res = mock(Resources.class); 3737 when(mContext.getResources()).thenReturn(res); 3738 when(res.getString(com.android.internal.R.string.default_notification_channel_label)) 3739 .thenReturn(newLabel); 3740 3741 mHelper.onLocaleChanged(mContext, USER.getIdentifier()); 3742 3743 assertEquals(newLabel, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, 3744 NotificationChannel.DEFAULT_CHANNEL_ID, false).getName()); 3745 } 3746 3747 @Test testIsGroupBlocked_noGroup()3748 public void testIsGroupBlocked_noGroup() throws Exception { 3749 assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, null)); 3750 3751 assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, "non existent group")); 3752 } 3753 3754 @Test testIsGroupBlocked_notBlocked()3755 public void testIsGroupBlocked_notBlocked() throws Exception { 3756 NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); 3757 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, 3758 UID_N_MR1, false); 3759 3760 assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); 3761 } 3762 3763 @Test testIsGroupBlocked_blocked()3764 public void testIsGroupBlocked_blocked() throws Exception { 3765 NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); 3766 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, 3767 UID_N_MR1, false); 3768 group.setBlocked(true); 3769 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, false, 3770 UID_N_MR1, false); 3771 3772 assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); 3773 } 3774 3775 @Test testIsGroupBlocked_appCannotCreateAsBlocked()3776 public void testIsGroupBlocked_appCannotCreateAsBlocked() throws Exception { 3777 NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); 3778 group.setBlocked(true); 3779 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, 3780 UID_N_MR1, false); 3781 assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); 3782 3783 NotificationChannelGroup group3 = group.clone(); 3784 group3.setBlocked(false); 3785 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true, 3786 UID_N_MR1, false); 3787 assertFalse(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); 3788 } 3789 3790 @Test testIsGroup_appCannotResetBlock()3791 public void testIsGroup_appCannotResetBlock() throws Exception { 3792 NotificationChannelGroup group = new NotificationChannelGroup("id", "name"); 3793 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, 3794 UID_N_MR1, false); 3795 NotificationChannelGroup group2 = group.clone(); 3796 group2.setBlocked(true); 3797 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group2, false, 3798 UID_N_MR1, false); 3799 assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); 3800 3801 NotificationChannelGroup group3 = group.clone(); 3802 group3.setBlocked(false); 3803 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group3, true, 3804 UID_N_MR1, false); 3805 assertTrue(mHelper.isGroupBlocked(PKG_N_MR1, UID_N_MR1, group.getId())); 3806 } 3807 3808 @Test testGetNotificationChannelGroupWithChannels()3809 public void testGetNotificationChannelGroupWithChannels() throws Exception { 3810 NotificationChannelGroup group = new NotificationChannelGroup("group", "group"); 3811 NotificationChannelGroup other = new NotificationChannelGroup("something else", "name"); 3812 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, group, true, 3813 UID_N_MR1, false); 3814 mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, other, true, 3815 UID_N_MR1, false); 3816 3817 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); 3818 a.setGroup(group.getId()); 3819 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT); 3820 b.setGroup(other.getId()); 3821 NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); 3822 c.setGroup(group.getId()); 3823 NotificationChannel d = new NotificationChannel("d", "d", IMPORTANCE_DEFAULT); 3824 3825 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, a, true, false, 3826 UID_N_MR1, false); 3827 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, true, false, 3828 UID_N_MR1, false); 3829 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, c, true, false, 3830 UID_N_MR1, false); 3831 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, d, true, false, 3832 UID_N_MR1, false); 3833 mHelper.deleteNotificationChannel(PKG_N_MR1, UID_N_MR1, c.getId(), 3834 UID_N_MR1, false); 3835 3836 NotificationChannelGroup retrieved = mHelper.getNotificationChannelGroupWithChannels( 3837 PKG_N_MR1, UID_N_MR1, group.getId(), true); 3838 assertEquals(2, retrieved.getChannels().size()); 3839 compareChannels(a, findChannel(retrieved.getChannels(), a.getId())); 3840 compareChannels(c, findChannel(retrieved.getChannels(), c.getId())); 3841 3842 retrieved = mHelper.getNotificationChannelGroupWithChannels( 3843 PKG_N_MR1, UID_N_MR1, group.getId(), false); 3844 assertEquals(1, retrieved.getChannels().size()); 3845 compareChannels(a, findChannel(retrieved.getChannels(), a.getId())); 3846 } 3847 3848 @Test testAndroidPkgCannotBypassDnd_creation()3849 public void testAndroidPkgCannotBypassDnd_creation() { 3850 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3851 test.setBypassDnd(true); 3852 3853 mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false, 3854 SYSTEM_UID, true); 3855 3856 assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) 3857 .canBypassDnd()); 3858 } 3859 3860 @Test testDndPkgCanBypassDnd_creation()3861 public void testDndPkgCanBypassDnd_creation() { 3862 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3863 test.setBypassDnd(true); 3864 3865 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true, 3866 UID_N_MR1, false); 3867 3868 assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd()); 3869 } 3870 3871 @Test testNormalPkgCannotBypassDnd_creation()3872 public void testNormalPkgCannotBypassDnd_creation() { 3873 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3874 test.setBypassDnd(true); 3875 3876 mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false, 3877 UID_N_MR1, false); 3878 3879 assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd()); 3880 } 3881 3882 @Test testAndroidPkgCannotBypassDnd_update()3883 public void testAndroidPkgCannotBypassDnd_update() throws Exception { 3884 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3885 mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, test, true, false, 3886 SYSTEM_UID, true); 3887 3888 NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3889 update.setBypassDnd(true); 3890 assertFalse(mHelper.createNotificationChannel(SYSTEM_PKG, SYSTEM_UID, update, true, false, 3891 SYSTEM_UID, true)); 3892 3893 assertFalse(mHelper.getNotificationChannel(SYSTEM_PKG, SYSTEM_UID, "A", false) 3894 .canBypassDnd()); 3895 } 3896 3897 @Test testDndPkgCanBypassDnd_update()3898 public void testDndPkgCanBypassDnd_update() throws Exception { 3899 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3900 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, test, true, true, 3901 UID_N_MR1, false); 3902 3903 NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3904 update.setBypassDnd(true); 3905 assertTrue(mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, update, true, true, 3906 UID_N_MR1, false)); 3907 3908 assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "A", false).canBypassDnd()); 3909 } 3910 3911 @Test testNormalPkgCannotBypassDnd_update()3912 public void testNormalPkgCannotBypassDnd_update() { 3913 NotificationChannel test = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3914 mHelper.createNotificationChannel(PKG_N_MR1, 1000, test, true, false, 3915 UID_N_MR1, false); 3916 NotificationChannel update = new NotificationChannel("A", "a", IMPORTANCE_LOW); 3917 update.setBypassDnd(true); 3918 mHelper.createNotificationChannel(PKG_N_MR1, 1000, update, true, false, 3919 UID_N_MR1, false); 3920 assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, 1000, "A", false).canBypassDnd()); 3921 } 3922 3923 @Test testXml_statusBarIcons_default()3924 public void testXml_statusBarIcons_default() throws Exception { 3925 String preQXml = "<ranking version=\"1\">\n" 3926 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n" 3927 + "<channel id=\"something\" name=\"name\" importance=\"2\" " 3928 + "show_badge=\"true\" />\n" 3929 + "<channel id=\"miscellaneous\" name=\"Uncategorized\" usage=\"5\" " 3930 + "content_type=\"4\" flags=\"0\" show_badge=\"true\" />\n" 3931 + "</package>\n" 3932 + "</ranking>\n"; 3933 3934 loadByteArrayXml(preQXml.getBytes(), true, USER_SYSTEM); 3935 3936 assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, 3937 mXmlHelper.shouldHideSilentStatusIcons()); 3938 } 3939 3940 @Test testXml_statusBarIcons()3941 public void testXml_statusBarIcons() throws Exception { 3942 mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS); 3943 3944 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_SYSTEM); 3945 loadStreamXml(baos, false, UserHandle.USER_ALL); 3946 3947 assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, 3948 mXmlHelper.shouldHideSilentStatusIcons()); 3949 } 3950 3951 @Test testXml_statusBarIcons_restore()3952 public void testXml_statusBarIcons_restore() throws Exception { 3953 mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS); 3954 3955 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_SYSTEM); 3956 loadStreamXml(baos, true, USER_SYSTEM); 3957 3958 assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, 3959 mXmlHelper.shouldHideSilentStatusIcons()); 3960 } 3961 3962 @Test testXml_statusBarIcons_restoreSecondary()3963 public void testXml_statusBarIcons_restoreSecondary() throws Exception { 3964 mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS); 3965 3966 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 3967 loadStreamXml(baos, true, USER_ALL); 3968 3969 assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS, 3970 mXmlHelper.shouldHideSilentStatusIcons()); 3971 } 3972 3973 @Test testSetNotificationDelegate()3974 public void testSetNotificationDelegate() { 3975 mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 3976 assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O)); 3977 } 3978 3979 @Test testRevokeNotificationDelegate()3980 public void testRevokeNotificationDelegate() { 3981 mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 3982 mHelper.revokeNotificationDelegate(PKG_O, UID_O); 3983 3984 assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); 3985 } 3986 3987 @Test testRevokeNotificationDelegate_noDelegateExistsNoCrash()3988 public void testRevokeNotificationDelegate_noDelegateExistsNoCrash() { 3989 mHelper.revokeNotificationDelegate(PKG_O, UID_O); 3990 3991 assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O)); 3992 } 3993 3994 @Test testIsDelegateAllowed_noSource()3995 public void testIsDelegateAllowed_noSource() { 3996 assertFalse(mHelper.isDelegateAllowed("does not exist", -1, "whatever", 0)); 3997 } 3998 3999 @Test testIsDelegateAllowed_noDelegate()4000 public void testIsDelegateAllowed_noDelegate() { 4001 mHelper.canShowBadge(PKG_O, UID_O); 4002 4003 assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "whatever", 0)); 4004 } 4005 4006 @Test testIsDelegateAllowed_delegateDisabledByApp()4007 public void testIsDelegateAllowed_delegateDisabledByApp() { 4008 mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 4009 mHelper.revokeNotificationDelegate(PKG_O, UID_O); 4010 4011 assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53)); 4012 } 4013 4014 @Test testIsDelegateAllowed_wrongDelegate()4015 public void testIsDelegateAllowed_wrongDelegate() { 4016 mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 4017 mHelper.revokeNotificationDelegate(PKG_O, UID_O); 4018 4019 assertFalse(mHelper.isDelegateAllowed(PKG_O, UID_O, "banana", 27)); 4020 } 4021 4022 @Test testIsDelegateAllowed()4023 public void testIsDelegateAllowed() { 4024 mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 4025 4026 assertTrue(mHelper.isDelegateAllowed(PKG_O, UID_O, "other", 53)); 4027 } 4028 4029 @Test testDelegateXml_noDelegate()4030 public void testDelegateXml_noDelegate() throws Exception { 4031 mHelper.canShowBadge(PKG_O, UID_O); 4032 4033 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 4034 loadStreamXml(baos, false, UserHandle.USER_ALL); 4035 4036 assertNull(mXmlHelper.getNotificationDelegate(PKG_O, UID_O)); 4037 } 4038 4039 @Test testDelegateXml_delegate()4040 public void testDelegateXml_delegate() throws Exception { 4041 mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 4042 4043 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 4044 loadStreamXml(baos, false, UserHandle.USER_ALL); 4045 4046 assertEquals("other", mXmlHelper.getNotificationDelegate(PKG_O, UID_O)); 4047 } 4048 4049 @Test testDelegateXml_disabledDelegate()4050 public void testDelegateXml_disabledDelegate() throws Exception { 4051 mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 4052 mHelper.revokeNotificationDelegate(PKG_O, UID_O); 4053 4054 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 4055 loadStreamXml(baos, false, UserHandle.USER_ALL); 4056 4057 assertNull(mXmlHelper.getNotificationDelegate(PKG_O, UID_O)); 4058 4059 mXmlHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53); 4060 assertEquals("other", mXmlHelper.getNotificationDelegate(PKG_O, UID_O)); 4061 } 4062 4063 @Test testBubblePreference_defaults()4064 public void testBubblePreference_defaults() throws Exception { 4065 assertEquals(BUBBLE_PREFERENCE_NONE, mHelper.getBubblePreference(PKG_O, UID_O)); 4066 4067 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 4068 loadStreamXml(baos, false, UserHandle.USER_ALL); 4069 4070 assertEquals(BUBBLE_PREFERENCE_NONE, mXmlHelper.getBubblePreference(PKG_O, UID_O)); 4071 assertEquals(0, mXmlHelper.getAppLockedFields(PKG_O, UID_O)); 4072 } 4073 4074 @Test testBubblePreference_upgradeWithSAWPermission()4075 public void testBubblePreference_upgradeWithSAWPermission() throws Exception { 4076 when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), 4077 anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED); 4078 4079 final String xml = "<ranking version=\"1\">\n" 4080 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n" 4081 + "<channel id=\"someId\" name=\"hi\"" 4082 + " importance=\"3\"/>" 4083 + "</package>" 4084 + "</ranking>"; 4085 TypedXmlPullParser parser = Xml.newFastPullParser(); 4086 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4087 null); 4088 parser.nextTag(); 4089 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4090 4091 assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O)); 4092 assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); 4093 } 4094 4095 @Test testBubblePreference_upgradeWithSAWThenUserOverride()4096 public void testBubblePreference_upgradeWithSAWThenUserOverride() throws Exception { 4097 when(mAppOpsManager.noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), 4098 anyString(), eq(null), anyString())).thenReturn(MODE_ALLOWED); 4099 4100 final String xml = "<ranking version=\"1\">\n" 4101 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\">\n" 4102 + "<channel id=\"someId\" name=\"hi\"" 4103 + " importance=\"3\"/>" 4104 + "</package>" 4105 + "</ranking>"; 4106 TypedXmlPullParser parser = Xml.newFastPullParser(); 4107 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4108 null); 4109 parser.nextTag(); 4110 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4111 4112 assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O)); 4113 assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); 4114 4115 mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED); 4116 assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O)); 4117 assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, 4118 mHelper.getAppLockedFields(PKG_O, UID_O)); 4119 4120 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 4121 loadStreamXml(baos, false, UserHandle.USER_ALL); 4122 4123 assertEquals(BUBBLE_PREFERENCE_SELECTED, mHelper.getBubblePreference(PKG_O, UID_O)); 4124 assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, 4125 mXmlHelper.getAppLockedFields(PKG_O, UID_O)); 4126 } 4127 4128 @Test testBubblePrefence_noSAWCheckForUnknownUid()4129 public void testBubblePrefence_noSAWCheckForUnknownUid() throws Exception { 4130 final String xml = "<ranking version=\"1\">\n" 4131 + "<package name=\"" + PKG_O + "\" uid=\"" + UNKNOWN_UID + "\">\n" 4132 + "<channel id=\"someId\" name=\"hi\"" 4133 + " importance=\"3\"/>" 4134 + "</package>" 4135 + "</ranking>"; 4136 TypedXmlPullParser parser = Xml.newFastPullParser(); 4137 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4138 null); 4139 parser.nextTag(); 4140 mXmlHelper.readXml(parser, false, UserHandle.USER_ALL); 4141 4142 assertEquals(DEFAULT_BUBBLE_PREFERENCE, mHelper.getBubblePreference(PKG_O, UID_O)); 4143 assertEquals(0, mXmlHelper.getAppLockedFields(PKG_O, UID_O)); 4144 verify(mAppOpsManager, never()).noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), 4145 anyString(), eq(null), anyString()); 4146 } 4147 4148 @Test testBubblePreference_xml()4149 public void testBubblePreference_xml() throws Exception { 4150 mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE); 4151 assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); 4152 assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, 4153 mHelper.getAppLockedFields(PKG_O, UID_O)); 4154 4155 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 4156 loadStreamXml(baos, false, UserHandle.USER_ALL); 4157 4158 assertEquals(mXmlHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); 4159 assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE, 4160 mXmlHelper.getAppLockedFields(PKG_O, UID_O)); 4161 } 4162 4163 @Test testReadXml_existingPackage_bubblePrefsRestored()4164 public void testReadXml_existingPackage_bubblePrefsRestored() throws Exception { 4165 mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL); 4166 assertEquals(BUBBLE_PREFERENCE_ALL, mHelper.getBubblePreference(PKG_O, UID_O)); 4167 4168 mXmlHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE); 4169 assertEquals(BUBBLE_PREFERENCE_NONE, mXmlHelper.getBubblePreference(PKG_O, UID_O)); 4170 4171 ByteArrayOutputStream stream = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL); 4172 loadStreamXml(stream, true, UserHandle.USER_ALL); 4173 4174 assertEquals(BUBBLE_PREFERENCE_ALL, mXmlHelper.getBubblePreference(PKG_O, UID_O)); 4175 } 4176 4177 @Test testUpdateNotificationChannel_fixedPermission()4178 public void testUpdateNotificationChannel_fixedPermission() { 4179 List<UserInfo> users = ImmutableList.of(new UserInfo(UserHandle.USER_SYSTEM, "user0", 0)); 4180 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true); 4181 PackageInfo pm = new PackageInfo(); 4182 pm.packageName = PKG_O; 4183 pm.applicationInfo = new ApplicationInfo(); 4184 pm.applicationInfo.uid = UID_O; 4185 List<PackageInfo> packages = ImmutableList.of(pm); 4186 when(mPm.getInstalledPackagesAsUser(eq(0), anyInt())).thenReturn(packages); 4187 mHelper.updateFixedImportance(users); 4188 4189 assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O)); 4190 4191 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4192 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, 4193 UID_O, false); 4194 4195 NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); 4196 update.setAllowBubbles(false); 4197 4198 mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, 4199 UID_O, false); 4200 4201 assertEquals(IMPORTANCE_HIGH, 4202 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4203 assertEquals(false, 4204 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble()); 4205 } 4206 4207 @Test testUpdateNotificationChannel_defaultApp()4208 public void testUpdateNotificationChannel_defaultApp() { 4209 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4210 toAdd.add(new Pair<>(PKG_O, UID_O)); 4211 mHelper.updateDefaultApps(0, null, toAdd); 4212 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4213 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4214 4215 NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); 4216 update.setAllowBubbles(false); 4217 4218 mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); 4219 4220 assertEquals(IMPORTANCE_HIGH, 4221 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4222 assertEquals(false, 4223 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble()); 4224 } 4225 4226 @Test testUpdateNotificationChannel_fixedPermission_butUserPreviouslyBlockedIt()4227 public void testUpdateNotificationChannel_fixedPermission_butUserPreviouslyBlockedIt() { 4228 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true); 4229 4230 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_NONE); 4231 mHelper.createNotificationChannel(PKG_O, UID_O, a, false, false, UID_O, false); 4232 4233 NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4234 update.setAllowBubbles(false); 4235 4236 mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); 4237 4238 assertEquals(IMPORTANCE_HIGH, 4239 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4240 assertEquals(false, 4241 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble()); 4242 } 4243 4244 @Test testUpdateNotificationChannel_fixedPermission_butAppAllowsIt()4245 public void testUpdateNotificationChannel_fixedPermission_butAppAllowsIt() { 4246 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true); 4247 4248 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4249 a.setBlockable(true); 4250 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4251 4252 NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); 4253 update.setAllowBubbles(false); 4254 4255 mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); 4256 4257 assertEquals(IMPORTANCE_NONE, 4258 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4259 assertEquals(false, 4260 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble()); 4261 } 4262 4263 @Test testUpdateNotificationChannel_notFixedPermission()4264 public void testUpdateNotificationChannel_notFixedPermission() { 4265 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false); 4266 4267 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4268 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4269 4270 NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); 4271 update.setAllowBubbles(false); 4272 4273 mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, UID_O, false); 4274 4275 assertEquals(IMPORTANCE_NONE, 4276 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4277 assertEquals(false, 4278 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble()); 4279 } 4280 4281 @Test testUpdateFixedImportance_multiUser()4282 public void testUpdateFixedImportance_multiUser() { 4283 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4284 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); 4285 NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); 4286 // different uids, same package 4287 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4288 mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, 4289 SYSTEM_UID, true); 4290 mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true, 4291 UserHandle.PER_USER_RANGE + 1, false); 4292 4293 UserInfo user = new UserInfo(); 4294 user.id = 0; 4295 List<UserInfo> users = ImmutableList.of(user); 4296 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true); 4297 PackageInfo pm = new PackageInfo(); 4298 pm.packageName = PKG_O; 4299 pm.applicationInfo = new ApplicationInfo(); 4300 pm.applicationInfo.uid = UID_O; 4301 List<PackageInfo> packages = ImmutableList.of(pm); 4302 when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages); 4303 mHelper.updateFixedImportance(users); 4304 4305 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4306 .isImportanceLockedByCriticalDeviceFunction()); 4307 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false) 4308 .isImportanceLockedByCriticalDeviceFunction()); 4309 assertFalse(mHelper.getNotificationChannel( 4310 PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false) 4311 .isImportanceLockedByCriticalDeviceFunction()); 4312 } 4313 4314 @Test testUpdateFixedImportance_channelDoesNotExistYet()4315 public void testUpdateFixedImportance_channelDoesNotExistYet() { 4316 UserInfo user = new UserInfo(); 4317 user.id = 0; 4318 List<UserInfo> users = ImmutableList.of(user); 4319 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true); 4320 PackageInfo pm = new PackageInfo(); 4321 pm.packageName = PKG_O; 4322 pm.applicationInfo = new ApplicationInfo(); 4323 pm.applicationInfo.uid = UID_O; 4324 List<PackageInfo> packages = ImmutableList.of(pm); 4325 when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages); 4326 mHelper.updateFixedImportance(users); 4327 4328 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4329 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4330 4331 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4332 .isImportanceLockedByCriticalDeviceFunction()); 4333 } 4334 4335 @Test testUpdateDefaultApps_add_multiUser()4336 public void testUpdateDefaultApps_add_multiUser() { 4337 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4338 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); 4339 NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); 4340 // different uids, same package 4341 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4342 mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, UID_O, false); 4343 mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true, 4344 UID_O, false); 4345 4346 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4347 toAdd.add(new Pair<>(PKG_O, UID_O)); 4348 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4349 4350 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4351 .isImportanceLockedByCriticalDeviceFunction()); 4352 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false) 4353 .isImportanceLockedByCriticalDeviceFunction()); 4354 assertFalse(mHelper.getNotificationChannel( 4355 PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false) 4356 .isImportanceLockedByCriticalDeviceFunction()); 4357 } 4358 4359 @Test testUpdateDefaultApps_add_onlyGivenPkg()4360 public void testUpdateDefaultApps_add_onlyGivenPkg() { 4361 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4362 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); 4363 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4364 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false, UID_O, false); 4365 4366 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4367 toAdd.add(new Pair<>(PKG_O, UID_O)); 4368 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4369 4370 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4371 .isImportanceLockedByCriticalDeviceFunction()); 4372 assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false) 4373 .isImportanceLockedByCriticalDeviceFunction()); 4374 } 4375 4376 @Test testUpdateDefaultApps_remove()4377 public void testUpdateDefaultApps_remove() { 4378 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4379 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); 4380 // different uids, same package 4381 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4382 mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false, SYSTEM_UID, true); 4383 4384 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4385 toAdd.add(new Pair<>(PKG_O, UID_O)); 4386 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4387 4388 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4389 .isImportanceLockedByCriticalDeviceFunction()); 4390 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false) 4391 .isImportanceLockedByCriticalDeviceFunction()); 4392 4393 ArraySet<String> toRemove = new ArraySet<>(); 4394 toRemove.add(PKG_O); 4395 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, null); 4396 4397 assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4398 .isImportanceLockedByCriticalDeviceFunction()); 4399 assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false) 4400 .isImportanceLockedByCriticalDeviceFunction()); 4401 } 4402 4403 @Test testUpdateDefaultApps_addAndRemove()4404 public void testUpdateDefaultApps_addAndRemove() { 4405 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4406 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); 4407 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, 4408 UID_O, false); 4409 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false, 4410 UID_N_MR1, false); 4411 4412 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4413 toAdd.add(new Pair<>(PKG_O, UID_O)); 4414 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4415 4416 4417 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4418 .isImportanceLockedByCriticalDeviceFunction()); 4419 assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false) 4420 .isImportanceLockedByCriticalDeviceFunction()); 4421 4422 // now the default is PKG_N_MR1 4423 ArraySet<String> toRemove = new ArraySet<>(); 4424 toRemove.add(PKG_O); 4425 toAdd = new ArraySet<>(); 4426 toAdd.add(new Pair<>(PKG_N_MR1, UID_N_MR1)); 4427 mHelper.updateDefaultApps(USER.getIdentifier(), toRemove, toAdd); 4428 4429 assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4430 .isImportanceLockedByCriticalDeviceFunction()); 4431 assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false) 4432 .isImportanceLockedByCriticalDeviceFunction()); 4433 } 4434 4435 @Test testUpdateDefaultApps_appDoesNotExist_noCrash()4436 public void testUpdateDefaultApps_appDoesNotExist_noCrash() { 4437 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4438 toAdd.add(new Pair<>(PKG_O, UID_O)); 4439 ArraySet<String> toRemove = new ArraySet<>(); 4440 toRemove.add(PKG_N_MR1); 4441 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, toAdd); 4442 } 4443 4444 @Test testUpdateDefaultApps_channelDoesNotExistYet()4445 public void testUpdateDefaultApps_channelDoesNotExistYet() { 4446 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4447 NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW); 4448 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4449 4450 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4451 toAdd.add(new Pair<>(PKG_O, UID_O)); 4452 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4453 4454 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4455 .isImportanceLockedByCriticalDeviceFunction()); 4456 4457 mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false, UID_O, false); 4458 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false) 4459 .isImportanceLockedByCriticalDeviceFunction()); 4460 } 4461 4462 @Test testUpdateNotificationChannel_defaultAppLockedImportance()4463 public void testUpdateNotificationChannel_defaultAppLockedImportance() { 4464 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4465 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4466 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4467 toAdd.add(new Pair<>(PKG_O, UID_O)); 4468 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4469 4470 NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE); 4471 update.setAllowBubbles(false); 4472 4473 mHelper.updateNotificationChannel(PKG_O, UID_O, update, true, SYSTEM_UID, true); 4474 assertEquals(IMPORTANCE_HIGH, 4475 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4476 assertEquals(false, 4477 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble()); 4478 4479 mHelper.updateNotificationChannel(PKG_O, UID_O, update, false, UID_O, false); 4480 assertEquals(IMPORTANCE_HIGH, 4481 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4482 4483 NotificationChannel updateImportanceLow = new NotificationChannel("a", "a", 4484 IMPORTANCE_LOW); 4485 mHelper.updateNotificationChannel(PKG_O, UID_O, updateImportanceLow, true, 4486 SYSTEM_UID, true); 4487 assertEquals(IMPORTANCE_LOW, 4488 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance()); 4489 } 4490 4491 @Test testDefaultApp_appHasNoSettingsYet()4492 public void testDefaultApp_appHasNoSettingsYet() { 4493 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4494 toAdd.add(new Pair<>(PKG_O, UID_O)); 4495 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4496 4497 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4498 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4499 4500 assertTrue(a.isImportanceLockedByCriticalDeviceFunction()); 4501 } 4502 4503 @Test testUpdateFixedImportance_thenDefaultAppsRemoves()4504 public void testUpdateFixedImportance_thenDefaultAppsRemoves() { 4505 UserInfo user = new UserInfo(); 4506 user.id = 0; 4507 List<UserInfo> users = ImmutableList.of(user); 4508 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(true); 4509 PackageInfo pm = new PackageInfo(); 4510 pm.packageName = PKG_O; 4511 pm.applicationInfo = new ApplicationInfo(); 4512 pm.applicationInfo.uid = UID_O; 4513 List<PackageInfo> packages = ImmutableList.of(pm); 4514 when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages); 4515 mHelper.updateFixedImportance(users); 4516 4517 ArraySet<String> toRemove = new ArraySet<>(); 4518 toRemove.add(PKG_O); 4519 mHelper.updateDefaultApps(0, toRemove, null); 4520 4521 assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O)); 4522 4523 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4524 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4525 4526 // Still locked by permission if not role 4527 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4528 .isImportanceLockedByCriticalDeviceFunction()); 4529 } 4530 4531 @Test testUpdateDefaultApps_thenNotFixedPermission()4532 public void testUpdateDefaultApps_thenNotFixedPermission() { 4533 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4534 toAdd.add(new Pair<>(PKG_O, UID_O)); 4535 mHelper.updateDefaultApps(0, null, toAdd); 4536 4537 UserInfo user = new UserInfo(); 4538 user.id = 0; 4539 List<UserInfo> users = ImmutableList.of(user); 4540 when(mPermissionHelper.isPermissionFixed(PKG_O, 0)).thenReturn(false); 4541 PackageInfo pm = new PackageInfo(); 4542 pm.packageName = PKG_O; 4543 pm.applicationInfo = new ApplicationInfo(); 4544 pm.applicationInfo.uid = UID_O; 4545 List<PackageInfo> packages = ImmutableList.of(pm); 4546 when(mPm.getInstalledPackagesAsUser(0, 0)).thenReturn(packages); 4547 mHelper.updateFixedImportance(users); 4548 4549 assertTrue(mHelper.isImportanceLocked(PKG_O, UID_O)); 4550 4551 NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 4552 mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false, UID_O, false); 4553 4554 // Still locked by role if not permission 4555 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false) 4556 .isImportanceLockedByCriticalDeviceFunction()); 4557 } 4558 4559 @Test testChannelXml_backupDefaultApp()4560 public void testChannelXml_backupDefaultApp() throws Exception { 4561 NotificationChannel channel1 = 4562 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH); 4563 4564 mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false, UID_O, false); 4565 4566 // clear data 4567 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, true, 4568 USER_SYSTEM, channel1.getId(), NotificationChannel.DEFAULT_CHANNEL_ID); 4569 mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_O}, new int[]{ 4570 UID_O}); 4571 4572 ArraySet<Pair<String, Integer>> toAdd = new ArraySet<>(); 4573 toAdd.add(new Pair<>(PKG_O, UID_O)); 4574 mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd); 4575 4576 TypedXmlPullParser parser = Xml.newFastPullParser(); 4577 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 4578 null); 4579 parser.nextTag(); 4580 mHelper.readXml(parser, true, USER_SYSTEM); 4581 4582 assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, channel1.getId(), false) 4583 .isImportanceLockedByCriticalDeviceFunction()); 4584 } 4585 4586 @Test testSetBubblesAllowed_none()4587 public void testSetBubblesAllowed_none() { 4588 // Change it to non-default first 4589 mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL); 4590 assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL); 4591 verify(mHandler, times(1)).requestSort(); 4592 reset(mHandler); 4593 // Now test 4594 mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE); 4595 assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); 4596 verify(mHandler, times(1)).requestSort(); 4597 } 4598 4599 @Test testSetBubblesAllowed_all()4600 public void testSetBubblesAllowed_all() { 4601 mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_ALL); 4602 assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_ALL); 4603 verify(mHandler, times(1)).requestSort(); 4604 } 4605 4606 @Test testSetBubblesAllowed_selected()4607 public void testSetBubblesAllowed_selected() { 4608 mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_SELECTED); 4609 assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_SELECTED); 4610 verify(mHandler, times(1)).requestSort(); 4611 } 4612 4613 @Test testTooManyChannels()4614 public void testTooManyChannels() { 4615 for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) { 4616 NotificationChannel channel = new NotificationChannel(String.valueOf(i), 4617 String.valueOf(i), NotificationManager.IMPORTANCE_HIGH); 4618 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false); 4619 } 4620 try { 4621 NotificationChannel channel = new NotificationChannel( 4622 String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT), 4623 String.valueOf(NOTIFICATION_CHANNEL_COUNT_LIMIT), 4624 NotificationManager.IMPORTANCE_HIGH); 4625 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false); 4626 fail("Allowed to create too many notification channels"); 4627 } catch (IllegalStateException e) { 4628 // great 4629 } 4630 } 4631 4632 @Test testTooManyChannels_xml()4633 public void testTooManyChannels_xml() throws Exception { 4634 String extraChannel = "EXTRA"; 4635 String extraChannel1 = "EXTRA1"; 4636 4637 // create first... many... directly so we don't need a big xml blob in this test 4638 for (int i = 0; i < NOTIFICATION_CHANNEL_COUNT_LIMIT; i++) { 4639 NotificationChannel channel = new NotificationChannel(String.valueOf(i), 4640 String.valueOf(i), NotificationManager.IMPORTANCE_HIGH); 4641 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, true, UID_O, false); 4642 } 4643 4644 final String xml = "<ranking version=\"1\">\n" 4645 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" 4646 + "<channel id=\"" + extraChannel + "\" name=\"hi\" importance=\"3\"/>" 4647 + "<channel id=\"" + extraChannel1 + "\" name=\"hi\" importance=\"3\"/>" 4648 + "</package>" 4649 + "</ranking>"; 4650 TypedXmlPullParser parser = Xml.newFastPullParser(); 4651 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4652 null); 4653 parser.nextTag(); 4654 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4655 4656 assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel, true)); 4657 assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, extraChannel1, true)); 4658 } 4659 4660 @Test testTooManyGroups_fromTargetApp()4661 public void testTooManyGroups_fromTargetApp() { 4662 testTooManyGroups(/* fromTargetApp= */ true); 4663 } 4664 4665 @Test testTooManyGroups_fromListener()4666 public void testTooManyGroups_fromListener() { 4667 testTooManyGroups(/* fromTargetApp= */ false); 4668 } 4669 testTooManyGroups(boolean fromTargetApp)4670 private void testTooManyGroups(boolean fromTargetApp) { 4671 for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) { 4672 NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i), 4673 String.valueOf(i)); 4674 mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp, 4675 UID_O, false); 4676 } 4677 try { 4678 NotificationChannelGroup group = new NotificationChannelGroup( 4679 String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT), 4680 String.valueOf(NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT)); 4681 mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, fromTargetApp, 4682 UID_O, false); 4683 fail("Allowed to create too many notification channel groups"); 4684 } catch (IllegalStateException e) { 4685 // great 4686 } 4687 } 4688 4689 @Test testTooManyGroups_xml()4690 public void testTooManyGroups_xml() throws Exception { 4691 String extraGroup = "EXTRA"; 4692 String extraGroup1 = "EXTRA1"; 4693 4694 // create first... many... directly so we don't need a big xml blob in this test 4695 for (int i = 0; i < NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT; i++) { 4696 NotificationChannelGroup group = new NotificationChannelGroup(String.valueOf(i), 4697 String.valueOf(i)); 4698 mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true, 4699 UID_O, false); 4700 } 4701 4702 final String xml = "<ranking version=\"1\">\n" 4703 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" 4704 + "<channelGroup id=\"" + extraGroup + "\" name=\"hi\"/>" 4705 + "<channelGroup id=\"" + extraGroup1 + "\" name=\"hi2\"/>" 4706 + "</package>" 4707 + "</ranking>"; 4708 TypedXmlPullParser parser = Xml.newFastPullParser(); 4709 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4710 null); 4711 parser.nextTag(); 4712 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4713 4714 assertNull(mHelper.getNotificationChannelGroup(extraGroup, PKG_O, UID_O)); 4715 assertNull(mHelper.getNotificationChannelGroup(extraGroup1, PKG_O, UID_O)); 4716 } 4717 4718 @Test testRestoreMultiUser()4719 public void testRestoreMultiUser() throws Exception { 4720 String pkg = "restore_pkg"; 4721 String channelId = "channelId"; 4722 int user0Importance = 3; 4723 int user10Importance = 4; 4724 when(mPm.getPackageUidAsUser(eq(pkg), anyInt())).thenReturn(UserHandle.USER_NULL); 4725 4726 // both users have the same package, but different notification settings 4727 final String xmlUser0 = "<ranking version=\"1\">\n" 4728 + "<package name=\"" + pkg + "\" >\n" 4729 + "<channel id=\"" + channelId + "\" name=\"hi\"" 4730 + " importance=\"" + user0Importance + "\"/>" 4731 + "</package>" 4732 + "</ranking>"; 4733 final String xmlUser10 = "<ranking version=\"1\">\n" 4734 + "<package name=\"" + pkg + "\" >\n" 4735 + "<channel id=\"" + channelId + "\" name=\"hi\"" 4736 + " importance=\"" + user10Importance + "\"/>" 4737 + "</package>" 4738 + "</ranking>"; 4739 4740 // trigger a restore for both users 4741 TypedXmlPullParser parser = Xml.newFastPullParser(); 4742 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser0.getBytes())), 4743 null); 4744 parser.nextTag(); 4745 mHelper.readXml(parser, true, 0); 4746 parser = Xml.newFastPullParser(); 4747 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xmlUser10.getBytes())), 4748 null); 4749 parser.nextTag(); 4750 mHelper.readXml(parser, true, 10); 4751 4752 // "install" package on both users 4753 String[] pkgList = new String[] {pkg}; 4754 int[] uidList0 = new int[] {UserHandle.PER_USER_RANGE}; 4755 int[] uidList10 = new int[] {UserHandle.PER_USER_RANGE + 1}; 4756 when(mPm.getPackageUidAsUser(pkg, 0)).thenReturn(uidList0[0]); 4757 when(mPm.getPackageUidAsUser(pkg, 10)).thenReturn(uidList10[0]); 4758 ApplicationInfo info = new ApplicationInfo(); 4759 info.targetSdkVersion = Build.VERSION_CODES.Q; 4760 when(mPm.getApplicationInfoAsUser(eq(pkg), anyInt(), anyInt())).thenReturn(info); 4761 4762 mHelper.onPackagesChanged(false, 0, pkgList, uidList0); 4763 mHelper.onPackagesChanged(false, 10, pkgList, uidList10); 4764 4765 assertEquals(user0Importance, 4766 mHelper.getNotificationChannel(pkg, uidList0[0], channelId, false).getImportance()); 4767 assertEquals(user10Importance, mHelper.getNotificationChannel( 4768 pkg, uidList10[0], channelId, false).getImportance()); 4769 } 4770 4771 @Test testGetConversationNotificationChannel()4772 public void testGetConversationNotificationChannel() { 4773 String conversationId = "friend"; 4774 4775 NotificationChannel parent = 4776 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); 4777 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, 4778 UID_O, false); 4779 4780 NotificationChannel friend = new NotificationChannel(String.format( 4781 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId), 4782 "messages", IMPORTANCE_DEFAULT); 4783 friend.setConversationId(parent.getId(), conversationId); 4784 mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, 4785 UID_O, false); 4786 4787 compareChannelsParentChild(parent, mHelper.getConversationNotificationChannel( 4788 PKG_O, UID_O, parent.getId(), conversationId, false, false), conversationId); 4789 } 4790 4791 @Test testGetNotificationChannel_conversationProvidedByNotCustomizedYet()4792 public void testGetNotificationChannel_conversationProvidedByNotCustomizedYet() { 4793 String conversationId = "friend"; 4794 4795 NotificationChannel parent = 4796 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); 4797 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, 4798 UID_O, false); 4799 4800 compareChannels(parent, mHelper.getConversationNotificationChannel( 4801 PKG_O, UID_O, parent.getId(), conversationId, true, false)); 4802 } 4803 4804 @Test testConversationNotificationChannelsRequireParents()4805 public void testConversationNotificationChannelsRequireParents() { 4806 String parentId = "does not exist"; 4807 String conversationId = "friend"; 4808 4809 NotificationChannel friend = new NotificationChannel(String.format( 4810 CONVERSATION_CHANNEL_ID_FORMAT, parentId, conversationId), 4811 "messages", IMPORTANCE_DEFAULT); 4812 friend.setConversationId(parentId, conversationId); 4813 4814 try { 4815 mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, 4816 UID_O, false); 4817 fail("allowed creation of conversation channel without a parent"); 4818 } catch (IllegalArgumentException e) { 4819 // good 4820 } 4821 } 4822 4823 @Test testPlaceholderConversationId_shortcutRequired()4824 public void testPlaceholderConversationId_shortcutRequired() throws Exception { 4825 final String xml = "<ranking version=\"1\">\n" 4826 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" 4827 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"foo:placeholder_id\"/>" 4828 + "</package>" 4829 + "</ranking>"; 4830 TypedXmlPullParser parser = Xml.newFastPullParser(); 4831 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4832 null); 4833 parser.nextTag(); 4834 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4835 4836 assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true)); 4837 } 4838 4839 @Test testNormalConversationId_shortcutRequired()4840 public void testNormalConversationId_shortcutRequired() throws Exception { 4841 final String xml = "<ranking version=\"1\">\n" 4842 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" 4843 + "<channel id=\"id\" name=\"hi\" importance=\"3\" conv_id=\"other\"/>" 4844 + "</package>" 4845 + "</ranking>"; 4846 TypedXmlPullParser parser = Xml.newFastPullParser(); 4847 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4848 null); 4849 parser.nextTag(); 4850 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4851 4852 assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true)); 4853 } 4854 4855 @Test testNoConversationId_shortcutRequired()4856 public void testNoConversationId_shortcutRequired() throws Exception { 4857 final String xml = "<ranking version=\"1\">\n" 4858 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" 4859 + "<channel id=\"id\" name=\"hi\" importance=\"3\"/>" 4860 + "</package>" 4861 + "</ranking>"; 4862 TypedXmlPullParser parser = Xml.newFastPullParser(); 4863 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4864 null); 4865 parser.nextTag(); 4866 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4867 4868 assertNotNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true)); 4869 } 4870 4871 @Test testDeleted_noTime()4872 public void testDeleted_noTime() throws Exception { 4873 final String xml = "<ranking version=\"1\">\n" 4874 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" 4875 + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\"/>" 4876 + "</package>" 4877 + "</ranking>"; 4878 TypedXmlPullParser parser = Xml.newFastPullParser(); 4879 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4880 null); 4881 parser.nextTag(); 4882 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4883 4884 assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, "id", true)); 4885 } 4886 4887 @Test testDeleted_twice()4888 public void testDeleted_twice() throws Exception { 4889 mHelper.createNotificationChannel( 4890 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, 4891 UID_P, false); 4892 4893 assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", 4894 UID_P, false)); 4895 assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", 4896 UID_P, false)); 4897 } 4898 4899 @Test testDeleted_recentTime()4900 public void testDeleted_recentTime() throws Exception { 4901 mHelper.createNotificationChannel( 4902 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, 4903 UID_P, false); 4904 mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", UID_P, false); 4905 NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); 4906 assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs())); 4907 assertTrue(nc1.isDeleted()); 4908 4909 ByteArrayOutputStream baos = writeXmlAndPurge(PKG_P, UID_P, false, 4910 USER_SYSTEM, "id", NotificationChannel.DEFAULT_CHANNEL_ID); 4911 4912 TypedXmlPullParser parser = Xml.newFastPullParser(); 4913 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 4914 null); 4915 parser.nextTag(); 4916 mHelper.readXml(parser, true, USER_SYSTEM); 4917 4918 NotificationChannel nc = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); 4919 assertTrue(DateUtils.isToday(nc.getDeletedTimeMs())); 4920 assertTrue(nc.isDeleted()); 4921 } 4922 4923 @Test testUnDelete_time()4924 public void testUnDelete_time() throws Exception { 4925 mHelper.createNotificationChannel( 4926 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, 4927 UID_P, false); 4928 mHelper.deleteNotificationChannel(PKG_P, UID_P, "id", UID_P, false); 4929 NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); 4930 assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs())); 4931 assertTrue(nc1.isDeleted()); 4932 4933 mHelper.createNotificationChannel( 4934 PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false, 4935 UID_P, false); 4936 nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true); 4937 assertEquals(-1, nc1.getDeletedTimeMs()); 4938 assertFalse(nc1.isDeleted()); 4939 } 4940 4941 @Test testDeleted_longTime()4942 public void testDeleted_longTime() throws Exception { 4943 long time = System.currentTimeMillis() - (DateUtils.DAY_IN_MILLIS * 30); 4944 4945 final String xml = "<ranking version=\"1\">\n" 4946 + "<package name=\"" + PKG_O + "\" uid=\"" + UID_O + "\" >\n" 4947 + "<channel id=\"id\" name=\"hi\" importance=\"3\" deleted=\"true\" del_time=\"" 4948 + time + "\"/>" 4949 + "</package>" 4950 + "</ranking>"; 4951 TypedXmlPullParser parser = Xml.newFastPullParser(); 4952 parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), 4953 null); 4954 parser.nextTag(); 4955 mHelper.readXml(parser, false, UserHandle.USER_ALL); 4956 4957 NotificationChannel nc = mHelper.getNotificationChannel(PKG_O, UID_O, "id", true); 4958 assertNull(nc); 4959 } 4960 4961 @Test testGetConversations_all()4962 public void testGetConversations_all() { 4963 String convoId = "convo"; 4964 NotificationChannel messages = 4965 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 4966 mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, 4967 UID_O, false); 4968 NotificationChannel calls = 4969 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); 4970 mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, 4971 UID_O, false); 4972 NotificationChannel p = 4973 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT); 4974 mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, 4975 UID_P, false); 4976 4977 NotificationChannel channel = 4978 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); 4979 channel.setConversationId(messages.getId(), convoId); 4980 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, 4981 UID_O, false); 4982 4983 NotificationChannel diffConvo = 4984 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); 4985 diffConvo.setConversationId(p.getId(), "different convo"); 4986 mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false, 4987 UID_O, false); 4988 4989 NotificationChannel channel2 = 4990 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); 4991 channel2.setConversationId(calls.getId(), convoId); 4992 channel2.setImportantConversation(true); 4993 mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false, 4994 SYSTEM_UID, true); 4995 4996 List<ConversationChannelWrapper> convos = 4997 mHelper.getConversations(IntArray.wrap(new int[] {0}), false); 4998 4999 assertEquals(3, convos.size()); 5000 assertTrue(conversationWrapperContainsChannel(convos, channel)); 5001 assertTrue(conversationWrapperContainsChannel(convos, diffConvo)); 5002 assertTrue(conversationWrapperContainsChannel(convos, channel2)); 5003 } 5004 5005 @Test testGetConversations_multiUser()5006 public void testGetConversations_multiUser() { 5007 String convoId = "convo"; 5008 NotificationChannel messages = 5009 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5010 mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, 5011 UID_O, false); 5012 5013 NotificationChannel messagesUser10 = 5014 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5015 mHelper.createNotificationChannel( 5016 PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesUser10, true, false, 5017 UID_O + UserHandle.PER_USER_RANGE, false); 5018 5019 NotificationChannel messagesFromB = 5020 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); 5021 messagesFromB.setConversationId(messages.getId(), "different convo"); 5022 mHelper.createNotificationChannel(PKG_O, UID_O, messagesFromB, true, false, UID_O, false); 5023 5024 NotificationChannel messagesFromBUser10 = 5025 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); 5026 messagesFromBUser10.setConversationId(messagesUser10.getId(), "different convo"); 5027 mHelper.createNotificationChannel( 5028 PKG_O, UID_O + UserHandle.PER_USER_RANGE, messagesFromBUser10, true, false, 5029 UID_O + UserHandle.PER_USER_RANGE, false); 5030 5031 5032 List<ConversationChannelWrapper> convos = 5033 mHelper.getConversations(IntArray.wrap(new int[] {0}), false); 5034 5035 assertEquals(1, convos.size()); 5036 assertTrue(conversationWrapperContainsChannel(convos, messagesFromB)); 5037 5038 convos = 5039 mHelper.getConversations(IntArray.wrap(new int[] {0, UserHandle.getUserId(UID_O + UserHandle.PER_USER_RANGE)}), false); 5040 5041 assertEquals(2, convos.size()); 5042 assertTrue(conversationWrapperContainsChannel(convos, messagesFromB)); 5043 assertTrue(conversationWrapperContainsChannel(convos, messagesFromBUser10)); 5044 } 5045 5046 @Test testGetConversations_notDemoted()5047 public void testGetConversations_notDemoted() { 5048 String convoId = "convo"; 5049 NotificationChannel messages = 5050 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5051 mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); 5052 NotificationChannel calls = 5053 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); 5054 mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); 5055 NotificationChannel p = 5056 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT); 5057 mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, UID_O, false); 5058 5059 NotificationChannel channel = 5060 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); 5061 channel.setConversationId(messages.getId(), convoId); 5062 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5063 5064 NotificationChannel diffConvo = 5065 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); 5066 diffConvo.setConversationId(p.getId(), "different convo"); 5067 diffConvo.setDemoted(true); 5068 mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, true, false, UID_P, false); 5069 5070 NotificationChannel channel2 = 5071 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); 5072 channel2.setConversationId(calls.getId(), convoId); 5073 channel2.setImportantConversation(true); 5074 mHelper.createNotificationChannel(PKG_O, UID_O, channel2, false, false, 5075 SYSTEM_UID, true); 5076 5077 List<ConversationChannelWrapper> convos = 5078 mHelper.getConversations(IntArray.wrap(new int[] {0}), false); 5079 5080 assertEquals(2, convos.size()); 5081 assertTrue(conversationWrapperContainsChannel(convos, channel)); 5082 assertFalse(conversationWrapperContainsChannel(convos, diffConvo)); 5083 assertTrue(conversationWrapperContainsChannel(convos, channel2)); 5084 } 5085 5086 @Test testGetConversations_onlyImportant()5087 public void testGetConversations_onlyImportant() { 5088 String convoId = "convo"; 5089 NotificationChannel messages = 5090 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5091 mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); 5092 NotificationChannel calls = 5093 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); 5094 mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); 5095 NotificationChannel p = 5096 new NotificationChannel("p calls", "Calls", IMPORTANCE_DEFAULT); 5097 mHelper.createNotificationChannel(PKG_P, UID_P, p, true, false, UID_P, false); 5098 5099 NotificationChannel channel = 5100 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); 5101 channel.setConversationId(messages.getId(), convoId); 5102 channel.setImportantConversation(true); 5103 mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false, UID_O, false); 5104 5105 NotificationChannel diffConvo = 5106 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); 5107 diffConvo.setConversationId(p.getId(), "different convo"); 5108 diffConvo.setImportantConversation(true); 5109 mHelper.createNotificationChannel(PKG_P, UID_P, diffConvo, false, false, 5110 SYSTEM_UID, true); 5111 5112 NotificationChannel channel2 = 5113 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); 5114 channel2.setConversationId(calls.getId(), convoId); 5115 mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false); 5116 5117 List<ConversationChannelWrapper> convos = 5118 mHelper.getConversations(IntArray.wrap(new int[] {0}), true); 5119 5120 assertEquals(2, convos.size()); 5121 assertTrue(conversationWrapperContainsChannel(convos, channel)); 5122 assertTrue(conversationWrapperContainsChannel(convos, diffConvo)); 5123 assertFalse(conversationWrapperContainsChannel(convos, channel2)); 5124 } 5125 5126 @Test testGetConversations_parentDeleted()5127 public void testGetConversations_parentDeleted() { 5128 String convoId = "convo"; 5129 NotificationChannel messages = 5130 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5131 mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); 5132 5133 NotificationChannel channel = 5134 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); 5135 channel.setConversationId(messages.getId(), convoId); 5136 channel.setImportantConversation(true); 5137 mHelper.createNotificationChannel(PKG_O, UID_O, channel, false, false, 5138 SYSTEM_UID, true); 5139 5140 mHelper.permanentlyDeleteNotificationChannel(PKG_O, UID_O, "messages"); 5141 5142 List<ConversationChannelWrapper> convos = 5143 mHelper.getConversations(IntArray.wrap(new int[] {0}), true); 5144 5145 assertEquals(1, convos.size()); 5146 assertTrue(conversationWrapperContainsChannel(convos, channel)); 5147 } 5148 conversationWrapperContainsChannel(List<ConversationChannelWrapper> list, NotificationChannel expected)5149 private boolean conversationWrapperContainsChannel(List<ConversationChannelWrapper> list, 5150 NotificationChannel expected) { 5151 for (ConversationChannelWrapper ccw : list) { 5152 if (ccw.getNotificationChannel().equals(expected)) { 5153 return true; 5154 } 5155 } 5156 5157 return false; 5158 } 5159 5160 @Test testGetConversations_invalidPkg()5161 public void testGetConversations_invalidPkg() { 5162 assertThat(mHelper.getConversations("bad", 1)).isEmpty(); 5163 } 5164 5165 @Test testGetConversations_noConversations()5166 public void testGetConversations_noConversations() { 5167 NotificationChannel channel = 5168 new NotificationChannel("not_convo", "not_convo", IMPORTANCE_DEFAULT); 5169 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5170 5171 assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); 5172 } 5173 5174 @Test testGetConversations_noDisabledGroups()5175 public void testGetConversations_noDisabledGroups() { 5176 NotificationChannelGroup group = new NotificationChannelGroup("a", "a"); 5177 group.setBlocked(true); 5178 mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, false, SYSTEM_UID, true); 5179 NotificationChannel parent = new NotificationChannel("parent", "p", 1); 5180 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); 5181 5182 NotificationChannel channel = 5183 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT); 5184 channel.setConversationId("parent", "convo"); 5185 channel.setGroup(group.getId()); 5186 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5187 5188 assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); 5189 } 5190 5191 @Test testGetConversations_noDeleted()5192 public void testGetConversations_noDeleted() { 5193 NotificationChannel parent = new NotificationChannel("parent", "p", 1); 5194 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); 5195 NotificationChannel channel = 5196 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT); 5197 channel.setConversationId("parent", "convo"); 5198 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5199 mHelper.deleteNotificationChannel(PKG_O, UID_O, channel.getId(), UID_O, false); 5200 5201 assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); 5202 } 5203 5204 @Test testGetConversations_noDemoted()5205 public void testGetConversations_noDemoted() { 5206 NotificationChannel parent = new NotificationChannel("parent", "p", 1); 5207 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); 5208 NotificationChannel channel = 5209 new NotificationChannel("convo", "convo", IMPORTANCE_DEFAULT); 5210 channel.setConversationId("parent", "convo"); 5211 channel.setDemoted(true); 5212 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5213 5214 assertThat(mHelper.getConversations(PKG_O, UID_O)).isEmpty(); 5215 } 5216 5217 @Test testGetConversations()5218 public void testGetConversations() { 5219 NotificationChannelGroup group = new NotificationChannelGroup("acct", "account_name"); 5220 mHelper.createNotificationChannelGroup(PKG_O, UID_O, group, true, UID_O, false); 5221 5222 NotificationChannel messages = 5223 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5224 messages.setGroup(group.getId()); 5225 mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); 5226 NotificationChannel calls = 5227 new NotificationChannel("calls", "Calls", IMPORTANCE_HIGH); 5228 mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); 5229 5230 NotificationChannel channel = 5231 new NotificationChannel("A person", "A lovely person", IMPORTANCE_DEFAULT); 5232 channel.setGroup(group.getId()); 5233 channel.setConversationId(messages.getId(), channel.getName().toString()); 5234 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5235 5236 NotificationChannel channel2 = 5237 new NotificationChannel("B person", "B fabulous person", IMPORTANCE_DEFAULT); 5238 channel2.setConversationId(calls.getId(), channel2.getName().toString()); 5239 mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false); 5240 5241 Map<String, NotificationChannel> expected = new HashMap<>(); 5242 expected.put(channel.getId(), channel); 5243 expected.put(channel2.getId(), channel2); 5244 5245 Map<String, CharSequence> expectedGroup = new HashMap<>(); 5246 expectedGroup.put(channel.getId(), group.getName()); 5247 expectedGroup.put(channel2.getId(), null); 5248 5249 Map<String, CharSequence> expectedParentLabel= new HashMap<>(); 5250 expectedParentLabel.put(channel.getId(), messages.getName()); 5251 expectedParentLabel.put(channel2.getId(), calls.getName()); 5252 5253 ArrayList<ConversationChannelWrapper> convos = mHelper.getConversations(PKG_O, UID_O); 5254 assertThat(convos).hasSize(2); 5255 5256 for (ConversationChannelWrapper convo : convos) { 5257 assertThat(convo.getNotificationChannel()) 5258 .isEqualTo(expected.get(convo.getNotificationChannel().getId())); 5259 assertThat(convo.getParentChannelLabel()) 5260 .isEqualTo(expectedParentLabel.get(convo.getNotificationChannel().getId())); 5261 assertThat(convo.getGroupLabel()) 5262 .isEqualTo(expectedGroup.get(convo.getNotificationChannel().getId())); 5263 } 5264 } 5265 5266 @Test testDeleteConversations()5267 public void testDeleteConversations() { 5268 String convoId = "convo"; 5269 String convoIdC = "convoC"; 5270 NotificationChannel messages = 5271 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5272 mHelper.createNotificationChannel(PKG_O, UID_O, messages, true, false, UID_O, false); 5273 NotificationChannel calls = 5274 new NotificationChannel("calls", "Calls", IMPORTANCE_DEFAULT); 5275 mHelper.createNotificationChannel(PKG_O, UID_O, calls, true, false, UID_O, false); 5276 5277 NotificationChannel channel = 5278 new NotificationChannel("A person msgs", "messages from A", IMPORTANCE_DEFAULT); 5279 channel.setConversationId(messages.getId(), convoId); 5280 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5281 5282 NotificationChannel noMatch = 5283 new NotificationChannel("B person msgs", "messages from B", IMPORTANCE_DEFAULT); 5284 noMatch.setConversationId(messages.getId(), "different convo"); 5285 mHelper.createNotificationChannel(PKG_O, UID_O, noMatch, true, false, UID_O, false); 5286 5287 NotificationChannel channel2 = 5288 new NotificationChannel("A person calls", "calls from A", IMPORTANCE_DEFAULT); 5289 channel2.setConversationId(calls.getId(), convoId); 5290 mHelper.createNotificationChannel(PKG_O, UID_O, channel2, true, false, UID_O, false); 5291 5292 NotificationChannel channel3 = 5293 new NotificationChannel("C person msgs", "msgs from C", IMPORTANCE_DEFAULT); 5294 channel3.setConversationId(messages.getId(), convoIdC); 5295 mHelper.createNotificationChannel(PKG_O, UID_O, channel3, true, false, UID_O, false); 5296 5297 assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false)); 5298 assertEquals(channel2, 5299 mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false)); 5300 List<String> deleted = mHelper.deleteConversations(PKG_O, UID_O, Set.of(convoId, convoIdC), 5301 UID_O, false); 5302 assertEquals(3, deleted.size()); 5303 5304 assertEquals(messages, 5305 mHelper.getNotificationChannel(PKG_O, UID_O, messages.getId(), false)); 5306 assertEquals(noMatch, 5307 mHelper.getNotificationChannel(PKG_O, UID_O, noMatch.getId(), false)); 5308 5309 assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), false)); 5310 assertNull(mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), false)); 5311 assertEquals(channel, mHelper.getNotificationChannel(PKG_O, UID_O, channel.getId(), true)); 5312 assertEquals(channel2, 5313 mHelper.getNotificationChannel(PKG_O, UID_O, channel2.getId(), true)); 5314 5315 assertEquals(9, mLogger.getCalls().size()); 5316 assertEquals( 5317 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED, 5318 mLogger.get(0).event); // Channel messages 5319 assertEquals( 5320 NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_CREATED, 5321 mLogger.get(1).event); // Channel calls 5322 assertEquals( 5323 NotificationChannelLogger.NotificationChannelEvent 5324 .NOTIFICATION_CHANNEL_CONVERSATION_CREATED, 5325 mLogger.get(2).event); // Channel channel - Conversation A person msgs 5326 assertEquals( 5327 NotificationChannelLogger.NotificationChannelEvent 5328 .NOTIFICATION_CHANNEL_CONVERSATION_CREATED, 5329 mLogger.get(3).event); // Channel noMatch - Conversation B person msgs 5330 assertEquals( 5331 NotificationChannelLogger.NotificationChannelEvent 5332 .NOTIFICATION_CHANNEL_CONVERSATION_CREATED, 5333 mLogger.get(4).event); // Channel channel2 - Conversation A person calls 5334 assertEquals( 5335 NotificationChannelLogger.NotificationChannelEvent 5336 .NOTIFICATION_CHANNEL_CONVERSATION_CREATED, 5337 mLogger.get(5).event); // Channel channel3 - Conversation C person msgs 5338 assertEquals( 5339 NotificationChannelLogger.NotificationChannelEvent 5340 .NOTIFICATION_CHANNEL_CONVERSATION_DELETED, 5341 mLogger.get(6).event); // Delete Channel channel - Conversation A person msgs 5342 assertEquals( 5343 NotificationChannelLogger.NotificationChannelEvent 5344 .NOTIFICATION_CHANNEL_CONVERSATION_DELETED, 5345 mLogger.get(7).event); // Delete Channel channel2 - Conversation A person calls 5346 assertEquals( 5347 NotificationChannelLogger.NotificationChannelEvent 5348 .NOTIFICATION_CHANNEL_CONVERSATION_DELETED, 5349 mLogger.get(8).event); // Delete Channel channel3 - Conversation C person msgs 5350 } 5351 5352 @Test testUpdateConversationParent_updatesConversations()5353 public void testUpdateConversationParent_updatesConversations() { 5354 SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver() 5355 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true); 5356 5357 NotificationChannel parent = 5358 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5359 mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true, 5360 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5361 NotificationChannel convoA = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT); 5362 convoA.setConversationId(parent.getId(), "A"); 5363 mHelper.createNotificationChannel(PKG_O, UID_O, convoA, /* fromTargetApp= */ true, 5364 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5365 NotificationChannel convoB = new NotificationChannel("B", "With B", IMPORTANCE_DEFAULT); 5366 convoB.setConversationId(parent.getId(), "B"); 5367 mHelper.createNotificationChannel(PKG_O, UID_O, convoB, /* fromTargetApp= */ true, 5368 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5369 assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "messages", /* includeDeleted= */ 5370 false).shouldVibrate()).isFalse(); 5371 assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A", 5372 /* includeDeleted= */ false).shouldVibrate()).isFalse(); 5373 assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "B", 5374 /* includeDeleted= */ false).shouldVibrate()).isFalse(); 5375 mLogger.clear(); 5376 5377 NotificationChannel parentUpdate = cloneChannel(parent); 5378 parentUpdate.enableVibration(true); 5379 mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, UID_O, 5380 /* fromSystemOrSystemUi= */ true); 5381 5382 assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "messages", 5383 /* includeDeleted= */ false).shouldVibrate()).isTrue(); 5384 assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A", 5385 /* includeDeleted= */ false).shouldVibrate()).isTrue(); 5386 assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "B", 5387 /* includeDeleted= */ false).shouldVibrate()).isTrue(); 5388 5389 // Verify that the changes to parent and children were logged. 5390 assertThat(mLogger.getCalls()).containsExactly( 5391 new NotificationChannelLoggerFake.CallRecord( 5392 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "messages"), 5393 new NotificationChannelLoggerFake.CallRecord( 5394 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "A"), 5395 new NotificationChannelLoggerFake.CallRecord( 5396 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "B")) 5397 .inOrder(); 5398 } 5399 5400 @Test testUpdateConversationParent_updatesUnlockedFields()5401 public void testUpdateConversationParent_updatesUnlockedFields() { 5402 SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver() 5403 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true); 5404 5405 NotificationChannel parent = 5406 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5407 mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true, 5408 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5409 NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT); 5410 convo.setConversationId(parent.getId(), "A"); 5411 mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true, 5412 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5413 NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5414 convo.getId(), /* includeDeleted= */ false); 5415 assertThat(originalChild.canBypassDnd()).isFalse(); 5416 assertThat(originalChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_NO_OVERRIDE); 5417 assertThat(originalChild.getImportance()).isEqualTo(IMPORTANCE_DEFAULT); 5418 assertThat(originalChild.shouldShowLights()).isFalse(); 5419 assertThat(originalChild.getSound()).isEqualTo(DEFAULT_SOUND_URI); 5420 assertThat(originalChild.shouldVibrate()).isFalse(); 5421 assertThat(originalChild.canShowBadge()).isTrue(); 5422 assertThat(originalChild.getAllowBubbles()).isEqualTo(DEFAULT_ALLOW_BUBBLE); 5423 5424 NotificationChannel parentUpdate = cloneChannel(parent); 5425 parentUpdate.setBypassDnd(true); 5426 parentUpdate.setLockscreenVisibility(VISIBILITY_SECRET); 5427 parentUpdate.setImportance(IMPORTANCE_HIGH); 5428 parentUpdate.enableLights(true); 5429 parentUpdate.setSound(SOUND_URI, mAudioAttributes); 5430 parentUpdate.enableVibration(true); 5431 parentUpdate.setShowBadge(false); 5432 parentUpdate.setAllowBubbles(true); 5433 mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, 5434 UID_O, /* fromSystemOrSystemUi= */ true); 5435 5436 NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5437 "A", /* includeDeleted= */ false); 5438 assertThat(updatedChild.canBypassDnd()).isTrue(); 5439 assertThat(updatedChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_SECRET); 5440 assertThat(updatedChild.getImportance()).isEqualTo(IMPORTANCE_HIGH); 5441 assertThat(updatedChild.shouldShowLights()).isTrue(); 5442 assertThat(updatedChild.getSound()).isEqualTo(SOUND_URI); 5443 assertThat(updatedChild.shouldVibrate()).isTrue(); 5444 assertThat(updatedChild.canShowBadge()).isFalse(); 5445 assertThat(updatedChild.getAllowBubbles()).isEqualTo(ALLOW_BUBBLE_ON); 5446 } 5447 5448 @Test testUpdateConversationParent_doesNotUpdateLockedFields()5449 public void testUpdateConversationParent_doesNotUpdateLockedFields() { 5450 SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver() 5451 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true); 5452 NotificationChannel parent = 5453 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5454 mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true, 5455 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5456 NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT); 5457 convo.setConversationId(parent.getId(), "A"); 5458 mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true, 5459 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5460 // Directly update the child to lock every field. 5461 // Normally this would be the result of one or more "fromUser" updates with modified fields. 5462 convo.lockFields( 5463 USER_LOCKED_PRIORITY | USER_LOCKED_VISIBILITY | USER_LOCKED_IMPORTANCE 5464 | USER_LOCKED_LIGHTS | USER_LOCKED_VIBRATION | USER_LOCKED_SOUND 5465 | USER_LOCKED_SHOW_BADGE | USER_LOCKED_ALLOW_BUBBLE); 5466 mLogger.clear(); 5467 5468 NotificationChannel parentUpdate = cloneChannel(parent); 5469 parentUpdate.setBypassDnd(true); 5470 parentUpdate.setLockscreenVisibility(VISIBILITY_SECRET); 5471 parentUpdate.setImportance(IMPORTANCE_HIGH); 5472 parentUpdate.enableLights(true); 5473 parentUpdate.setSound(SOUND_URI, mAudioAttributes); 5474 parentUpdate.enableVibration(true); 5475 parentUpdate.setShowBadge(false); 5476 parentUpdate.setAllowBubbles(true); 5477 mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, 5478 UID_O, /* fromSystemOrSystemUi= */ true); 5479 5480 NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5481 "A", /* includeDeleted= */ false); 5482 assertThat(updatedChild.canBypassDnd()).isFalse(); 5483 assertThat(updatedChild.getLockscreenVisibility()).isEqualTo(VISIBILITY_NO_OVERRIDE); 5484 assertThat(updatedChild.getImportance()).isEqualTo(IMPORTANCE_DEFAULT); 5485 assertThat(updatedChild.shouldShowLights()).isFalse(); 5486 assertThat(updatedChild.getSound()).isEqualTo(DEFAULT_SOUND_URI); 5487 assertThat(updatedChild.shouldVibrate()).isFalse(); 5488 assertThat(updatedChild.canShowBadge()).isTrue(); 5489 assertThat(updatedChild.getAllowBubbles()).isEqualTo(DEFAULT_ALLOW_BUBBLE); 5490 5491 // Verify that only the changes to the parent were logged. 5492 assertThat(mLogger.getCalls()).containsExactly( 5493 new NotificationChannelLoggerFake.CallRecord( 5494 NOTIFICATION_CHANNEL_UPDATED_BY_USER, "messages")); 5495 } 5496 5497 @Test testUpdateConversationParent_updatesDemotedConversation()5498 public void testUpdateConversationParent_updatesDemotedConversation() { 5499 SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver() 5500 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true); 5501 NotificationChannel parent = 5502 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5503 mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true, 5504 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5505 NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT); 5506 convo.setConversationId(parent.getId(), "A"); 5507 convo.setDemoted(true); 5508 mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true, 5509 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5510 NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5511 convo.getId(), /* includeDeleted= */ false); 5512 assertThat(originalChild.shouldVibrate()).isFalse(); 5513 5514 NotificationChannel parentUpdate = cloneChannel(parent); 5515 parentUpdate.enableVibration(true); 5516 mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, 5517 UID_O, /* fromSystemOrSystemUi= */ true); 5518 5519 NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5520 "A", /* includeDeleted= */ false); 5521 assertThat(updatedChild.shouldVibrate()).isTrue(); 5522 } 5523 5524 @Test testUpdateConversationParent_updatesDeletedConversation()5525 public void testUpdateConversationParent_updatesDeletedConversation() { 5526 SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver() 5527 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, true); 5528 NotificationChannel parent = 5529 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5530 mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true, 5531 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5532 NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT); 5533 convo.setConversationId(parent.getId(), "A"); 5534 mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true, 5535 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5536 mHelper.deleteNotificationChannel(PKG_O, UID_O, "A", UID_O, 5537 /* fromSystemOrSystemUi= */ false); 5538 assertThat(mHelper.getNotificationChannel(PKG_O, UID_O, "A", 5539 /* includeDeleted= */ false)).isNull(); 5540 5541 NotificationChannel parentUpdate = cloneChannel(parent); 5542 parentUpdate.enableVibration(true); 5543 mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, 5544 UID_O, /* fromSystemOrSystemUi= */ true); 5545 5546 NotificationChannel updatedChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5547 "A", /* includeDeleted= */ true); 5548 assertThat(updatedChild.shouldVibrate()).isTrue(); 5549 } 5550 5551 @Test testUpdateConversationParent_flagOff_doesNotUpdateConversations()5552 public void testUpdateConversationParent_flagOff_doesNotUpdateConversations() { 5553 SystemUiSystemPropertiesFlags.TEST_RESOLVER = new TestableFlagResolver() 5554 .setFlagOverride(PROPAGATE_CHANNEL_UPDATES_TO_CONVERSATIONS, false); 5555 NotificationChannel parent = 5556 new NotificationChannel("messages", "Messages", IMPORTANCE_DEFAULT); 5557 mHelper.createNotificationChannel(PKG_O, UID_O, parent, /* fromTargetApp= */ true, 5558 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5559 NotificationChannel convo = new NotificationChannel("A", "With A", IMPORTANCE_DEFAULT); 5560 convo.setConversationId(parent.getId(), "A"); 5561 mHelper.createNotificationChannel(PKG_O, UID_O, convo, /* fromTargetApp= */ true, 5562 /* hasDndAccess= */ false, UID_O, /* fromSystemOrSystemUi= */ false); 5563 NotificationChannel originalChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5564 convo.getId(), /* includeDeleted= */ false); 5565 assertThat(originalChild.shouldVibrate()).isFalse(); 5566 5567 NotificationChannel parentUpdate = cloneChannel(parent); 5568 parentUpdate.enableVibration(true); 5569 mHelper.updateNotificationChannel(PKG_O, UID_O, parentUpdate, /* fromUser= */ true, 5570 UID_O, /* fromSystemOrSystemUi= */ true); 5571 5572 NotificationChannel untouchedChild = mHelper.getNotificationChannel(PKG_O, UID_O, 5573 "A", /* includeDeleted= */ false); 5574 assertThat(untouchedChild.shouldVibrate()).isFalse(); 5575 } 5576 5577 @Test testInvalidMessageSent()5578 public void testInvalidMessageSent() { 5579 // create package preferences 5580 mHelper.canShowBadge(PKG_P, UID_P); 5581 5582 // check default value 5583 assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P)); 5584 5585 // change it 5586 mHelper.setInvalidMessageSent(PKG_P, UID_P); 5587 assertTrue(mHelper.isInInvalidMsgState(PKG_P, UID_P)); 5588 assertTrue(mHelper.hasSentInvalidMsg(PKG_P, UID_P)); 5589 } 5590 5591 @Test testValidMessageSent()5592 public void testValidMessageSent() { 5593 // create package preferences 5594 mHelper.canShowBadge(PKG_P, UID_P); 5595 5596 // get into the bad state 5597 mHelper.setInvalidMessageSent(PKG_P, UID_P); 5598 5599 // and then fix it 5600 mHelper.setValidMessageSent(PKG_P, UID_P); 5601 5602 assertTrue(mHelper.hasSentValidMsg(PKG_P, UID_P)); 5603 assertFalse(mHelper.isInInvalidMsgState(PKG_P, UID_P)); 5604 } 5605 5606 @Test testUserDemotedInvalidMsgApp()5607 public void testUserDemotedInvalidMsgApp() { 5608 // create package preferences 5609 mHelper.canShowBadge(PKG_P, UID_P); 5610 5611 // demotion means nothing before msg notif sent 5612 mHelper.setInvalidMsgAppDemoted(PKG_P, UID_P, true); 5613 assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P)); 5614 5615 // it's valid when incomplete msgs have been sent 5616 mHelper.setInvalidMessageSent(PKG_P, UID_P); 5617 assertTrue(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P)); 5618 5619 // and is invalid once complete msgs are sent 5620 mHelper.setValidMessageSent(PKG_P, UID_P); 5621 assertFalse(mHelper.hasUserDemotedInvalidMsgApp(PKG_P, UID_P)); 5622 } 5623 5624 @Test testValidBubbleSent()5625 public void testValidBubbleSent() { 5626 // create package preferences 5627 mHelper.canShowBadge(PKG_P, UID_P); 5628 // false by default 5629 assertFalse(mHelper.hasSentValidBubble(PKG_P, UID_P)); 5630 5631 // set something valid was sent 5632 mHelper.setValidBubbleSent(PKG_P, UID_P); 5633 assertTrue(mHelper.hasSentValidBubble(PKG_P, UID_P)); 5634 } 5635 5636 @Test testPullPackageChannelPreferencesStats()5637 public void testPullPackageChannelPreferencesStats() throws InvalidProtocolBufferException { 5638 String channelId = "parent"; 5639 String name = "messages"; 5640 NotificationChannel fodderA = new NotificationChannel("a", "a", IMPORTANCE_LOW); 5641 mHelper.createNotificationChannel(PKG_O, UID_O, fodderA, true, false, UID_O, false); 5642 NotificationChannel channel = 5643 new NotificationChannel(channelId, name, IMPORTANCE_DEFAULT); 5644 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5645 NotificationChannel fodderB = new NotificationChannel("b", "b", IMPORTANCE_HIGH); 5646 mHelper.createNotificationChannel(PKG_O, UID_O, fodderB, true, false, UID_O, false); 5647 5648 ArrayList<StatsEvent> events = new ArrayList<>(); 5649 mHelper.pullPackageChannelPreferencesStats(events); 5650 5651 // number of channels with preferences should be 3 total 5652 assertEquals("expected number of events", 3, events.size()); 5653 for (StatsEvent ev : events) { 5654 // all of these events should be of PackageNotificationChannelPreferences type, 5655 // and therefore we expect the atom to have this field. 5656 AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); 5657 assertTrue(atom.hasPackageNotificationChannelPreferences()); 5658 PackageNotificationChannelPreferences p = 5659 atom.getPackageNotificationChannelPreferences(); 5660 5661 // uid is shared across all channels; conversation & deleted are not set in any of 5662 // these channels; beyond that check individual channel properties 5663 assertEquals("uid", UID_O, p.getUid()); 5664 assertFalse("is conversation", p.getIsConversation()); 5665 assertFalse("is deleted", p.getIsDeleted()); 5666 5667 String eventChannelId = p.getChannelId(); 5668 if (eventChannelId.equals(channelId)) { 5669 assertEquals("channel name", name, p.getChannelName()); 5670 assertEquals("importance", IMPORTANCE_DEFAULT, p.getImportance()); 5671 assertFalse("is conversation", p.getIsConversation()); 5672 } else if (eventChannelId.equals("a")) { 5673 assertEquals("channel name", "a", p.getChannelName()); 5674 assertEquals("importance", IMPORTANCE_LOW, p.getImportance()); 5675 } else { // b 5676 assertEquals("channel name", "b", p.getChannelName()); 5677 assertEquals("importance", IMPORTANCE_HIGH, p.getImportance()); 5678 } 5679 } 5680 } 5681 5682 @Test testPullPackageChannelPreferencesStats_one_to_one()5683 public void testPullPackageChannelPreferencesStats_one_to_one() 5684 throws InvalidProtocolBufferException { 5685 NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW); 5686 mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false, UID_O, false); 5687 NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_LOW); 5688 mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false, UID_O, false); 5689 NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH); 5690 mHelper.createNotificationChannel(PKG_O, UID_O, channelC, true, false, UID_O, false); 5691 5692 List<String> channels = new LinkedList<>(Arrays.asList("a", "b", "c")); 5693 5694 ArrayList<StatsEvent> events = new ArrayList<>(); 5695 mHelper.pullPackageChannelPreferencesStats(events); 5696 5697 assertEquals("total events", 3, events.size()); 5698 for (StatsEvent ev : events) { 5699 AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); 5700 assertTrue(atom.hasPackageNotificationChannelPreferences()); 5701 PackageNotificationChannelPreferences p = 5702 atom.getPackageNotificationChannelPreferences(); 5703 String id = p.getChannelId(); 5704 assertTrue("missing channel in the output", channels.contains(id)); 5705 channels.remove(id); 5706 } 5707 assertTrue("unexpected channel in output", channels.isEmpty()); 5708 } 5709 5710 @Test testPullPackageChannelPreferencesStats_conversation()5711 public void testPullPackageChannelPreferencesStats_conversation() 5712 throws InvalidProtocolBufferException { 5713 String conversationId = "friend"; 5714 5715 NotificationChannel parent = 5716 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); 5717 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); 5718 5719 String channelId = String.format( 5720 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), conversationId); 5721 String name = "conversation"; 5722 NotificationChannel friend = new NotificationChannel(channelId, 5723 name, IMPORTANCE_DEFAULT); 5724 friend.setConversationId(parent.getId(), conversationId); 5725 mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, UID_O, false); 5726 5727 ArrayList<StatsEvent> events = new ArrayList<>(); 5728 mHelper.pullPackageChannelPreferencesStats(events); 5729 5730 // In this case, we want to check the properties of the conversation channel (not parent) 5731 assertEquals("total events", 2, events.size()); 5732 for (StatsEvent ev : events) { 5733 AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); 5734 assertTrue(atom.hasPackageNotificationChannelPreferences()); 5735 PackageNotificationChannelPreferences p = 5736 atom.getPackageNotificationChannelPreferences(); 5737 5738 if (channelId.equals(p.getChannelId())) { 5739 assertTrue("isConversation should be true", p.getIsConversation()); 5740 assertFalse("not demoted", p.getIsDemotedConversation()); 5741 assertFalse("not important", p.getIsImportantConversation()); 5742 } 5743 } 5744 } 5745 5746 @Test testPullPackageChannelPreferencesStats_conversation_demoted()5747 public void testPullPackageChannelPreferencesStats_conversation_demoted() 5748 throws InvalidProtocolBufferException { 5749 NotificationChannel parent = 5750 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); 5751 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); 5752 String channelId = String.format( 5753 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend"); 5754 NotificationChannel friend = new NotificationChannel(channelId, 5755 "conversation", IMPORTANCE_DEFAULT); 5756 friend.setConversationId(parent.getId(), "friend"); 5757 friend.setDemoted(true); 5758 mHelper.createNotificationChannel(PKG_O, UID_O, friend, true, false, UID_O, false); 5759 5760 ArrayList<StatsEvent> events = new ArrayList<>(); 5761 mHelper.pullPackageChannelPreferencesStats(events); 5762 5763 assertEquals("total events", 2, events.size()); 5764 for (StatsEvent ev : events) { 5765 AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); 5766 assertTrue(atom.hasPackageNotificationChannelPreferences()); 5767 PackageNotificationChannelPreferences p = 5768 atom.getPackageNotificationChannelPreferences(); 5769 if (channelId.equals(p.getChannelId())) { 5770 assertTrue("isConversation should be true", p.getIsConversation()); 5771 assertTrue("is demoted", p.getIsDemotedConversation()); 5772 assertFalse("not important", p.getIsImportantConversation()); 5773 } 5774 } 5775 } 5776 5777 @Test testPullPackageChannelPreferencesStats_conversation_priority()5778 public void testPullPackageChannelPreferencesStats_conversation_priority() 5779 throws InvalidProtocolBufferException { 5780 NotificationChannel parent = 5781 new NotificationChannel("parent", "messages", IMPORTANCE_DEFAULT); 5782 mHelper.createNotificationChannel(PKG_O, UID_O, parent, true, false, UID_O, false); 5783 String channelId = String.format( 5784 CONVERSATION_CHANNEL_ID_FORMAT, parent.getId(), "friend"); 5785 NotificationChannel friend = new NotificationChannel(channelId, 5786 "conversation", IMPORTANCE_DEFAULT); 5787 friend.setConversationId(parent.getId(), "friend"); 5788 friend.setImportantConversation(true); 5789 mHelper.createNotificationChannel(PKG_O, UID_O, friend, false, false, SYSTEM_UID, true); 5790 5791 ArrayList<StatsEvent> events = new ArrayList<>(); 5792 mHelper.pullPackageChannelPreferencesStats(events); 5793 5794 assertEquals("total events", 2, events.size()); 5795 for (StatsEvent ev : events) { 5796 AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); 5797 assertTrue(atom.hasPackageNotificationChannelPreferences()); 5798 PackageNotificationChannelPreferences p = 5799 atom.getPackageNotificationChannelPreferences(); 5800 if (channelId.equals(p.getChannelId())) { 5801 assertTrue("isConversation should be true", p.getIsConversation()); 5802 assertFalse("not demoted", p.getIsDemotedConversation()); 5803 assertTrue("is important", p.getIsImportantConversation()); 5804 } 5805 } 5806 } 5807 5808 @Test testPullPackagePreferencesStats_postPermissionMigration()5809 public void testPullPackagePreferencesStats_postPermissionMigration() 5810 throws InvalidProtocolBufferException { 5811 // make sure there's at least one channel for each package we want to test 5812 NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); 5813 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channelA, true, false, 5814 UID_N_MR1, false); 5815 NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT); 5816 mHelper.createNotificationChannel(PKG_O, UID_O, channelB, true, false, UID_O, false); 5817 NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT); 5818 mHelper.createNotificationChannel(PKG_P, UID_P, channelC, true, false, UID_P, false); 5819 5820 // build a collection of app permissions that should be passed in and used 5821 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> appPermissions = new ArrayMap<>(); 5822 appPermissions.put(new Pair<>(UID_N_MR1, PKG_N_MR1), new Pair<>(true, false)); 5823 appPermissions.put(new Pair<>(UID_O, PKG_O), new Pair<>(false, true)); // in local prefs 5824 5825 // local preferences 5826 mHelper.canShowBadge(PKG_O, UID_O); 5827 mHelper.canShowBadge(PKG_P, UID_P); 5828 5829 // expected output. format: uid -> importance, as only uid (and not package name) 5830 // is in PackageNotificationPreferences 5831 ArrayMap<Integer, Pair<Integer, Boolean>> expected = new ArrayMap<>(); 5832 expected.put(UID_N_MR1, new Pair<>(IMPORTANCE_DEFAULT, false)); 5833 expected.put(UID_O, new Pair<>(IMPORTANCE_NONE, true)); // banned by permissions 5834 expected.put(UID_P, new Pair<>(IMPORTANCE_UNSPECIFIED, false)); // default: unspecified 5835 5836 ArrayList<StatsEvent> events = new ArrayList<>(); 5837 mHelper.pullPackagePreferencesStats(events, appPermissions); 5838 5839 assertEquals("total number of packages", 3, events.size()); 5840 for (StatsEvent ev : events) { 5841 AtomsProto.Atom atom = StatsEventTestUtils.convertToAtom(ev); 5842 assertTrue(atom.hasPackageNotificationPreferences()); 5843 PackageNotificationPreferences p = atom.getPackageNotificationPreferences(); 5844 int uid = p.getUid(); 5845 5846 // if it's one of the expected ids, then make sure the importance matches 5847 assertTrue(expected.containsKey(uid)); 5848 assertThat(expected.get(uid).first).isEqualTo(p.getImportance()); 5849 assertThat(expected.get(uid).second).isEqualTo(p.getUserSetImportance()); 5850 } 5851 } 5852 5853 @Test testUnlockNotificationChannelImportance()5854 public void testUnlockNotificationChannelImportance() { 5855 NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_LOW); 5856 mHelper.createNotificationChannel(PKG_O, UID_O, channel, true, false, UID_O, false); 5857 channel.lockFields(USER_LOCKED_IMPORTANCE); 5858 assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0); 5859 5860 mHelper.unlockNotificationChannelImportance(PKG_O, UID_O, channel.getId()); 5861 assertTrue((channel.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0); 5862 5863 } 5864 5865 @Test testUnlockAllNotificationChannels()5866 public void testUnlockAllNotificationChannels() { 5867 NotificationChannel channelA = new NotificationChannel("a", "a", IMPORTANCE_LOW); 5868 mHelper.createNotificationChannel(PKG_O, UID_O, channelA, true, false, UID_O, false); 5869 NotificationChannel channelB = new NotificationChannel("b", "b", IMPORTANCE_DEFAULT); 5870 mHelper.createNotificationChannel(PKG_P, UID_P, channelB, true, false, UID_P, false); 5871 NotificationChannel channelC = new NotificationChannel("c", "c", IMPORTANCE_HIGH); 5872 mHelper.createNotificationChannel(PKG_P, UID_O, channelC, false, false, UID_O, false); 5873 5874 channelA.lockFields(USER_LOCKED_IMPORTANCE); 5875 channelB.lockFields(USER_LOCKED_IMPORTANCE); 5876 channelC.lockFields(USER_LOCKED_IMPORTANCE); 5877 5878 assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0); 5879 assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0); 5880 assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) != 0); 5881 5882 mHelper.unlockAllNotificationChannels(); 5883 assertTrue((channelA.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0); 5884 assertTrue((channelB.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0); 5885 assertTrue((channelC.getUserLockedFields() & USER_LOCKED_IMPORTANCE) == 0); 5886 } 5887 5888 @Test createNotificationChannel_updateDifferent_requestsSort()5889 public void createNotificationChannel_updateDifferent_requestsSort() { 5890 NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); 5891 mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); 5892 clearInvocations(mHandler); 5893 5894 NotificationChannel updated = new NotificationChannel("id", "Wow", IMPORTANCE_DEFAULT); 5895 mHelper.createNotificationChannel(PKG_P, 0, updated, true, false, 0, false); 5896 5897 verify(mHandler).requestSort(); 5898 } 5899 5900 @Test createNotificationChannel_updateSame_doesNotRequestSort()5901 public void createNotificationChannel_updateSame_doesNotRequestSort() { 5902 NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); 5903 mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); 5904 clearInvocations(mHandler); 5905 5906 NotificationChannel same = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); 5907 mHelper.createNotificationChannel(PKG_P, 0, same, true, false, 0, false); 5908 5909 verifyZeroInteractions(mHandler); 5910 } 5911 5912 @Test updateNotificationChannel_different_requestsSort()5913 public void updateNotificationChannel_different_requestsSort() { 5914 NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); 5915 mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); 5916 clearInvocations(mHandler); 5917 5918 NotificationChannel updated = new NotificationChannel("id", "Wow", IMPORTANCE_DEFAULT); 5919 mHelper.updateNotificationChannel(PKG_P, 0, updated, false, 0, false); 5920 5921 verify(mHandler).requestSort(); 5922 } 5923 5924 @Test updateNotificationChannel_same_doesNotRequestSort()5925 public void updateNotificationChannel_same_doesNotRequestSort() { 5926 NotificationChannel original = new NotificationChannel("id", "Bah", IMPORTANCE_DEFAULT); 5927 mHelper.createNotificationChannel(PKG_P, 0, original, true, false, 0, false); 5928 clearInvocations(mHandler); 5929 // Note: Creating a NotificationChannel identical to the original is not equals(), because 5930 // of mOriginalImportance. So we create a "true copy" instead. 5931 NotificationChannel same = cloneChannel(original); 5932 5933 mHelper.updateNotificationChannel(PKG_P, 0, same, false, 0, false); 5934 5935 verifyZeroInteractions(mHandler); 5936 } 5937 5938 @Test setShowBadge_update_requestsSort()5939 public void setShowBadge_update_requestsSort() { 5940 mHelper.setShowBadge(PKG_P, 0, false); 5941 5942 verify(mHandler).requestSort(); 5943 } 5944 5945 @Test setShowBadge_same_doesNotRequestSort()5946 public void setShowBadge_same_doesNotRequestSort() { 5947 mHelper.setShowBadge(PKG_P, 0, true); // true == DEFAULT_SHOW_BADGE 5948 5949 verifyZeroInteractions(mHandler); 5950 } 5951 5952 @Test testGetFsiState_appDidNotRequest_enumNotRequested()5953 public void testGetFsiState_appDidNotRequest_enumNotRequested() { 5954 final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0, 5955 /* requestedFsiPermission */ false); 5956 5957 assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED, fsiState); 5958 } 5959 5960 @Test testGetFsiState_permissionGranted_enumGranted()5961 public void testGetFsiState_permissionGranted_enumGranted() { 5962 when(mPermissionManager.checkPermissionForPreflight(any(), any())) 5963 .thenReturn(PermissionManager.PERMISSION_GRANTED); 5964 5965 final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0, 5966 /* requestedFsiPermission= */ true); 5967 5968 assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED, fsiState); 5969 } 5970 5971 @Test testGetFsiState_permissionSoftDenied_enumDenied()5972 public void testGetFsiState_permissionSoftDenied_enumDenied() { 5973 when(mPermissionManager.checkPermissionForPreflight(any(), any())) 5974 .thenReturn(PermissionManager.PERMISSION_SOFT_DENIED); 5975 5976 final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0, 5977 /* requestedFsiPermission = */ true); 5978 5979 assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED, fsiState); 5980 } 5981 5982 @Test testGetFsiState_permissionHardDenied_enumDenied()5983 public void testGetFsiState_permissionHardDenied_enumDenied() { 5984 when(mPermissionManager.checkPermissionForPreflight(any(), any())) 5985 .thenReturn(PermissionManager.PERMISSION_HARD_DENIED); 5986 5987 final int fsiState = mHelper.getFsiState("pkg", /* uid= */ 0, 5988 /* requestedFsiPermission = */ true); 5989 5990 assertEquals(PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED, fsiState); 5991 } 5992 5993 @Test testIsFsiPermissionUserSet_appDidNotRequest_false()5994 public void testIsFsiPermissionUserSet_appDidNotRequest_false() { 5995 final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0, 5996 /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED, 5997 /* currentPermissionFlags= */ PackageManager.FLAG_PERMISSION_USER_SET); 5998 5999 assertFalse(isUserSet); 6000 } 6001 6002 @Test testIsFsiPermissionUserSet_userSet_true()6003 public void testIsFsiPermissionUserSet_userSet_true() { 6004 final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0, 6005 /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED, 6006 /* currentPermissionFlags= */ PackageManager.FLAG_PERMISSION_USER_SET); 6007 6008 assertTrue(isUserSet); 6009 } 6010 6011 @Test testIsFsiPermissionUserSet_notUserSet_false()6012 public void testIsFsiPermissionUserSet_notUserSet_false() { 6013 final boolean isUserSet = mHelper.isFsiPermissionUserSet("pkg", /* uid= */ 0, 6014 /* fsiState = */ PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED, 6015 /* currentPermissionFlags= */ ~PackageManager.FLAG_PERMISSION_USER_SET); 6016 6017 assertFalse(isUserSet); 6018 } 6019 6020 @Test testGetNotificationChannelGroups_withChannelFilter_includeBlocked()6021 public void testGetNotificationChannelGroups_withChannelFilter_includeBlocked() { 6022 NotificationChannel channel = 6023 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); 6024 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 6025 UID_N_MR1, false); 6026 // modifying same object, don't need to call updateNotificationChannel 6027 channel.setImportance(IMPORTANCE_NONE); 6028 6029 NotificationChannel channel2 = 6030 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 6031 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, 6032 UID_N_MR1, false); 6033 6034 NotificationChannel channel3 = 6035 new NotificationChannel("id3", "name3", NotificationManager.IMPORTANCE_HIGH); 6036 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, 6037 UID_N_MR1, false); 6038 6039 Set<String> filter = ImmutableSet.of("id3"); 6040 6041 NotificationChannelGroup actual = mHelper.getNotificationChannelGroups( 6042 PKG_N_MR1, UID_N_MR1, false, true, false, true, filter).getList().get(0); 6043 assertEquals(2, actual.getChannels().size()); 6044 assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id3")).count()); 6045 assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id2")).count()); 6046 } 6047 6048 @Test testGetNotificationChannelGroups_withChannelFilter_doNotIncludeBlocked()6049 public void testGetNotificationChannelGroups_withChannelFilter_doNotIncludeBlocked() { 6050 NotificationChannel channel = 6051 new NotificationChannel("id2", "name1", NotificationManager.IMPORTANCE_HIGH); 6052 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, 6053 UID_N_MR1, false); 6054 // modifying same object, don't need to call updateNotificationChannel 6055 channel.setImportance(IMPORTANCE_NONE); 6056 6057 NotificationChannel channel2 = 6058 new NotificationChannel("id2", "name2", NotificationManager.IMPORTANCE_HIGH); 6059 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2, true, false, 6060 UID_N_MR1, false); 6061 6062 NotificationChannel channel3 = 6063 new NotificationChannel("id3", "name3", NotificationManager.IMPORTANCE_HIGH); 6064 mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3, true, false, 6065 UID_N_MR1, false); 6066 6067 Set<String> filter = ImmutableSet.of("id3"); 6068 6069 NotificationChannelGroup actual = mHelper.getNotificationChannelGroups( 6070 PKG_N_MR1, UID_N_MR1, false, true, false, false, filter).getList().get(0); 6071 assertEquals(1, actual.getChannels().size()); 6072 assertEquals(1, actual.getChannels().stream().filter(c -> c.getId().equals("id3")).count()); 6073 assertEquals(0, actual.getChannels().stream().filter(c -> c.getId().equals("id2")).count()); 6074 } 6075 6076 @Test testRestoredWithoutUid_threadSafety()6077 public void testRestoredWithoutUid_threadSafety() throws Exception { 6078 when(mPm.getPackageUidAsUser(anyString(), anyInt())).thenReturn(UNKNOWN_UID); 6079 when(mPm.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())).thenThrow( 6080 new PackageManager.NameNotFoundException()); 6081 when(mClock.millis()).thenReturn(System.currentTimeMillis()); 6082 testThreadSafety(() -> { 6083 String id = "id"; 6084 String xml = "<ranking version=\"1\">\n" 6085 + "<package name=\"" + Thread.currentThread()+ "\" show_badge=\"true\">\n" 6086 + "<channel id=\"" + id + "\" name=\"name\" importance=\"2\" " 6087 + "show_badge=\"true\" />\n" 6088 + "</package>\n" 6089 + "<package name=\"" + PKG_P + "\" show_badge=\"true\">\n" 6090 + "</package>\n" 6091 + "</ranking>\n"; 6092 6093 try { 6094 loadByteArrayXml(xml.getBytes(), true, USER_SYSTEM); 6095 } catch (Exception e) { 6096 throw new RuntimeException(e); 6097 } 6098 6099 // trigger a removal from the list 6100 mXmlHelper.onPackagesChanged(true, USER_SYSTEM, new String[]{PKG_P}, 6101 new int[]{UNKNOWN_UID}); 6102 }, 20, 50); 6103 } 6104 cloneChannel(NotificationChannel original)6105 private static NotificationChannel cloneChannel(NotificationChannel original) { 6106 Parcel parcel = Parcel.obtain(); 6107 try { 6108 original.writeToParcel(parcel, 0); 6109 parcel.setDataPosition(0); 6110 return NotificationChannel.CREATOR.createFromParcel(parcel); 6111 } finally { 6112 parcel.recycle(); 6113 } 6114 } 6115 } 6116