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