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