1 /* 2 * Copyright (C) 2016 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 17 package com.android.server.notification; 18 19 import static android.Manifest.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS; 20 import static android.Manifest.permission.STATUS_BAR_SERVICE; 21 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; 22 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; 23 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.NOT_FOREGROUND_SERVICE; 24 import static android.app.ActivityManagerInternal.ServiceNotificationPolicy.SHOW_IMMEDIATELY; 25 import static android.app.ActivityTaskManager.INVALID_TASK_ID; 26 import static android.app.Flags.FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS; 27 import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME; 28 import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP; 29 import static android.app.Notification.EXTRA_PICTURE; 30 import static android.app.Notification.EXTRA_PICTURE_ICON; 31 import static android.app.Notification.EXTRA_TEXT; 32 import static android.app.Notification.FLAG_AUTO_CANCEL; 33 import static android.app.Notification.FLAG_BUBBLE; 34 import static android.app.Notification.FLAG_CAN_COLORIZE; 35 import static android.app.Notification.FLAG_FOREGROUND_SERVICE; 36 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 37 import static android.app.Notification.FLAG_NO_CLEAR; 38 import static android.app.Notification.FLAG_NO_DISMISS; 39 import static android.app.Notification.FLAG_ONGOING_EVENT; 40 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; 41 import static android.app.Notification.FLAG_USER_INITIATED_JOB; 42 import static android.app.Notification.VISIBILITY_PRIVATE; 43 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; 44 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; 45 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; 46 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; 47 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; 48 import static android.app.NotificationManager.EXTRA_BLOCKED_STATE; 49 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 50 import static android.app.NotificationManager.IMPORTANCE_HIGH; 51 import static android.app.NotificationManager.IMPORTANCE_LOW; 52 import static android.app.NotificationManager.IMPORTANCE_MAX; 53 import static android.app.NotificationManager.IMPORTANCE_NONE; 54 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 55 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; 56 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS; 57 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 58 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 59 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 60 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 61 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 62 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 63 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 64 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 65 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 66 import static android.app.PendingIntent.FLAG_IMMUTABLE; 67 import static android.app.PendingIntent.FLAG_MUTABLE; 68 import static android.app.PendingIntent.FLAG_ONE_SHOT; 69 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; 70 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; 71 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 72 import static android.content.pm.PackageManager.FEATURE_TELECOM; 73 import static android.content.pm.PackageManager.FEATURE_WATCH; 74 import static android.content.pm.PackageManager.PERMISSION_DENIED; 75 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 76 import static android.media.AudioAttributes.USAGE_MEDIA; 77 import static android.media.AudioAttributes.USAGE_NOTIFICATION; 78 import static android.os.Build.VERSION_CODES.O_MR1; 79 import static android.os.Build.VERSION_CODES.P; 80 import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; 81 import static android.os.PowerManager.PARTIAL_WAKE_LOCK; 82 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE; 83 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; 84 import static android.os.UserHandle.USER_SYSTEM; 85 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; 86 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; 87 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; 88 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; 89 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; 90 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; 91 import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS; 92 import static android.service.notification.Adjustment.KEY_IMPORTANCE; 93 import static android.service.notification.Adjustment.KEY_TEXT_REPLIES; 94 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; 95 import static android.service.notification.Condition.SOURCE_CONTEXT; 96 import static android.service.notification.Condition.SOURCE_USER_ACTION; 97 import static android.service.notification.Condition.STATE_TRUE; 98 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS; 99 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; 100 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; 101 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; 102 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 103 import static android.service.notification.NotificationListenerService.REASON_CANCEL; 104 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; 105 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; 106 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; 107 import static android.view.Display.DEFAULT_DISPLAY; 108 import static android.view.Display.INVALID_DISPLAY; 109 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 110 111 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; 112 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; 113 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; 114 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; 115 import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL; 116 import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS; 117 import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION; 118 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 119 import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL; 120 import static com.android.server.notification.NotificationManagerService.TAG; 121 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED; 122 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; 123 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED; 124 125 import static com.google.common.collect.Iterables.getOnlyElement; 126 import static com.google.common.truth.Truth.assertThat; 127 import static com.google.common.truth.Truth.assertWithMessage; 128 129 import static junit.framework.Assert.assertEquals; 130 import static junit.framework.Assert.assertFalse; 131 import static junit.framework.Assert.assertNotNull; 132 import static junit.framework.Assert.assertNotSame; 133 import static junit.framework.Assert.assertNull; 134 import static junit.framework.Assert.assertSame; 135 import static junit.framework.Assert.assertTrue; 136 import static junit.framework.Assert.fail; 137 138 import static org.junit.Assert.assertNotEquals; 139 import static org.junit.Assert.assertThrows; 140 import static org.mockito.ArgumentMatchers.isNull; 141 import static org.mockito.Matchers.anyBoolean; 142 import static org.mockito.Matchers.anyLong; 143 import static org.mockito.Matchers.anyString; 144 import static org.mockito.Matchers.eq; 145 import static org.mockito.Mockito.any; 146 import static org.mockito.Mockito.anyInt; 147 import static org.mockito.Mockito.atLeastOnce; 148 import static org.mockito.Mockito.clearInvocations; 149 import static org.mockito.Mockito.doAnswer; 150 import static org.mockito.Mockito.doNothing; 151 import static org.mockito.Mockito.doReturn; 152 import static org.mockito.Mockito.doThrow; 153 import static org.mockito.Mockito.inOrder; 154 import static org.mockito.Mockito.mock; 155 import static org.mockito.Mockito.never; 156 import static org.mockito.Mockito.reset; 157 import static org.mockito.Mockito.spy; 158 import static org.mockito.Mockito.timeout; 159 import static org.mockito.Mockito.times; 160 import static org.mockito.Mockito.verify; 161 import static org.mockito.Mockito.verifyNoMoreInteractions; 162 import static org.mockito.Mockito.when; 163 164 import static java.util.Collections.emptyList; 165 import static java.util.Collections.singletonList; 166 167 import android.Manifest; 168 import android.annotation.Nullable; 169 import android.annotation.SuppressLint; 170 import android.annotation.UserIdInt; 171 import android.app.ActivityManager; 172 import android.app.ActivityManagerInternal; 173 import android.app.AlarmManager; 174 import android.app.AppOpsManager; 175 import android.app.AutomaticZenRule; 176 import android.app.IActivityManager; 177 import android.app.ICallNotificationEventCallback; 178 import android.app.INotificationManager; 179 import android.app.ITransientNotification; 180 import android.app.IUriGrantsManager; 181 import android.app.Notification; 182 import android.app.Notification.MessagingStyle.Message; 183 import android.app.NotificationChannel; 184 import android.app.NotificationChannelGroup; 185 import android.app.NotificationManager; 186 import android.app.PendingIntent; 187 import android.app.Person; 188 import android.app.RemoteInput; 189 import android.app.RemoteInputHistoryItem; 190 import android.app.StatsManager; 191 import android.app.admin.DevicePolicyManagerInternal; 192 import android.app.job.JobScheduler; 193 import android.app.role.RoleManager; 194 import android.app.usage.UsageStatsManagerInternal; 195 import android.companion.AssociationInfo; 196 import android.companion.AssociationRequest; 197 import android.companion.ICompanionDeviceManager; 198 import android.compat.testing.PlatformCompatChangeRule; 199 import android.content.BroadcastReceiver; 200 import android.content.ComponentName; 201 import android.content.ContentUris; 202 import android.content.Context; 203 import android.content.IIntentSender; 204 import android.content.Intent; 205 import android.content.IntentFilter; 206 import android.content.pm.ActivityInfo; 207 import android.content.pm.ApplicationInfo; 208 import android.content.pm.IPackageManager; 209 import android.content.pm.LauncherApps; 210 import android.content.pm.ModuleInfo; 211 import android.content.pm.PackageInfo; 212 import android.content.pm.PackageManager; 213 import android.content.pm.PackageManagerInternal; 214 import android.content.pm.ParceledListSlice; 215 import android.content.pm.ResolveInfo; 216 import android.content.pm.ShortcutInfo; 217 import android.content.pm.ShortcutServiceInternal; 218 import android.content.pm.UserInfo; 219 import android.content.pm.VersionedPackage; 220 import android.content.res.Resources; 221 import android.graphics.Bitmap; 222 import android.graphics.Color; 223 import android.graphics.drawable.Icon; 224 import android.media.AudioAttributes; 225 import android.media.AudioManager; 226 import android.media.session.MediaSession; 227 import android.net.Uri; 228 import android.os.Binder; 229 import android.os.Build; 230 import android.os.Bundle; 231 import android.os.IBinder; 232 import android.os.Looper; 233 import android.os.Parcel; 234 import android.os.Parcelable; 235 import android.os.PowerManager; 236 import android.os.PowerManager.WakeLock; 237 import android.os.Process; 238 import android.os.RemoteException; 239 import android.os.SystemClock; 240 import android.os.UserHandle; 241 import android.os.UserManager; 242 import android.os.WorkSource; 243 import android.permission.PermissionManager; 244 import android.platform.test.annotations.DisableFlags; 245 import android.platform.test.annotations.EnableFlags; 246 import android.platform.test.flag.junit.FlagsParameterization; 247 import android.platform.test.flag.junit.SetFlagsRule; 248 import android.platform.test.rule.LimitDevicesRule; 249 import android.provider.MediaStore; 250 import android.provider.Settings; 251 import android.service.notification.Adjustment; 252 import android.service.notification.Condition; 253 import android.service.notification.ConversationChannelWrapper; 254 import android.service.notification.DeviceEffectsApplier; 255 import android.service.notification.INotificationListener; 256 import android.service.notification.NotificationListenerFilter; 257 import android.service.notification.NotificationListenerService; 258 import android.service.notification.NotificationRankingUpdate; 259 import android.service.notification.NotificationStats; 260 import android.service.notification.StatusBarNotification; 261 import android.service.notification.ZenModeConfig; 262 import android.service.notification.ZenPolicy; 263 import android.telecom.TelecomManager; 264 import android.testing.TestWithLooperRule; 265 import android.testing.TestableContentResolver; 266 import android.testing.TestableLooper; 267 import android.testing.TestableLooper.RunWithLooper; 268 import android.testing.TestablePermissions; 269 import android.testing.TestableResources; 270 import android.text.Html; 271 import android.text.TextUtils; 272 import android.util.ArrayMap; 273 import android.util.ArraySet; 274 import android.util.AtomicFile; 275 import android.util.Log; 276 import android.util.Pair; 277 import android.util.Xml; 278 import android.view.accessibility.AccessibilityManager; 279 import android.widget.RemoteViews; 280 281 import androidx.test.InstrumentationRegistry; 282 import androidx.test.filters.SmallTest; 283 284 import com.android.internal.R; 285 import com.android.internal.config.sysui.TestableFlagResolver; 286 import com.android.internal.logging.InstanceIdSequence; 287 import com.android.internal.logging.InstanceIdSequenceFake; 288 import com.android.internal.messages.nano.SystemMessageProto; 289 import com.android.internal.statusbar.NotificationVisibility; 290 import com.android.internal.widget.LockPatternUtils; 291 import com.android.modules.utils.TypedXmlPullParser; 292 import com.android.modules.utils.TypedXmlSerializer; 293 import com.android.server.DeviceIdleInternal; 294 import com.android.server.LocalServices; 295 import com.android.server.SystemService; 296 import com.android.server.SystemService.TargetUser; 297 import com.android.server.UiServiceTestCase; 298 import com.android.server.job.JobSchedulerInternal; 299 import com.android.server.lights.LightsManager; 300 import com.android.server.lights.LogicalLight; 301 import com.android.server.notification.GroupHelper.NotificationAttributes; 302 import com.android.server.notification.NotificationManagerService.NotificationAssistants; 303 import com.android.server.notification.NotificationManagerService.NotificationListeners; 304 import com.android.server.notification.NotificationManagerService.PostNotificationTracker; 305 import com.android.server.notification.NotificationManagerService.PostNotificationTrackerFactory; 306 import com.android.server.pm.PackageManagerService; 307 import com.android.server.pm.UserManagerInternal; 308 import com.android.server.policy.PermissionPolicyInternal; 309 import com.android.server.statusbar.StatusBarManagerInternal; 310 import com.android.server.uri.UriGrantsManagerInternal; 311 import com.android.server.utils.quota.MultiRateLimiter; 312 import com.android.server.wm.ActivityTaskManagerInternal; 313 import com.android.server.wm.WindowManagerInternal; 314 315 import com.google.android.collect.Lists; 316 import com.google.common.collect.ImmutableList; 317 318 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; 319 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; 320 321 import org.junit.After; 322 import org.junit.Assert; 323 import org.junit.Before; 324 import org.junit.ClassRule; 325 import org.junit.Rule; 326 import org.junit.Test; 327 import org.junit.rules.TestRule; 328 import org.junit.runner.RunWith; 329 import org.mockito.ArgumentCaptor; 330 import org.mockito.ArgumentMatcher; 331 import org.mockito.ArgumentMatchers; 332 import org.mockito.InOrder; 333 import org.mockito.Mock; 334 import org.mockito.Mockito; 335 import org.mockito.MockitoAnnotations; 336 import org.mockito.invocation.InvocationOnMock; 337 import org.mockito.stubbing.Answer; 338 339 import java.io.BufferedInputStream; 340 import java.io.BufferedOutputStream; 341 import java.io.ByteArrayInputStream; 342 import java.io.ByteArrayOutputStream; 343 import java.io.File; 344 import java.io.FileOutputStream; 345 import java.time.Duration; 346 import java.util.ArrayList; 347 import java.util.Arrays; 348 import java.util.List; 349 import java.util.Map; 350 import java.util.concurrent.CountDownLatch; 351 import java.util.function.Consumer; 352 353 import platform.test.runner.parameterized.ParameterizedAndroidJunit4; 354 import platform.test.runner.parameterized.Parameters; 355 356 @SmallTest 357 @RunWith(ParameterizedAndroidJunit4.class) 358 @RunWithLooper 359 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. 360 public class NotificationManagerServiceTest extends UiServiceTestCase { 361 private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"; 362 private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package"; 363 private static final String PKG_NO_CHANNELS = "com.example.no.channels"; 364 private static final int TEST_TASK_ID = 1; 365 private static final int UID_HEADLESS = 1_000_000; 366 private static final int TOAST_DURATION = 2_000; 367 private static final int SECONDARY_DISPLAY_ID = 42; 368 private static final int TEST_PROFILE_USERHANDLE = 12; 369 370 private static final String ACTION_NOTIFICATION_TIMEOUT = 371 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 372 private static final String EXTRA_KEY = "key"; 373 private static final String SCHEME_TIMEOUT = "timeout"; 374 private static final String REDACTED_TEXT = "redacted text"; 375 376 private static final AutomaticZenRule SOME_ZEN_RULE = 377 new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 378 .setOwner(new ComponentName("pkg", "cls")) 379 .build(); 380 381 @ClassRule 382 public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule(); 383 384 @Rule 385 public TestRule compatChangeRule = new PlatformCompatChangeRule(); 386 387 private TestableNotificationManagerService mService; 388 private INotificationManager mBinderService; 389 private NotificationManagerInternal mInternalService; 390 private ShortcutHelper mShortcutHelper; 391 @Mock 392 private IPackageManager mPackageManager; 393 @Mock 394 private PackageManager mPackageManagerClient; 395 @Mock 396 private PackageManagerInternal mPackageManagerInternal; 397 @Mock 398 private PermissionPolicyInternal mPermissionPolicyInternal; 399 @Mock 400 private WindowManagerInternal mWindowManagerInternal; 401 @Mock 402 private PermissionHelper mPermissionHelper; 403 private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake(); 404 @Rule(order = Integer.MAX_VALUE) 405 public TestWithLooperRule mlooperRule = new TestWithLooperRule(); 406 private TestableLooper mTestableLooper; 407 @Mock 408 private RankingHelper mRankingHelper; 409 @Mock private PreferencesHelper mPreferencesHelper; 410 AtomicFile mPolicyFile; 411 File mFile; 412 @Mock 413 private NotificationUsageStats mUsageStats; 414 @Mock 415 private UsageStatsManagerInternal mAppUsageStats; 416 @Mock 417 private AudioManager mAudioManager; 418 @Mock 419 private LauncherApps mLauncherApps; 420 @Mock 421 private ShortcutServiceInternal mShortcutServiceInternal; 422 @Mock 423 private UserManager mUserManager; 424 @Mock 425 ActivityManager mActivityManager; 426 @Mock 427 TelecomManager mTelecomManager; 428 @Mock 429 Resources mResources; 430 @Mock 431 RankingHandler mRankingHandler; 432 @Mock 433 ActivityManagerInternal mAmi; 434 @Mock 435 JobSchedulerInternal mJsi; 436 @Mock 437 private Looper mMainLooper; 438 @Mock 439 private NotificationManager mMockNm; 440 @Mock 441 private PermissionManager mPermissionManager; 442 @Mock 443 private DevicePolicyManagerInternal mDevicePolicyManager; 444 @Mock 445 private PowerManager mPowerManager; 446 @Mock 447 private LightsManager mLightsManager; 448 private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>(); 449 private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory = 450 new TestPostNotificationTrackerFactory(); 451 452 private PendingIntent mActivityIntent; 453 private PendingIntent mActivityIntentImmutable; 454 455 private static final int MAX_POST_DELAY = 1000; 456 457 private NotificationChannel mTestNotificationChannel = new NotificationChannel( 458 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 459 460 NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW); 461 462 private static final int NOTIFICATION_LOCATION_UNKNOWN = 0; 463 464 private static final String VALID_CONVO_SHORTCUT_ID = "shortcut"; 465 private static final String SEARCH_SELECTOR_PKG = "searchSelector"; 466 private static final String ADSERVICES_MODULE_PKG = "com.android.adservices"; 467 private static final String ADSERVICES_APK_PKG = "com.android.adservices.api"; 468 469 @Mock 470 private NotificationListeners mListeners; 471 @Mock 472 private NotificationListenerFilter mNlf; 473 @Mock private NotificationAssistants mAssistants; 474 @Mock private ConditionProviders mConditionProviders; 475 private ManagedServices.ManagedServiceInfo mListener; 476 @Mock private ICompanionDeviceManager mCompanionMgr; 477 @Mock SnoozeHelper mSnoozeHelper; 478 @Mock GroupHelper mGroupHelper; 479 @Mock 480 IBinder mPermOwner; 481 @Mock 482 IActivityManager mAm; 483 @Mock 484 ActivityTaskManagerInternal mAtm; 485 @Mock 486 IUriGrantsManager mUgm; 487 @Mock 488 UriGrantsManagerInternal mUgmInternal; 489 @Mock 490 AppOpsManager mAppOpsManager; 491 private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener; 492 @Mock 493 private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback 494 mNotificationAssistantAccessGrantedCallback; 495 @Mock 496 UserManager mUm; 497 @Mock 498 UserManagerInternal mUmInternal; 499 @Mock 500 NotificationHistoryManager mHistoryManager; 501 @Mock 502 StatsManager mStatsManager; 503 @Mock 504 AlarmManager mAlarmManager; 505 @Mock JobScheduler mJobScheduler; 506 @Mock 507 MultiRateLimiter mToastRateLimiter; 508 BroadcastReceiver mPackageIntentReceiver; 509 BroadcastReceiver mUserIntentReceiver; 510 BroadcastReceiver mNotificationTimeoutReceiver; 511 NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); 512 TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker; 513 514 TestableFlagResolver mTestFlagResolver = new TestableFlagResolver(); 515 @Rule 516 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 517 private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( 518 1 << 30); 519 @Mock 520 StatusBarManagerInternal mStatusBar; 521 522 @Mock 523 NotificationAttentionHelper mAttentionHelper; 524 525 private NotificationManagerService.WorkerHandler mWorkerHandler; 526 527 private class TestableToastCallback extends ITransientNotification.Stub { 528 @Override show(IBinder windowToken)529 public void show(IBinder windowToken) { 530 } 531 532 @Override hide()533 public void hide() { 534 } 535 } 536 537 private class TestPostNotificationTrackerFactory implements PostNotificationTrackerFactory { 538 539 private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>(); 540 541 @Override newTracker(@ullable WakeLock optionalWakeLock)542 public PostNotificationTracker newTracker(@Nullable WakeLock optionalWakeLock) { 543 PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker( 544 optionalWakeLock); 545 mCreatedTrackers.add(tracker); 546 return tracker; 547 } 548 } 549 550 @Parameters(name = "{0}") getParams()551 public static List<FlagsParameterization> getParams() { 552 return FlagsParameterization.allCombinationsOf( 553 FLAG_ALL_NOTIFS_NEED_TTL); 554 } 555 NotificationManagerServiceTest(FlagsParameterization flags)556 public NotificationManagerServiceTest(FlagsParameterization flags) { 557 mSetFlagsRule.setFlagsParameterization(flags); 558 } 559 560 @Before setUp()561 public void setUp() throws Exception { 562 // Shell permisssions will override permissions of our app, so add all necessary permissions 563 // for this test here: 564 InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 565 "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG", 566 "android.permission.READ_DEVICE_CONFIG", 567 "android.permission.READ_CONTACTS"); 568 569 MockitoAnnotations.initMocks(this); 570 571 DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class); 572 when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L); 573 574 LocalServices.removeServiceForTest(UserManagerInternal.class); 575 LocalServices.addService(UserManagerInternal.class, mUmInternal); 576 LocalServices.removeServiceForTest(UriGrantsManagerInternal.class); 577 LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal); 578 LocalServices.removeServiceForTest(WindowManagerInternal.class); 579 LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal); 580 LocalServices.removeServiceForTest(StatusBarManagerInternal.class); 581 LocalServices.addService(StatusBarManagerInternal.class, mStatusBar); 582 LocalServices.removeServiceForTest(DeviceIdleInternal.class); 583 LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal); 584 LocalServices.removeServiceForTest(ActivityManagerInternal.class); 585 LocalServices.addService(ActivityManagerInternal.class, mAmi); 586 LocalServices.removeServiceForTest(JobSchedulerInternal.class); 587 LocalServices.addService(JobSchedulerInternal.class, mJsi); 588 LocalServices.removeServiceForTest(PackageManagerInternal.class); 589 LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); 590 LocalServices.removeServiceForTest(PermissionPolicyInternal.class); 591 LocalServices.addService(PermissionPolicyInternal.class, mPermissionPolicyInternal); 592 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 593 LocalServices.addService(ShortcutServiceInternal.class, mShortcutServiceInternal); 594 mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); 595 mContext.addMockSystemService(NotificationManager.class, mMockNm); 596 mContext.addMockSystemService(RoleManager.class, mock(RoleManager.class)); 597 mContext.addMockSystemService(Context.LAUNCHER_APPS_SERVICE, mLauncherApps); 598 mContext.addMockSystemService(Context.USER_SERVICE, mUm); 599 mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, 600 mock(AccessibilityManager.class)); 601 602 doNothing().when(mContext).sendBroadcast(any(), anyString()); 603 doNothing().when(mContext).sendBroadcastAsUser(any(), any()); 604 doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); 605 TestableContentResolver cr = mock(TestableContentResolver.class); 606 when(mContext.getContentResolver()).thenReturn(cr); 607 doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt()); 608 609 when(mAppOpsManager.checkOpNoThrow( 610 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 611 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED); 612 613 // Use this testable looper. 614 mTestableLooper = TestableLooper.get(this); 615 // MockPackageManager - default returns ApplicationInfo with matching calling UID 616 mContext.setMockPackageManager(mPackageManagerClient); 617 618 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())) 619 .thenAnswer((Answer<ApplicationInfo>) invocation -> { 620 Object[] args = invocation.getArguments(); 621 return getApplicationInfo((String) args[0], mUid); 622 }); 623 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 624 .thenAnswer((Answer<ApplicationInfo>) invocation -> { 625 Object[] args = invocation.getArguments(); 626 return getApplicationInfo((String) args[0], mUid); 627 }); 628 when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid); 629 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer( 630 (Answer<Boolean>) invocation -> { 631 // TODO: b/317957802 - This is overly broad and basically makes ANY 632 // isSameApp() check pass, requiring Mockito.reset() for meaningful 633 // tests! Make it more precise. 634 Object[] args = invocation.getArguments(); 635 return (int) args[1] == mUid; 636 }); 637 when(mLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class)); 638 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); 639 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false); 640 when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner); 641 when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{mPkg}); 642 when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{mPkg}); 643 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())) 644 .thenReturn(INVALID_TASK_ID); 645 mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); 646 when(mUm.getProfileIds(eq(mUserId), eq(false))).thenReturn(new int[] { mUserId }); 647 when(mAmi.getCurrentUserId()).thenReturn(mUserId); 648 649 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true); 650 651 ActivityManager.AppTask task = mock(ActivityManager.AppTask.class); 652 List<ActivityManager.AppTask> taskList = new ArrayList<>(); 653 ActivityManager.RecentTaskInfo taskInfo = new ActivityManager.RecentTaskInfo(); 654 taskInfo.taskId = TEST_TASK_ID; 655 when(task.getTaskInfo()).thenReturn(taskInfo); 656 taskList.add(task); 657 when(mAtm.getAppTasks(anyString(), anyInt())).thenReturn(taskList); 658 659 // write to a test file; the system file isn't readable from tests 660 mFile = new File(mContext.getCacheDir(), "test.xml"); 661 mFile.createNewFile(); 662 final String preupgradeXml = "<notification-policy></notification-policy>"; 663 mPolicyFile = new AtomicFile(mFile); 664 FileOutputStream fos = mPolicyFile.startWrite(); 665 fos.write(preupgradeXml.getBytes()); 666 mPolicyFile.finishWrite(fos); 667 668 // Setup managed services 669 when(mNlf.isTypeAllowed(anyInt())).thenReturn(true); 670 when(mNlf.isPackageAllowed(any())).thenReturn(true); 671 when(mNlf.isPackageAllowed(null)).thenReturn(true); 672 when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf); 673 mListener = mListeners.new ManagedServiceInfo( 674 null, new ComponentName(mPkg, "test_class"), 675 mUserId, true, null, 0, 123); 676 ComponentName defaultComponent = ComponentName.unflattenFromString("config/device"); 677 ArraySet<ComponentName> components = new ArraySet<>(); 678 components.add(defaultComponent); 679 when(mListeners.getDefaultComponents()).thenReturn(components); 680 when(mConditionProviders.getDefaultPackages()) 681 .thenReturn(new ArraySet<>(Arrays.asList("config"))); 682 when(mAssistants.getDefaultComponents()).thenReturn(components); 683 when(mAssistants.queryPackageForServices( 684 anyString(), anyInt(), anyInt())).thenReturn(components); 685 when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener); 686 ManagedServices.Config listenerConfig = new ManagedServices.Config(); 687 listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS; 688 when(mListeners.getConfig()).thenReturn(listenerConfig); 689 ManagedServices.Config assistantConfig = new ManagedServices.Config(); 690 assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS; 691 when(mAssistants.getConfig()).thenReturn(assistantConfig); 692 ManagedServices.Config dndConfig = new ManagedServices.Config(); 693 dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS; 694 when(mConditionProviders.getConfig()).thenReturn(dndConfig); 695 696 when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); 697 698 // Use the real PowerManager to back up the mock w.r.t. creating WakeLocks. 699 // This is because 1) we need a mock to verify() calls and tracking the created WakeLocks, 700 // but 2) PowerManager and WakeLock perform their own checks (e.g. correct arguments, don't 701 // call release twice, etc) and we want the test to fail if such misuse happens, too. 702 PowerManager realPowerManager = mContext.getSystemService(PowerManager.class); 703 when(mPowerManager.newWakeLock(anyInt(), anyString())).then( 704 (Answer<WakeLock>) invocation -> { 705 WakeLock wl = realPowerManager.newWakeLock(invocation.getArgument(0), 706 invocation.getArgument(1)); 707 mAcquiredWakeLocks.add(wl); 708 return wl; 709 }); 710 711 // TODO (b/291907312): remove feature flag 712 // NOTE: Prefer using the @EnableFlags annotation where possible. Do not add any android.app 713 // flags here. 714 mSetFlagsRule.disableFlags( 715 Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE); 716 717 mActivityIntent = spy(PendingIntent.getActivity(mContext, 0, 718 new Intent().setPackage(mPkg), PendingIntent.FLAG_MUTABLE)); 719 mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0, 720 new Intent().setPackage(mPkg), FLAG_IMMUTABLE)); 721 722 initNMS(); 723 } 724 initNMS()725 private void initNMS() throws Exception { 726 initNMS(SystemService.PHASE_BOOT_COMPLETED); 727 } 728 initNMS(int upToBootPhase)729 private void initNMS(int upToBootPhase) throws Exception { 730 mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, 731 mNotificationInstanceIdSequence); 732 733 // apps allowed as convos 734 mService.setStringArrayResourceValue(PKG_O); 735 736 TestableResources tr = mContext.getOrCreateTestableResources(); 737 tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName, 738 SEARCH_SELECTOR_PKG); 739 740 doAnswer(invocation -> { 741 mOnPermissionChangeListener = invocation.getArgument(2); 742 return null; 743 }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(), 744 any()); 745 when(mUmInternal.isUserInitialized(anyInt())).thenReturn(true); 746 747 mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper())); 748 mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient, 749 mLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr, 750 mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm, 751 mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal, 752 mAppOpsManager, mUm, mHistoryManager, mStatsManager, 753 mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class), 754 mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager, 755 mPowerManager, mPostNotificationTrackerFactory); 756 757 mService.setAttentionHelper(mAttentionHelper); 758 mService.setLockPatternUtils(mock(LockPatternUtils.class)); 759 760 // Return first true for RoleObserver main-thread check 761 when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); 762 ModuleInfo moduleInfo = new ModuleInfo(); 763 moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG); 764 moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG)); 765 when(mPackageManagerClient.getInstalledModules(anyInt())) 766 .thenReturn(List.of(moduleInfo)); 767 if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) { 768 mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper); 769 } 770 771 Mockito.reset(mHistoryManager); 772 verify(mHistoryManager, never()).onBootPhaseAppsCanStart(); 773 774 if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 775 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 776 verify(mHistoryManager).onBootPhaseAppsCanStart(); 777 } 778 779 mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext); 780 mService.setStrongAuthTracker(mStrongAuthTracker); 781 782 mShortcutHelper = mService.getShortcutHelper(); 783 mShortcutHelper.setLauncherApps(mLauncherApps); 784 mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal); 785 mShortcutHelper.setUserManager(mUserManager); 786 787 // Capture PackageIntentReceiver 788 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = 789 ArgumentCaptor.forClass(BroadcastReceiver.class); 790 ArgumentCaptor<IntentFilter> intentFilterCaptor = 791 ArgumentCaptor.forClass(IntentFilter.class); 792 793 verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(), 794 any(), intentFilterCaptor.capture(), any(), any()); 795 verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(), 796 intentFilterCaptor.capture(), anyInt()); 797 verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(), 798 intentFilterCaptor.capture()); 799 List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues(); 800 List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues(); 801 802 for (int i = 0; i < intentFilters.size(); i++) { 803 final IntentFilter filter = intentFilters.get(i); 804 if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED) 805 && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED) 806 && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) { 807 mPackageIntentReceiver = broadcastReceivers.get(i); 808 } 809 if (filter.hasAction(Intent.ACTION_USER_SWITCHED) 810 || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE) 811 || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { 812 // There may be multiple receivers, get the NMS one 813 if (broadcastReceivers.get(i).toString().contains( 814 NotificationManagerService.class.getName())) { 815 mUserIntentReceiver = broadcastReceivers.get(i); 816 } 817 } 818 if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT) 819 && filter.hasDataScheme(SCHEME_TIMEOUT)) { 820 mNotificationTimeoutReceiver = broadcastReceivers.get(i); 821 } 822 } 823 assertNotNull("package intent receiver should exist", mPackageIntentReceiver); 824 assertNotNull("User receiver should exist", mUserIntentReceiver); 825 if (!Flags.allNotifsNeedTtl()) { 826 assertNotNull("Notification timeout receiver should exist", 827 mNotificationTimeoutReceiver); 828 } 829 830 // Pretend the shortcut exists 831 List<ShortcutInfo> shortcutInfos = new ArrayList<>(); 832 ShortcutInfo info = mock(ShortcutInfo.class); 833 when(info.getPackage()).thenReturn(mPkg); 834 when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID); 835 when(info.getUserId()).thenReturn(USER_SYSTEM); 836 when(info.isLongLived()).thenReturn(true); 837 when(info.isEnabled()).thenReturn(true); 838 shortcutInfos.add(info); 839 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); 840 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 841 anyString(), anyInt(), any())).thenReturn(true); 842 when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true); 843 mockIsUserVisible(DEFAULT_DISPLAY, true); 844 mockIsVisibleBackgroundUsersSupported(false); 845 846 // Set the testable bubble extractor 847 RankingHelper rankingHelper = mService.getRankingHelper(); 848 BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class); 849 extractor.setActivityManager(mActivityManager); 850 851 // Tests call directly into the Binder. 852 mBinderService = mService.getBinderService(); 853 mInternalService = mService.getInternalService(); 854 855 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice( 856 Arrays.asList(mTestNotificationChannel, mSilentChannel))); 857 mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice( 858 Arrays.asList(mTestNotificationChannel, mSilentChannel))); 859 mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice( 860 Arrays.asList(mTestNotificationChannel, mSilentChannel))); 861 assertNotNull(mBinderService.getNotificationChannel( 862 mPkg, mContext.getUserId(), mPkg, TEST_CHANNEL_ID)); 863 assertNotNull(mBinderService.getNotificationChannel( 864 mPkg, mContext.getUserId(), mPkg, mSilentChannel.getId())); 865 clearInvocations(mRankingHandler); 866 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 867 868 var checker = mock(TestableNotificationManagerService.ComponentPermissionChecker.class); 869 mService.permissionChecker = checker; 870 when(checker.check(anyString(), anyInt(), anyInt(), anyBoolean())) 871 .thenReturn(PackageManager.PERMISSION_DENIED); 872 } 873 874 @After assertNotificationRecordLoggerCallsValid()875 public void assertNotificationRecordLoggerCallsValid() { 876 waitForIdle(); // Finish async work, including all logging calls done by Runnables. 877 for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) { 878 if (call.wasLogged) { 879 assertNotNull(call.event); 880 if (call.event == NOTIFICATION_POSTED || call.event == NOTIFICATION_UPDATED) { 881 assertThat(call.postDurationMillisLogged).isGreaterThan(0); 882 } else { 883 assertThat(call.postDurationMillisLogged).isNull(); 884 } 885 } 886 } 887 assertThat(mNotificationRecordLogger.getPendingLogs()).isEmpty(); 888 } 889 890 @After assertAllTrackersFinishedOrCancelled()891 public void assertAllTrackersFinishedOrCancelled() { 892 waitForIdle(); // Finish async work. 893 // Verify that no trackers were left dangling. 894 for (PostNotificationTracker tracker : mPostNotificationTrackerFactory.mCreatedTrackers) { 895 assertThat(tracker.isOngoing()).isFalse(); 896 } 897 mPostNotificationTrackerFactory.mCreatedTrackers.clear(); 898 } 899 900 @After assertAllWakeLocksReleased()901 public void assertAllWakeLocksReleased() { 902 waitForIdle(); // Finish async work. 903 for (WakeLock wakeLock : mAcquiredWakeLocks) { 904 assertThat(wakeLock.isHeld()).isFalse(); 905 } 906 } 907 908 @After tearDown()909 public void tearDown() throws Exception { 910 if (mFile != null) mFile.delete(); 911 912 if (mActivityIntent != null) { 913 mActivityIntent.cancel(); 914 } 915 916 mService.clearNotifications(); 917 if (mTestableLooper != null) { 918 mTestableLooper.processAllMessages(); 919 } 920 921 try { 922 mService.onDestroy(); 923 } catch (IllegalStateException | IllegalArgumentException e) { 924 Log.e(TAG, "failed to destroy", e); 925 // can throw if a broadcast receiver was never registered 926 } 927 928 InstrumentationRegistry.getInstrumentation() 929 .getUiAutomation().dropShellPermissionIdentity(); 930 if (mWorkerHandler != null) { 931 // Remove scheduled messages that would be processed when the test is already done, and 932 // could cause issues, for example, messages that remove/cancel shown toasts (this causes 933 // problematic interactions with mocks when they're no longer working as expected). 934 mWorkerHandler.removeCallbacksAndMessages(null); 935 } 936 937 if (mTestableLooper != null) { 938 // Must remove static reference to this test object to prevent leak (b/261039202) 939 mTestableLooper.remove(this); 940 } 941 } 942 simulatePackageSuspendBroadcast(boolean suspend, String pkg, int uid)943 private void simulatePackageSuspendBroadcast(boolean suspend, String pkg, 944 int uid) { 945 // mimics receive broadcast that package is (un)suspended 946 // but does not actually (un)suspend the package 947 final Bundle extras = new Bundle(); 948 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, 949 new String[]{pkg}); 950 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid}); 951 952 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED 953 : Intent.ACTION_PACKAGES_UNSUSPENDED; 954 final Intent intent = new Intent(action); 955 intent.putExtras(extras); 956 957 mPackageIntentReceiver.onReceive(getContext(), intent); 958 } 959 simulatePackageRemovedBroadcast(String pkg, int uid)960 private void simulatePackageRemovedBroadcast(String pkg, int uid) { 961 // mimics receive broadcast that package is removed, but doesn't remove the package. 962 final Bundle extras = new Bundle(); 963 extras.putInt(Intent.EXTRA_UID, uid); 964 965 final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); 966 intent.setData(Uri.parse("package:" + pkg)); 967 intent.putExtras(extras); 968 969 mPackageIntentReceiver.onReceive(getContext(), intent); 970 } 971 simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids)972 private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) { 973 // mimics receive broadcast that package is (un)distracting 974 // but does not actually register that info with packagemanager 975 final Bundle extras = new Bundle(); 976 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs); 977 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag); 978 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids); 979 980 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 981 intent.putExtras(extras); 982 983 mPackageIntentReceiver.onReceive(getContext(), intent); 984 } 985 simulateProfileAvailabilityActions(String intentAction)986 private void simulateProfileAvailabilityActions(String intentAction) { 987 final Intent intent = new Intent(intentAction); 988 intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE); 989 mUserIntentReceiver.onReceive(mContext, intent); 990 } 991 generateResetComponentValues()992 private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() { 993 ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>(); 994 changed.put(true, new ArrayList<>()); 995 changed.put(false, new ArrayList<>()); 996 return changed; 997 } getApplicationInfo(String pkg, int uid)998 private ApplicationInfo getApplicationInfo(String pkg, int uid) { 999 final ApplicationInfo applicationInfo = new ApplicationInfo(); 1000 applicationInfo.packageName = pkg; 1001 applicationInfo.uid = uid; 1002 applicationInfo.sourceDir = mContext.getApplicationInfo().sourceDir; 1003 switch (pkg) { 1004 case PKG_N_MR1: 1005 applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1006 break; 1007 case PKG_O: 1008 applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; 1009 break; 1010 case PKG_P: 1011 applicationInfo.targetSdkVersion = Build.VERSION_CODES.P; 1012 break; 1013 default: 1014 applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; 1015 break; 1016 } 1017 return applicationInfo; 1018 } 1019 waitForIdle()1020 public void waitForIdle() { 1021 if (mTestableLooper != null) { 1022 mTestableLooper.processAllMessages(); 1023 } 1024 } 1025 setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, int pkgPref, boolean channelEnabled)1026 private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, 1027 int pkgPref, boolean channelEnabled) { 1028 Settings.Secure.putInt(mContext.getContentResolver(), 1029 Settings.Secure.NOTIFICATION_BUBBLES, globalEnabled ? 1 : 0); 1030 mService.mPreferencesHelper.updateBubblesEnabled(); 1031 assertEquals(globalEnabled, mService.mPreferencesHelper.bubblesEnabled( 1032 mock(UserHandle.class))); 1033 try { 1034 mBinderService.setBubblesAllowed(pkg, uid, pkgPref); 1035 } catch (RemoteException e) { 1036 e.printStackTrace(); 1037 } 1038 mTestNotificationChannel.setAllowBubbles(channelEnabled); 1039 } 1040 setUpPrefsForHistory(@serIdInt int userId, boolean globalEnabled)1041 private void setUpPrefsForHistory(@UserIdInt int userId, boolean globalEnabled) 1042 throws Exception { 1043 initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY); 1044 1045 // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid 1046 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1047 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, userId); 1048 // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0 1049 Settings.Secure.putInt(mContext.getContentResolver(), 1050 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0); 1051 setUsers(new int[] {0, userId}); 1052 1053 // Forces an update by calling observe on mSettingsObserver, which picks up the settings 1054 // changes above. 1055 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 1056 1057 assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(), 1058 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, userId) != 0); 1059 } 1060 generateSbn(String pkg, int uid, long postTime, int userId)1061 private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) { 1062 Notification.Builder nb = new Notification.Builder(mContext, "a") 1063 .setContentTitle("foo") 1064 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1065 StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid, 1066 "tag" + System.currentTimeMillis(), uid, 0, 1067 nb.build(), new UserHandle(userId), null, postTime); 1068 return sbn; 1069 } 1070 generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary)1071 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1072 String groupKey, boolean isSummary) { 1073 return generateNotificationRecord(channel, id, "tag" + System.currentTimeMillis(), groupKey, 1074 isSummary); 1075 } 1076 generateNotificationRecord(NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary)1077 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1078 String tag, String groupKey, boolean isSummary) { 1079 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1080 .setContentTitle("foo") 1081 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1082 .setGroup(groupKey) 1083 .setGroupSummary(isSummary); 1084 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, 1085 tag, mUid, 0, 1086 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1087 return new NotificationRecord(mContext, sbn, channel); 1088 } 1089 generateNotificationRecord(NotificationChannel channel)1090 private NotificationRecord generateNotificationRecord(NotificationChannel channel) { 1091 return generateNotificationRecord(channel, null); 1092 } 1093 generateNotificationRecord(NotificationChannel channel, Notification.TvExtender extender)1094 private NotificationRecord generateNotificationRecord(NotificationChannel channel, 1095 Notification.TvExtender extender) { 1096 if (channel == null) { 1097 channel = mTestNotificationChannel; 1098 } 1099 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1100 .setContentTitle("foo") 1101 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1102 .addAction(new Notification.Action.Builder(null, "test", mActivityIntent).build()) 1103 .addAction(new Notification.Action.Builder( 1104 null, "test", mActivityIntentImmutable).build()); 1105 if (extender != null) { 1106 nb.extend(extender); 1107 } 1108 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 1109 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1110 return new NotificationRecord(mContext, sbn, channel); 1111 } 1112 generateNotificationRecord(NotificationChannel channel, long postTime)1113 private NotificationRecord generateNotificationRecord(NotificationChannel channel, 1114 long postTime) { 1115 final StatusBarNotification sbn = generateSbn(mPkg, mUid, postTime, mUserId); 1116 return new NotificationRecord(mContext, sbn, channel); 1117 } 1118 generateNotificationRecord(NotificationChannel channel, int userId)1119 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) { 1120 return generateNotificationRecord(channel, 1, userId); 1121 } 1122 generateNotificationRecord(NotificationChannel channel, int id, int userId)1123 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1124 int userId) { 1125 return generateNotificationRecord(channel, id, userId, "foo"); 1126 } 1127 generateNotificationRecord(NotificationChannel channel, int id, int userId, String title)1128 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1129 int userId, String title) { 1130 if (channel == null) { 1131 channel = mTestNotificationChannel; 1132 } 1133 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1134 .setContentTitle(title) 1135 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1136 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0, 1137 nb.build(), new UserHandle(userId), null, 0); 1138 NotificationRecord r = new NotificationRecord(mContext, sbn, channel); 1139 return r; 1140 } 1141 generateMessageBubbleNotifRecord(NotificationChannel channel, String tag)1142 private NotificationRecord generateMessageBubbleNotifRecord(NotificationChannel channel, 1143 String tag) { 1144 return generateMessageBubbleNotifRecord(true, channel, 1, tag, null, false, true); 1145 } 1146 generateMessageBubbleNotifRecord(boolean addMetadata, NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, boolean mutable)1147 private NotificationRecord generateMessageBubbleNotifRecord(boolean addMetadata, 1148 NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, 1149 boolean mutable) { 1150 if (channel == null) { 1151 channel = mTestNotificationChannel; 1152 } 1153 if (tag == null) { 1154 tag = "tag"; 1155 } 1156 Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey, 1157 isSummary, mutable); 1158 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, 1159 tag, mUid, 0, 1160 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1161 return new NotificationRecord(mContext, sbn, channel); 1162 } 1163 generateRedactedSbn(NotificationChannel channel, int id, int userId)1164 private StatusBarNotification generateRedactedSbn(NotificationChannel channel, int id, 1165 int userId) { 1166 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1167 .setContentTitle("foo") 1168 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1169 .setContentText(REDACTED_TEXT); 1170 return new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0, 1171 nb.build(), new UserHandle(userId), null, 0); 1172 } 1173 getSignalExtractorSideEffects()1174 private Map<String, Answer> getSignalExtractorSideEffects() { 1175 Map<String, Answer> answers = new ArrayMap<>(); 1176 1177 answers.put("override group key", invocationOnMock -> { 1178 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1179 .setOverrideGroupKey("bananas"); 1180 return null; 1181 }); 1182 answers.put("override people", invocationOnMock -> { 1183 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1184 .setPeopleOverride(new ArrayList<>()); 1185 return null; 1186 }); 1187 answers.put("snooze criteria", invocationOnMock -> { 1188 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1189 .setSnoozeCriteria(new ArrayList<>()); 1190 return null; 1191 }); 1192 answers.put("notification channel", invocationOnMock -> { 1193 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1194 .updateNotificationChannel(new NotificationChannel("a", "", IMPORTANCE_LOW)); 1195 return null; 1196 }); 1197 answers.put("badging", invocationOnMock -> { 1198 NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0]; 1199 r.setShowBadge(!r.canShowBadge()); 1200 return null; 1201 }); 1202 answers.put("bubbles", invocationOnMock -> { 1203 NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0]; 1204 r.setAllowBubble(!r.canBubble()); 1205 return null; 1206 }); 1207 answers.put("package visibility", invocationOnMock -> { 1208 ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride( 1209 Notification.VISIBILITY_SECRET); 1210 return null; 1211 }); 1212 1213 return answers; 1214 } 1215 getMessageStyleNotifBuilder(boolean addBubbleMetadata, String groupKey, boolean isSummary, boolean mutable)1216 private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata, 1217 String groupKey, boolean isSummary, boolean mutable) { 1218 // Give it a person 1219 Person person = new Person.Builder() 1220 .setName("bubblebot") 1221 .build(); 1222 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 1223 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 1224 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 1225 mutable ? mActivityIntent : mActivityIntentImmutable).addRemoteInput(remoteInput) 1226 .build(); 1227 // Make it messaging style 1228 Notification.Builder nb = new Notification.Builder(mContext, 1229 mTestNotificationChannel.getId()) 1230 .setContentTitle("foo") 1231 .setStyle(new Notification.MessagingStyle(person) 1232 .setConversationTitle("Bubble Chat") 1233 .addMessage("Hello?", 1234 SystemClock.currentThreadTimeMillis() - 300000, person) 1235 .addMessage("Is it me you're looking for?", 1236 SystemClock.currentThreadTimeMillis(), person) 1237 ) 1238 .setActions(replyAction) 1239 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1240 .setShortcutId(VALID_CONVO_SHORTCUT_ID) 1241 .setGroupSummary(isSummary); 1242 if (groupKey != null) { 1243 nb.setGroup(groupKey); 1244 } 1245 if (addBubbleMetadata) { 1246 nb.setBubbleMetadata(getBubbleMetadata()); 1247 } 1248 return nb; 1249 } 1250 getBubbleMetadata()1251 private Notification.BubbleMetadata getBubbleMetadata() { 1252 ActivityInfo info = new ActivityInfo(); 1253 info.resizeMode = RESIZE_MODE_RESIZEABLE; 1254 ResolveInfo ri = new ResolveInfo(); 1255 ri.activityInfo = info; 1256 when(mPackageManagerClient.resolveActivity(any(), anyInt())).thenReturn(ri); 1257 1258 return new Notification.BubbleMetadata.Builder( 1259 mActivityIntent, 1260 Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon)) 1261 .build(); 1262 } 1263 addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)1264 private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel) 1265 throws RemoteException { 1266 1267 String groupKey = "BUBBLE_GROUP"; 1268 1269 // Notification that has bubble metadata 1270 NotificationRecord nrBubble = generateMessageBubbleNotifRecord(true /* addMetadata */, 1271 mTestNotificationChannel, 1 /* id */, "tag", groupKey, false /* isSummary */, 1272 true); 1273 1274 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrBubble.getSbn().getTag(), 1275 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(), 1276 nrBubble.getSbn().getUserId()); 1277 waitForIdle(); 1278 1279 // Make sure we are a bubble 1280 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 1281 assertEquals(1, notifsAfter.length); 1282 assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0); 1283 1284 // Notification without bubble metadata 1285 NotificationRecord nrPlain = generateMessageBubbleNotifRecord(false /* addMetadata */, 1286 mTestNotificationChannel, 2 /* id */, "tag", groupKey, false /* isSummary */, 1287 true); 1288 1289 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrPlain.getSbn().getTag(), 1290 nrPlain.getSbn().getId(), nrPlain.getSbn().getNotification(), 1291 nrPlain.getSbn().getUserId()); 1292 waitForIdle(); 1293 1294 notifsAfter = mBinderService.getActiveNotifications(mPkg); 1295 assertEquals(2, notifsAfter.length); 1296 1297 // Summary notification for both of those 1298 NotificationRecord nrSummary = generateMessageBubbleNotifRecord(false /* addMetadata */, 1299 mTestNotificationChannel, 3 /* id */, "tag", groupKey, true /* isSummary */, 1300 true); 1301 1302 if (summaryAutoCancel) { 1303 nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL; 1304 } 1305 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrSummary.getSbn().getTag(), 1306 nrSummary.getSbn().getId(), nrSummary.getSbn().getNotification(), 1307 nrSummary.getSbn().getUserId()); 1308 waitForIdle(); 1309 1310 notifsAfter = mBinderService.getActiveNotifications(mPkg); 1311 assertEquals(3, notifsAfter.length); 1312 1313 return nrSummary; 1314 } 1315 createAndPostCallStyleNotification(String packageName, UserHandle userHandle, String testName)1316 private NotificationRecord createAndPostCallStyleNotification(String packageName, 1317 UserHandle userHandle, String testName) throws Exception { 1318 Person person = new Person.Builder().setName("caller").build(); 1319 Notification.Builder nb = new Notification.Builder(mContext, 1320 mTestNotificationChannel.getId()) 1321 .setFlag(FLAG_USER_INITIATED_JOB, true) 1322 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 1323 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1324 StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1, 1325 testName, mUid, 0, nb.build(), userHandle, null, 0); 1326 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 1327 1328 mService.addEnqueuedNotification(r); 1329 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1330 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run(); 1331 waitForIdle(); 1332 1333 return mService.findNotificationLocked( 1334 packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId()); 1335 } 1336 createAndPostNotification(Notification.Builder nb, String testName)1337 private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName) 1338 throws RemoteException { 1339 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0, 1340 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1341 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 1342 1343 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1344 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 1345 waitForIdle(); 1346 1347 return mService.findNotificationLocked( 1348 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 1349 } 1350 parcelAndUnparcel(T source, Parcelable.Creator<T> creator)1351 private static <T extends Parcelable> T parcelAndUnparcel(T source, 1352 Parcelable.Creator<T> creator) { 1353 Parcel parcel = Parcel.obtain(); 1354 source.writeToParcel(parcel, 0); 1355 parcel.setDataPosition(0); 1356 return creator.createFromParcel(parcel); 1357 } 1358 createPendingIntent(String action)1359 private PendingIntent createPendingIntent(String action) { 1360 return PendingIntent.getActivity(mContext, 0, 1361 new Intent(action).setPackage(mContext.getPackageName()), 1362 PendingIntent.FLAG_MUTABLE); 1363 } 1364 allowTestPackageToToast()1365 private void allowTestPackageToToast() throws Exception { 1366 assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty(); 1367 mService.isSystemUid = false; 1368 mService.isSystemAppId = false; 1369 setToastRateIsWithinQuota(true); 1370 setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false); 1371 // package is not suspended 1372 when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId)) 1373 .thenReturn(false); 1374 } 1375 enqueueToast(String testPackage, ITransientNotification callback)1376 private boolean enqueueToast(String testPackage, ITransientNotification callback) 1377 throws RemoteException { 1378 return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), 1379 callback); 1380 } 1381 enqueueToast(INotificationManager service, String testPackage, IBinder token, ITransientNotification callback)1382 private boolean enqueueToast(INotificationManager service, String testPackage, 1383 IBinder token, ITransientNotification callback) throws RemoteException { 1384 return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ 1385 true, DEFAULT_DISPLAY); 1386 } 1387 enqueueTextToast(String testPackage, CharSequence text)1388 private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { 1389 return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY); 1390 } 1391 enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, int displayId)1392 private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, 1393 int displayId) throws RemoteException { 1394 return ((INotificationManager) mService.mService).enqueueTextToast(testPackage, 1395 new Binder(), text, TOAST_DURATION, isUiContext, displayId, 1396 /* textCallback= */ null); 1397 } 1398 mockIsVisibleBackgroundUsersSupported(boolean supported)1399 private void mockIsVisibleBackgroundUsersSupported(boolean supported) { 1400 when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported); 1401 } 1402 mockIsUserVisible(int displayId, boolean visible)1403 private void mockIsUserVisible(int displayId, boolean visible) { 1404 when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible); 1405 } 1406 mockDisplayAssignedToUser(int displayId)1407 private void mockDisplayAssignedToUser(int displayId) { 1408 when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId); 1409 } 1410 verifyToastShownForTestPackage(String text, int displayId)1411 private void verifyToastShownForTestPackage(String text, int displayId) { 1412 verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(), 1413 eq(TOAST_DURATION), any(), eq(displayId)); 1414 } 1415 1416 @Test 1417 @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL) testLimitTimeOutBroadcast()1418 public void testLimitTimeOutBroadcast() { 1419 NotificationChannel channel = new NotificationChannel("id", "name", 1420 NotificationManager.IMPORTANCE_HIGH); 1421 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1422 .setContentTitle("foo") 1423 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1424 .setTimeoutAfter(1); 1425 1426 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 1427 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1428 NotificationRecord r = new NotificationRecord(mContext, sbn, channel); 1429 1430 mService.scheduleTimeoutLocked(r); 1431 ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class); 1432 verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture()); 1433 assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, 1434 captor.getValue().getIntent().getPackage()); 1435 1436 mService.cancelScheduledTimeoutLocked(r); 1437 verify(mAlarmManager).cancel(captor.capture()); 1438 assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, 1439 captor.getValue().getIntent().getPackage()); 1440 } 1441 1442 @Test testDefaultAssistant_overrideDefault()1443 public void testDefaultAssistant_overrideDefault() { 1444 final int userId = mContext.getUserId(); 1445 final String testComponent = "package/class"; 1446 final List<UserInfo> userInfos = new ArrayList<>(); 1447 userInfos.add(new UserInfo(userId, "", 0)); 1448 final ArraySet<ComponentName> validAssistants = new ArraySet<>(); 1449 validAssistants.add(ComponentName.unflattenFromString(testComponent)); 1450 when(mActivityManager.isLowRamDevice()).thenReturn(false); 1451 when(mAssistants.queryPackageForServices(isNull(), anyInt(), anyInt())) 1452 .thenReturn(validAssistants); 1453 when(mAssistants.getDefaultComponents()).thenReturn(validAssistants); 1454 when(mUm.getEnabledProfiles(anyInt())).thenReturn(userInfos); 1455 1456 mService.setDefaultAssistantForUser(userId); 1457 1458 verify(mAssistants).setPackageOrComponentEnabled( 1459 eq(testComponent), eq(userId), eq(true), eq(true), eq(false)); 1460 } 1461 1462 @Test testCreateNotificationChannels_SingleChannel()1463 public void testCreateNotificationChannels_SingleChannel() throws Exception { 1464 final NotificationChannel channel = 1465 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1466 mBinderService.createNotificationChannels(mPkg, 1467 new ParceledListSlice(Arrays.asList(channel))); 1468 final NotificationChannel createdChannel = 1469 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1470 assertTrue(createdChannel != null); 1471 } 1472 1473 @Test testCreateNotificationChannels_NullChannelThrowsException()1474 public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception { 1475 try { 1476 mBinderService.createNotificationChannels(mPkg, 1477 new ParceledListSlice(Arrays.asList((Object[])null))); 1478 fail("Exception should be thrown immediately."); 1479 } catch (NullPointerException e) { 1480 // pass 1481 } 1482 } 1483 1484 @Test testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()1485 public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog() 1486 throws Exception { 1487 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1488 final NotificationChannel channel = 1489 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1490 mBinderService.createNotificationChannels(PKG_NO_CHANNELS, 1491 new ParceledListSlice(Arrays.asList(channel))); 1492 verify(mWorkerHandler).post(eq(new NotificationManagerService 1493 .ShowNotificationPermissionPromptRunnable(PKG_NO_CHANNELS, 1494 mUserId, TEST_TASK_ID, mPermissionPolicyInternal))); 1495 } 1496 1497 @Test testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()1498 public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog() 1499 throws Exception { 1500 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1501 assertTrue(mBinderService.getNumNotificationChannelsForPackage(mPkg, mUid, true) > 0); 1502 1503 final NotificationChannel channel = 1504 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1505 mBinderService.createNotificationChannels(mPkg, 1506 new ParceledListSlice(Arrays.asList(channel))); 1507 verify(mWorkerHandler, never()).post(any( 1508 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class)); 1509 } 1510 1511 @Test testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()1512 public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog() 1513 throws Exception { 1514 reset(mPermissionPolicyInternal); 1515 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1516 1517 final NotificationChannel channel = 1518 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1519 mBinderService.createNotificationChannels(mPkg, 1520 new ParceledListSlice(Arrays.asList(channel))); 1521 1522 verify(mWorkerHandler, never()).post(any( 1523 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class)); 1524 } 1525 1526 @Test testCreateNotificationChannels_TwoChannels()1527 public void testCreateNotificationChannels_TwoChannels() throws Exception { 1528 final NotificationChannel channel1 = 1529 new NotificationChannel("id1", "name", IMPORTANCE_DEFAULT); 1530 final NotificationChannel channel2 = 1531 new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT); 1532 mBinderService.createNotificationChannels(mPkg, 1533 new ParceledListSlice(Arrays.asList(channel1, channel2))); 1534 assertTrue(mBinderService.getNotificationChannel( 1535 mPkg, mContext.getUserId(), mPkg, "id1") != null); 1536 assertTrue(mBinderService.getNotificationChannel( 1537 mPkg, mContext.getUserId(), mPkg, "id2") != null); 1538 } 1539 1540 @Test testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()1541 public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance() 1542 throws Exception { 1543 final NotificationChannel channel = 1544 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1545 mBinderService.createNotificationChannels(mPkg, 1546 new ParceledListSlice(Arrays.asList(channel))); 1547 1548 // Recreating the channel doesn't throw, but ignores importance. 1549 final NotificationChannel dupeChannel = 1550 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1551 mBinderService.createNotificationChannels(mPkg, 1552 new ParceledListSlice(Arrays.asList(dupeChannel))); 1553 final NotificationChannel createdChannel = 1554 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1555 assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance()); 1556 } 1557 1558 @Test testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()1559 public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance() 1560 throws Exception { 1561 final NotificationChannel channel = 1562 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1563 mBinderService.createNotificationChannels(mPkg, 1564 new ParceledListSlice(Arrays.asList(channel))); 1565 1566 // Recreating with a lower importance is allowed to modify the channel. 1567 final NotificationChannel dupeChannel = 1568 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); 1569 mBinderService.createNotificationChannels(mPkg, 1570 new ParceledListSlice(Arrays.asList(dupeChannel))); 1571 final NotificationChannel createdChannel = 1572 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1573 assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance()); 1574 } 1575 1576 @Test testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()1577 public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated() 1578 throws Exception { 1579 final NotificationChannel channel = 1580 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1581 mBinderService.createNotificationChannels(mPkg, 1582 new ParceledListSlice(Arrays.asList(channel))); 1583 1584 // The user modifies importance directly, can no longer be changed by the app. 1585 final NotificationChannel updatedChannel = 1586 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1587 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, updatedChannel); 1588 1589 // Recreating with a lower importance leaves channel unchanged. 1590 final NotificationChannel dupeChannel = 1591 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); 1592 mBinderService.createNotificationChannels(mPkg, 1593 new ParceledListSlice(Arrays.asList(dupeChannel))); 1594 final NotificationChannel createdChannel = 1595 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1596 assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance()); 1597 } 1598 1599 @Test testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()1600 public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond() 1601 throws Exception { 1602 final NotificationChannel channel1 = 1603 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1604 final NotificationChannel channel2 = 1605 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1606 mBinderService.createNotificationChannels(mPkg, 1607 new ParceledListSlice(Arrays.asList(channel1, channel2))); 1608 final NotificationChannel createdChannel = 1609 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1610 assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance()); 1611 } 1612 1613 @Test testBlockedNotifications_suspended()1614 public void testBlockedNotifications_suspended() throws Exception { 1615 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true); 1616 1617 NotificationChannel channel = new NotificationChannel("id", "name", 1618 IMPORTANCE_HIGH); 1619 NotificationRecord r = generateNotificationRecord(channel); 1620 1621 // isBlocked is only used for user blocking, not app suspension 1622 assertFalse(mService.isRecordBlockedLocked(r)); 1623 } 1624 1625 @Test testBlockedNotifications_blockedChannel()1626 public void testBlockedNotifications_blockedChannel() throws Exception { 1627 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1628 1629 NotificationChannel channel = new NotificationChannel("id", "name", 1630 NotificationManager.IMPORTANCE_NONE); 1631 NotificationRecord r = generateNotificationRecord(channel); 1632 assertTrue(mService.isRecordBlockedLocked(r)); 1633 1634 mBinderService.createNotificationChannels( 1635 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1636 final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1637 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1638 "testBlockedNotifications_blockedChannel", 1639 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1640 waitForIdle(); 1641 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1642 } 1643 1644 @Test testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()1645 public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService() 1646 throws Exception { 1647 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1648 when(mAmi.applyForegroundServiceNotification( 1649 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1650 1651 NotificationChannel channel = new NotificationChannel("blocked", "name", 1652 NotificationManager.IMPORTANCE_NONE); 1653 mBinderService.createNotificationChannels( 1654 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1655 1656 final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1657 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1658 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1659 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1660 waitForIdle(); 1661 assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1662 assertEquals(IMPORTANCE_LOW, 1663 mService.getNotificationRecord(sbn.getKey()).getImportance()); 1664 assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel( 1665 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1666 } 1667 1668 @Test testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()1669 public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService() 1670 throws Exception { 1671 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1672 when(mAmi.applyForegroundServiceNotification( 1673 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1674 1675 NotificationChannel channel = 1676 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH); 1677 mBinderService.createNotificationChannels( 1678 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1679 1680 NotificationChannel update = 1681 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE); 1682 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update); 1683 waitForIdle(); 1684 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1685 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1686 1687 StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1688 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1689 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1690 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1691 waitForIdle(); 1692 // The first time a foreground service notification is shown, we allow the channel 1693 // to be updated to allow it to be seen. 1694 assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1695 assertEquals(IMPORTANCE_LOW, 1696 mService.getNotificationRecord(sbn.getKey()).getImportance()); 1697 assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel( 1698 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1699 mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId()); 1700 waitForIdle(); 1701 1702 update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE); 1703 update.setUserVisibleTaskShown(true); 1704 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update); 1705 waitForIdle(); 1706 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1707 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1708 1709 sbn = generateNotificationRecord(channel).getSbn(); 1710 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1711 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1712 "testEnqueuedBlockedNotifications_userBlockedChannelForegroundService", 1713 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1714 waitForIdle(); 1715 // The second time it is shown, we keep the user's preference. 1716 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1717 assertNull(mService.getNotificationRecord(sbn.getKey())); 1718 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1719 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1720 } 1721 1722 @Test testBlockedNotifications_blockedChannelGroup()1723 public void testBlockedNotifications_blockedChannelGroup() throws Exception { 1724 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1725 mService.setPreferencesHelper(mPreferencesHelper); 1726 when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())). 1727 thenReturn(true); 1728 1729 NotificationChannel channel = new NotificationChannel("id", "name", 1730 NotificationManager.IMPORTANCE_HIGH); 1731 channel.setGroup("something"); 1732 NotificationRecord r = generateNotificationRecord(channel); 1733 assertTrue(mService.isRecordBlockedLocked(r)); 1734 } 1735 1736 @Test testEnqueuedBlockedNotifications_blockedApp()1737 public void testEnqueuedBlockedNotifications_blockedApp() throws Exception { 1738 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1739 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1740 1741 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1742 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1743 "testEnqueuedBlockedNotifications_blockedApp", 1744 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1745 waitForIdle(); 1746 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1747 } 1748 1749 @Test testEnqueuedBlockedNotifications_blockedAppForegroundService()1750 public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception { 1751 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1752 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1753 when(mAmi.applyForegroundServiceNotification( 1754 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1755 1756 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1757 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1758 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1759 "testEnqueuedBlockedNotifications_blockedAppForegroundService", 1760 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1761 waitForIdle(); 1762 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1763 assertNull(mService.getNotificationRecord(sbn.getKey())); 1764 } 1765 1766 /** 1767 * Confirm an application with the SEND_CATEGORY_CAR_NOTIFICATIONS permission on automotive 1768 * devices can use car categories. 1769 */ 1770 @Test testEnqueuedRestrictedNotifications_hasPermission()1771 public void testEnqueuedRestrictedNotifications_hasPermission() throws Exception { 1772 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1773 .thenReturn(true); 1774 // SEND_CATEGORY_CAR_NOTIFICATIONS is a system-level permission that this test cannot 1775 // obtain. Mocking out enforce permission call to ensure notifications can be created when 1776 // permitted. 1777 doNothing().when(mContext).enforceCallingPermission( 1778 eq("android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"), anyString()); 1779 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1780 Notification.CATEGORY_CAR_WARNING, 1781 Notification.CATEGORY_CAR_INFORMATION); 1782 int id = 0; 1783 for (String category: categories) { 1784 final StatusBarNotification sbn = 1785 generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn(); 1786 sbn.getNotification().category = category; 1787 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1788 "testEnqueuedRestrictedNotifications_asSystem", 1789 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1790 } 1791 waitForIdle(); 1792 assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length); 1793 } 1794 1795 1796 /** 1797 * Confirm restricted notification categories only apply to automotive. 1798 */ 1799 @Test testEnqueuedRestrictedNotifications_notAutomotive()1800 public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception { 1801 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1802 .thenReturn(false); 1803 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1804 Notification.CATEGORY_CAR_WARNING, 1805 Notification.CATEGORY_CAR_INFORMATION); 1806 int id = 0; 1807 for (String category: categories) { 1808 final StatusBarNotification sbn = 1809 generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn(); 1810 sbn.getNotification().category = category; 1811 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1812 "testEnqueuedRestrictedNotifications_notAutomotive", 1813 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1814 } 1815 waitForIdle(); 1816 assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length); 1817 } 1818 1819 /** 1820 * Confirm if an application tries to use the car categories on a automotive device without the 1821 * SEND_CATEGORY_CAR_NOTIFICATIONS permission that a security exception will be thrown. 1822 */ 1823 @Test testEnqueuedRestrictedNotifications_noPermission()1824 public void testEnqueuedRestrictedNotifications_noPermission() throws Exception { 1825 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1826 .thenReturn(true); 1827 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1828 Notification.CATEGORY_CAR_WARNING, 1829 Notification.CATEGORY_CAR_INFORMATION); 1830 for (String category: categories) { 1831 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1832 sbn.getNotification().category = category; 1833 try { 1834 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1835 "testEnqueuedRestrictedNotifications_badUser", 1836 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1837 fail("Calls from non system apps should not allow use of restricted categories"); 1838 } catch (SecurityException e) { 1839 // pass 1840 } 1841 } 1842 waitForIdle(); 1843 assertEquals(0, mBinderService.getActiveNotifications(mPkg).length); 1844 } 1845 1846 @Test testSetNotificationsEnabledForPackage_noChange()1847 public void testSetNotificationsEnabledForPackage_noChange() throws Exception { 1848 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1849 mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true); 1850 1851 verify(mPermissionHelper, never()).setNotificationPermission( 1852 anyString(), anyInt(), anyBoolean(), anyBoolean()); 1853 } 1854 1855 @Test testSetNotificationsEnabledForPackage()1856 public void testSetNotificationsEnabledForPackage() throws Exception { 1857 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1858 mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false); 1859 1860 verify(mPermissionHelper).setNotificationPermission( 1861 mContext.getPackageName(), mUserId, false, true); 1862 1863 verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt()); 1864 List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls(); 1865 Assert.assertEquals( 1866 NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED, 1867 calls.get(calls.size() -1).event); 1868 } 1869 1870 @Test testBlockedNotifications_blockedByAssistant()1871 public void testBlockedNotifications_blockedByAssistant() throws Exception { 1872 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1873 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 1874 1875 NotificationChannel channel = new NotificationChannel("id", "name", 1876 NotificationManager.IMPORTANCE_HIGH); 1877 NotificationRecord r = generateNotificationRecord(channel); 1878 mService.addEnqueuedNotification(r); 1879 1880 Bundle bundle = new Bundle(); 1881 bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE); 1882 Adjustment adjustment = new Adjustment( 1883 r.getSbn().getPackageName(), r.getKey(), bundle, "", r.getUser().getIdentifier()); 1884 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 1885 1886 NotificationManagerService.PostNotificationRunnable runnable = 1887 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1888 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 1889 runnable.run(); 1890 waitForIdle(); 1891 1892 verify(mUsageStats, never()).registerPostedByApp(any()); 1893 } 1894 1895 @Test testBlockedNotifications_blockedByUser()1896 public void testBlockedNotifications_blockedByUser() throws Exception { 1897 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1898 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 1899 1900 NotificationChannel channel = new NotificationChannel("id", "name", 1901 NotificationManager.IMPORTANCE_HIGH); 1902 NotificationRecord r = generateNotificationRecord(channel); 1903 mService.addEnqueuedNotification(r); 1904 1905 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 1906 1907 NotificationManagerService.PostNotificationRunnable runnable = 1908 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1909 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 1910 runnable.run(); 1911 waitForIdle(); 1912 1913 verify(mUsageStats).registerBlocked(any()); 1914 verify(mUsageStats, never()).registerPostedByApp(any()); 1915 } 1916 1917 @Test testEnqueueNotificationInternal_noChannel()1918 public void testEnqueueNotificationInternal_noChannel() throws Exception { 1919 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1920 NotificationRecord nr = generateNotificationRecord( 1921 new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT)); 1922 1923 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 1924 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 1925 waitForIdle(); 1926 1927 verify(mPermissionHelper).hasPermission(mUid); 1928 verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID); 1929 1930 reset(mPermissionHelper); 1931 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1932 1933 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 1934 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 1935 waitForIdle(); 1936 1937 verify(mPermissionHelper).hasPermission(mUid); 1938 assertThat(mService.mChannelToastsSent).contains(mUid); 1939 } 1940 1941 @Test testEnqueueNotification_appBlocked()1942 public void testEnqueueNotification_appBlocked() throws Exception { 1943 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1944 1945 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1946 "testEnqueueNotification_appBlocked", 0, 1947 generateNotificationRecord(null).getNotification(), mUserId); 1948 waitForIdle(); 1949 verify(mWorkerHandler, never()).post( 1950 any(NotificationManagerService.EnqueueNotificationRunnable.class)); 1951 } 1952 1953 @Test testEnqueueNotificationWithTag_PopulatesGetActiveNotifications()1954 public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception { 1955 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1956 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 1957 generateNotificationRecord(null).getNotification(), mUserId); 1958 waitForIdle(); 1959 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 1960 assertEquals(1, notifs.length); 1961 assertEquals(1, mService.getNotificationRecordCount()); 1962 } 1963 1964 @Test testEnqueueNotificationWithTag_WritesExpectedLogs()1965 public void testEnqueueNotificationWithTag_WritesExpectedLogs() throws Exception { 1966 final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog"; 1967 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 1968 generateNotificationRecord(null).getNotification(), mUserId); 1969 waitForIdle(); 1970 assertEquals(1, mNotificationRecordLogger.numCalls()); 1971 1972 NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0); 1973 assertTrue(call.wasLogged); 1974 assertEquals(NOTIFICATION_POSTED, call.event); 1975 assertNotNull(call.r); 1976 assertNull(call.old); 1977 assertEquals(0, call.position); 1978 assertEquals(0, call.buzzBeepBlink); 1979 assertEquals(mPkg, call.r.getSbn().getPackageName()); 1980 assertEquals(0, call.r.getSbn().getId()); 1981 assertEquals(tag, call.r.getSbn().getTag()); 1982 assertEquals(1, call.getInstanceId()); // Fake instance IDs are assigned in order 1983 assertThat(call.postDurationMillisLogged).isGreaterThan(0); 1984 } 1985 1986 @Test testEnqueueNotificationWithTag_LogsOnMajorUpdates()1987 public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception { 1988 final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates"; 1989 Notification original = new Notification.Builder(mContext, 1990 mTestNotificationChannel.getId()) 1991 .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); 1992 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, original, mUserId); 1993 Notification update = new Notification.Builder(mContext, 1994 mTestNotificationChannel.getId()) 1995 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1996 .setCategory(Notification.CATEGORY_ALARM).build(); 1997 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, update, mUserId); 1998 waitForIdle(); 1999 assertEquals(2, mNotificationRecordLogger.numCalls()); 2000 2001 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2002 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2003 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 2004 assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0); 2005 2006 assertTrue(mNotificationRecordLogger.get(1).wasLogged); 2007 assertEquals(NOTIFICATION_UPDATED, mNotificationRecordLogger.event(1)); 2008 // Instance ID doesn't change on update of an active notification 2009 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 2010 assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isGreaterThan(0); 2011 } 2012 2013 @Test testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate()2014 public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate() throws Exception { 2015 final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate"; 2016 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2017 generateNotificationRecord(null).getNotification(), mUserId); 2018 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2019 generateNotificationRecord(null).getNotification(), mUserId); 2020 waitForIdle(); 2021 assertEquals(2, mNotificationRecordLogger.numCalls()); 2022 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2023 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2024 assertFalse(mNotificationRecordLogger.get(1).wasLogged); 2025 assertNull(mNotificationRecordLogger.event(1)); 2026 } 2027 2028 @Test testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate()2029 public void testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate() throws Exception { 2030 final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate"; 2031 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2032 generateNotificationRecord(null).getNotification(), 2033 mUserId); 2034 final Notification notif = generateNotificationRecord(null).getNotification(); 2035 notif.extras.putString(Notification.EXTRA_TITLE, "Changed title"); 2036 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notif, mUserId); 2037 waitForIdle(); 2038 assertEquals(2, mNotificationRecordLogger.numCalls()); 2039 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2040 assertNull(mNotificationRecordLogger.event(1)); 2041 } 2042 2043 @Test testEnqueueNotificationWithTag_LogsAgainAfterCancel()2044 public void testEnqueueNotificationWithTag_LogsAgainAfterCancel() throws Exception { 2045 final String tag = "testEnqueueNotificationWithTag_LogsAgainAfterCancel"; 2046 Notification notification = new Notification.Builder(mContext, 2047 mTestNotificationChannel.getId()) 2048 .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); 2049 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId); 2050 waitForIdle(); 2051 mBinderService.cancelNotificationWithTag(mPkg, mPkg, tag, 0, mUserId); 2052 waitForIdle(); 2053 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId); 2054 waitForIdle(); 2055 assertEquals(3, mNotificationRecordLogger.numCalls()); 2056 2057 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2058 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2059 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 2060 assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0); 2061 2062 assertEquals( 2063 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL, 2064 mNotificationRecordLogger.event(1)); 2065 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 2066 // Cancel is not post, so no logged post_duration_millis. 2067 assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isNull(); 2068 2069 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(2)); 2070 assertTrue(mNotificationRecordLogger.get(2).wasLogged); 2071 // New instance ID because notification was canceled before re-post 2072 assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId()); 2073 assertThat(mNotificationRecordLogger.get(2).postDurationMillisLogged).isGreaterThan(0); 2074 } 2075 2076 @Test testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed()2077 public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception { 2078 when(mAmi.applyForegroundServiceNotification( 2079 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 2080 mContext.getTestablePermissions().setPermission( 2081 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); 2082 2083 final String tag = "testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed"; 2084 2085 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2086 .setContentTitle("foo") 2087 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2088 .setFlag(FLAG_FOREGROUND_SERVICE, true) 2089 .build(); 2090 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, tag, mUid, 0, 2091 n, UserHandle.getUserHandleForUid(mUid), null, 0); 2092 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 2093 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2094 waitForIdle(); 2095 2096 StatusBarNotification[] notifs = 2097 mBinderService.getActiveNotifications(mPkg); 2098 assertThat(notifs[0].getNotification().flags).isEqualTo( 2099 FLAG_FOREGROUND_SERVICE | FLAG_CAN_COLORIZE | FLAG_NO_CLEAR); 2100 } 2101 2102 @Test testEnqueueNotificationWithTag_nullAction_fixed()2103 public void testEnqueueNotificationWithTag_nullAction_fixed() throws Exception { 2104 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2105 .setContentTitle("foo") 2106 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2107 .addAction(new Notification.Action.Builder(null, "one", null).build()) 2108 .addAction(new Notification.Action.Builder(null, "two", null).build()) 2109 .addAction(new Notification.Action.Builder(null, "three", null).build()) 2110 .build(); 2111 n.actions[1] = null; 2112 2113 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 2114 waitForIdle(); 2115 2116 StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg); 2117 assertThat(posted).hasLength(1); 2118 assertThat(posted[0].getNotification().actions).hasLength(2); 2119 assertThat(posted[0].getNotification().actions[0].title.toString()).isEqualTo("one"); 2120 assertThat(posted[0].getNotification().actions[1].title.toString()).isEqualTo("three"); 2121 } 2122 2123 @Test testEnqueueNotificationWithTag_allNullActions_fixed()2124 public void testEnqueueNotificationWithTag_allNullActions_fixed() throws Exception { 2125 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2126 .setContentTitle("foo") 2127 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2128 .addAction(new Notification.Action.Builder(null, "one", null).build()) 2129 .addAction(new Notification.Action.Builder(null, "two", null).build()) 2130 .build(); 2131 n.actions[0] = null; 2132 n.actions[1] = null; 2133 2134 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 2135 waitForIdle(); 2136 2137 StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg); 2138 assertThat(posted).hasLength(1); 2139 assertThat(posted[0].getNotification().actions).isNull(); 2140 } 2141 2142 @Test enqueueNotificationWithTag_usesAndFinishesTracker()2143 public void enqueueNotificationWithTag_usesAndFinishesTracker() throws Exception { 2144 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2145 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2146 generateNotificationRecord(null).getNotification(), mUserId); 2147 2148 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2149 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isTrue(); 2150 2151 waitForIdle(); 2152 2153 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(1); 2154 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2155 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2156 } 2157 2158 @Test enqueueNotificationWithTag_throws_usesAndCancelsTracker()2159 public void enqueueNotificationWithTag_throws_usesAndCancelsTracker() throws Exception { 2160 // Simulate not enqueued due to rejected inputs. 2161 assertThrows(Exception.class, 2162 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2163 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2164 /* notification= */ null, mUserId)); 2165 2166 waitForIdle(); 2167 2168 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2169 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2170 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2171 } 2172 2173 @Test enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker()2174 public void enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker() throws Exception { 2175 // Simulate not enqueued due to snoozing inputs. 2176 when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any())) 2177 .thenReturn("zzzzzzz"); 2178 2179 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2180 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2181 generateNotificationRecord(null).getNotification(), mUserId); 2182 waitForIdle(); 2183 2184 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2185 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2186 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2187 } 2188 2189 @Test enqueueNotificationWithTag_notPosted_usesAndCancelsTracker()2190 public void enqueueNotificationWithTag_notPosted_usesAndCancelsTracker() throws Exception { 2191 // Simulate not posted due to blocked app. 2192 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 2193 2194 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2195 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2196 generateNotificationRecord(null).getNotification(), mUserId); 2197 waitForIdle(); 2198 2199 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2200 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2201 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2202 } 2203 2204 @Test enqueueNotification_acquiresAndReleasesWakeLock()2205 public void enqueueNotification_acquiresAndReleasesWakeLock() throws Exception { 2206 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2207 "enqueueNotification_acquiresAndReleasesWakeLock", 0, 2208 generateNotificationRecord(null).getNotification(), mUserId); 2209 2210 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2211 assertThat(mAcquiredWakeLocks).hasSize(1); 2212 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2213 2214 waitForIdle(); 2215 2216 assertThat(mAcquiredWakeLocks).hasSize(1); 2217 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2218 } 2219 2220 @Test enqueueNotification_throws_acquiresAndReleasesWakeLock()2221 public void enqueueNotification_throws_acquiresAndReleasesWakeLock() throws Exception { 2222 // Simulate not enqueued due to rejected inputs. 2223 assertThrows(Exception.class, 2224 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2225 "enqueueNotification_throws_acquiresAndReleasesWakeLock", 0, 2226 /* notification= */ null, mUserId)); 2227 2228 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2229 assertThat(mAcquiredWakeLocks).hasSize(1); 2230 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2231 } 2232 2233 @Test enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock()2234 public void enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock() throws Exception { 2235 // Simulate not enqueued due to snoozing inputs. 2236 when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any())) 2237 .thenReturn("zzzzzzz"); 2238 2239 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2240 "enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock", 0, 2241 generateNotificationRecord(null).getNotification(), mUserId); 2242 2243 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2244 assertThat(mAcquiredWakeLocks).hasSize(1); 2245 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2246 2247 waitForIdle(); 2248 2249 assertThat(mAcquiredWakeLocks).hasSize(1); 2250 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2251 } 2252 2253 @Test enqueueNotification_notPosted_acquiresAndReleasesWakeLock()2254 public void enqueueNotification_notPosted_acquiresAndReleasesWakeLock() throws Exception { 2255 // Simulate enqueued but not posted due to missing small icon. 2256 Notification notif = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2257 .setContentTitle("foo") 2258 .build(); 2259 2260 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2261 "enqueueNotification_notPosted_acquiresAndReleasesWakeLock", 0, 2262 notif, mUserId); 2263 2264 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2265 assertThat(mAcquiredWakeLocks).hasSize(1); 2266 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2267 2268 waitForIdle(); 2269 2270 // NLSes were not called. 2271 verify(mListeners, never()).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 2272 2273 assertThat(mAcquiredWakeLocks).hasSize(1); 2274 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2275 } 2276 2277 @Test enqueueNotification_setsWakeLockWorkSource()2278 public void enqueueNotification_setsWakeLockWorkSource() throws Exception { 2279 // Use a "full" mock for the PowerManager (instead of the one that delegates to the real 2280 // service) so we can return a mocked WakeLock that we can verify() on. 2281 reset(mPowerManager); 2282 WakeLock wakeLock = mock(WakeLock.class); 2283 when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(wakeLock); 2284 2285 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2286 "enqueueNotification_setsWakeLockWorkSource", 0, 2287 generateNotificationRecord(null).getNotification(), mUserId); 2288 waitForIdle(); 2289 2290 InOrder inOrder = inOrder(mPowerManager, wakeLock); 2291 inOrder.verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2292 inOrder.verify(wakeLock).setWorkSource(eq(new WorkSource(mUid, mPkg))); 2293 inOrder.verify(wakeLock).acquire(anyLong()); 2294 inOrder.verify(wakeLock).release(); 2295 inOrder.verifyNoMoreInteractions(); 2296 } 2297 2298 @Test testCancelNonexistentNotification()2299 public void testCancelNonexistentNotification() throws Exception { 2300 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2301 "testCancelNonexistentNotification", 0, mUserId); 2302 waitForIdle(); 2303 // The notification record logger doesn't even get called when a nonexistent notification 2304 // is cancelled, because that happens very frequently and is not interesting. 2305 assertEquals(0, mNotificationRecordLogger.numCalls()); 2306 } 2307 2308 @Test testCancelNotificationImmediatelyAfterEnqueue()2309 public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception { 2310 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2311 "testCancelNotificationImmediatelyAfterEnqueue", 0, 2312 generateNotificationRecord(null).getNotification(), mUserId); 2313 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2314 "testCancelNotificationImmediatelyAfterEnqueue", 0, mUserId); 2315 waitForIdle(); 2316 StatusBarNotification[] notifs = 2317 mBinderService.getActiveNotifications(mPkg); 2318 assertEquals(0, notifs.length); 2319 assertEquals(0, mService.getNotificationRecordCount()); 2320 } 2321 2322 @Test testPostCancelPostNotifiesListeners()2323 public void testPostCancelPostNotifiesListeners() throws Exception { 2324 // WHEN a notification is posted 2325 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2326 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), 2327 sbn.getNotification(), sbn.getUserId()); 2328 mTestableLooper.moveTimeForward(1); 2329 // THEN it is canceled 2330 mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId()); 2331 mTestableLooper.moveTimeForward(1); 2332 // THEN it is posted again (before the cancel has a chance to finish) 2333 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), 2334 sbn.getNotification(), sbn.getUserId()); 2335 // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected 2336 waitForIdle(); 2337 2338 // The final enqueue made it to the listener instead of being canceled 2339 StatusBarNotification[] notifs = 2340 mBinderService.getActiveNotifications(mPkg); 2341 assertEquals(1, notifs.length); 2342 assertEquals(1, mService.getNotificationRecordCount()); 2343 } 2344 2345 @Test testCancelNotificationWhilePostedAndEnqueued()2346 public void testCancelNotificationWhilePostedAndEnqueued() throws Exception { 2347 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2348 "testCancelNotificationWhilePostedAndEnqueued", 0, 2349 generateNotificationRecord(null).getNotification(), mUserId); 2350 waitForIdle(); 2351 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2352 "testCancelNotificationWhilePostedAndEnqueued", 0, 2353 generateNotificationRecord(null).getNotification(), mUserId); 2354 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2355 "testCancelNotificationWhilePostedAndEnqueued", 0, mUserId); 2356 waitForIdle(); 2357 StatusBarNotification[] notifs = 2358 mBinderService.getActiveNotifications(mPkg); 2359 assertEquals(0, notifs.length); 2360 assertEquals(0, mService.getNotificationRecordCount()); 2361 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 2362 verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture()); 2363 assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface()); 2364 } 2365 2366 @Test testCancelNotificationsFromListenerImmediatelyAfterEnqueue()2367 public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception { 2368 NotificationRecord r = generateNotificationRecord(null); 2369 final StatusBarNotification sbn = r.getSbn(); 2370 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2371 "testCancelNotificationsFromListenerImmediatelyAfterEnqueue", 2372 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2373 mBinderService.cancelNotificationsFromListener(null, null); 2374 waitForIdle(); 2375 StatusBarNotification[] notifs = 2376 mBinderService.getActiveNotifications(sbn.getPackageName()); 2377 assertEquals(0, notifs.length); 2378 assertEquals(0, mService.getNotificationRecordCount()); 2379 } 2380 2381 @Test testCancelAllNotificationsImmediatelyAfterEnqueue()2382 public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception { 2383 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2384 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2385 "testCancelAllNotificationsImmediatelyAfterEnqueue", 2386 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2387 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2388 waitForIdle(); 2389 StatusBarNotification[] notifs = 2390 mBinderService.getActiveNotifications(sbn.getPackageName()); 2391 assertEquals(0, notifs.length); 2392 assertEquals(0, mService.getNotificationRecordCount()); 2393 } 2394 2395 @Test testUserInitiatedClearAll_noLeak()2396 public void testUserInitiatedClearAll_noLeak() throws Exception { 2397 final NotificationRecord n = generateNotificationRecord( 2398 mTestNotificationChannel, 1, "group", true); 2399 2400 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2401 "testUserInitiatedClearAll_noLeak", 2402 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId()); 2403 waitForIdle(); 2404 2405 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 2406 n.getUserId()); 2407 waitForIdle(); 2408 StatusBarNotification[] notifs = 2409 mBinderService.getActiveNotifications(n.getSbn().getPackageName()); 2410 assertEquals(0, notifs.length); 2411 assertEquals(0, mService.getNotificationRecordCount()); 2412 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 2413 verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture()); 2414 assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface()); 2415 } 2416 2417 @Test testCancelAllNotificationsCancelsChildren()2418 public void testCancelAllNotificationsCancelsChildren() throws Exception { 2419 final NotificationRecord parent = generateNotificationRecord( 2420 mTestNotificationChannel, 1, "group1", true); 2421 final NotificationRecord child = generateNotificationRecord( 2422 mTestNotificationChannel, 2, "group1", false); 2423 2424 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2425 "testCancelAllNotificationsCancelsChildren", 2426 parent.getSbn().getId(), parent.getSbn().getNotification(), 2427 parent.getSbn().getUserId()); 2428 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2429 "testCancelAllNotificationsCancelsChildren", 2430 child.getSbn().getId(), child.getSbn().getNotification(), 2431 child.getSbn().getUserId()); 2432 waitForIdle(); 2433 2434 mBinderService.cancelAllNotifications(mPkg, parent.getSbn().getUserId()); 2435 waitForIdle(); 2436 assertEquals(0, mService.getNotificationRecordCount()); 2437 } 2438 2439 @Test testCancelAllNotificationsMultipleEnqueuedDoesNotCrash()2440 public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception { 2441 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2442 for (int i = 0; i < 10; i++) { 2443 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2444 "testCancelAllNotificationsMultipleEnqueuedDoesNotCrash", 2445 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2446 } 2447 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2448 waitForIdle(); 2449 2450 assertEquals(0, mService.getNotificationRecordCount()); 2451 } 2452 2453 @Test testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash()2454 public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception { 2455 final NotificationRecord parent = generateNotificationRecord( 2456 mTestNotificationChannel, 1, "group1", true); 2457 final NotificationRecord parentAsChild = generateNotificationRecord( 2458 mTestNotificationChannel, 1, "group1", false); 2459 final NotificationRecord child = generateNotificationRecord( 2460 mTestNotificationChannel, 2, "group1", false); 2461 2462 // fully post parent notification 2463 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2464 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2465 parent.getSbn().getId(), parent.getSbn().getNotification(), 2466 parent.getSbn().getUserId()); 2467 waitForIdle(); 2468 2469 // enqueue the child several times 2470 for (int i = 0; i < 10; i++) { 2471 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2472 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2473 child.getSbn().getId(), child.getSbn().getNotification(), 2474 child.getSbn().getUserId()); 2475 } 2476 // make the parent a child, which will cancel the child notification 2477 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2478 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2479 parentAsChild.getSbn().getId(), parentAsChild.getSbn().getNotification(), 2480 parentAsChild.getSbn().getUserId()); 2481 waitForIdle(); 2482 2483 assertEquals(0, mService.getNotificationRecordCount()); 2484 } 2485 2486 @Test testAutobundledSummary_notificationAdded()2487 public void testAutobundledSummary_notificationAdded() { 2488 NotificationRecord summary = 2489 generateNotificationRecord(mTestNotificationChannel, 0, "pkg", true); 2490 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2491 mService.addNotification(summary); 2492 mService.mSummaryByGroupKey.put("pkg", summary); 2493 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2494 mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); 2495 2496 mService.updateAutobundledSummaryLocked(0, "pkg", 2497 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, 2498 mock(Icon.class), 0, VISIBILITY_PRIVATE), false); 2499 waitForIdle(); 2500 2501 assertTrue(summary.getSbn().isOngoing()); 2502 } 2503 2504 @Test testAutobundledSummary_notificationRemoved()2505 public void testAutobundledSummary_notificationRemoved() { 2506 NotificationRecord summary = 2507 generateNotificationRecord(mTestNotificationChannel, 0, "pkg", true); 2508 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2509 summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 2510 mService.addNotification(summary); 2511 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2512 mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); 2513 mService.mSummaryByGroupKey.put("pkg", summary); 2514 2515 mService.updateAutobundledSummaryLocked(0, "pkg", 2516 new NotificationAttributes(GroupHelper.BASE_FLAGS, 2517 mock(Icon.class), 0, VISIBILITY_PRIVATE), false); 2518 waitForIdle(); 2519 2520 assertFalse(summary.getSbn().isOngoing()); 2521 } 2522 2523 @Test testCancelAllNotifications_IgnoreForegroundService()2524 public void testCancelAllNotifications_IgnoreForegroundService() throws Exception { 2525 when(mAmi.applyForegroundServiceNotification( 2526 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 2527 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2528 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2529 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2530 "testCancelAllNotifications_IgnoreForegroundService", 2531 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2532 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2533 waitForIdle(); 2534 StatusBarNotification[] notifs = 2535 mBinderService.getActiveNotifications(sbn.getPackageName()); 2536 assertEquals(1, notifs.length); 2537 assertEquals(1, mService.getNotificationRecordCount()); 2538 } 2539 2540 @Test testCancelAllNotifications_FgsFlag_NoFgs_Allowed()2541 public void testCancelAllNotifications_FgsFlag_NoFgs_Allowed() throws Exception { 2542 when(mAmi.applyForegroundServiceNotification( 2543 any(), anyString(), anyInt(), anyString(), anyInt())) 2544 .thenReturn(NOT_FOREGROUND_SERVICE); 2545 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2546 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2547 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2548 "testCancelAllNotifications_IgnoreForegroundService", 2549 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2550 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2551 waitForIdle(); 2552 StatusBarNotification[] notifs = 2553 mBinderService.getActiveNotifications(sbn.getPackageName()); 2554 assertEquals(0, notifs.length); 2555 } 2556 2557 @Test testCancelAllNotifications_IgnoreOtherPackages()2558 public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception { 2559 when(mAmi.applyForegroundServiceNotification( 2560 any(), anyString(), anyInt(), anyString(), anyInt())) 2561 .thenReturn(SHOW_IMMEDIATELY); 2562 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2563 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2564 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2565 "testCancelAllNotifications_IgnoreOtherPackages", 2566 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2567 mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); 2568 waitForIdle(); 2569 StatusBarNotification[] notifs = 2570 mBinderService.getActiveNotifications(sbn.getPackageName()); 2571 assertEquals(1, notifs.length); 2572 assertEquals(1, mService.getNotificationRecordCount()); 2573 } 2574 2575 @Test testCancelAllNotifications_NullPkgRemovesAll()2576 public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception { 2577 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2578 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2579 "testCancelAllNotifications_NullPkgRemovesAll", 2580 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2581 mBinderService.cancelAllNotifications(null, sbn.getUserId()); 2582 waitForIdle(); 2583 StatusBarNotification[] notifs = 2584 mBinderService.getActiveNotifications(sbn.getPackageName()); 2585 assertEquals(0, notifs.length); 2586 assertEquals(0, mService.getNotificationRecordCount()); 2587 } 2588 2589 @Test testCancelAllNotifications_NullPkgIgnoresUserAllNotifications()2590 public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception { 2591 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2592 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2593 "testCancelAllNotifications_NullPkgIgnoresUserAllNotifications", 2594 sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL); 2595 // Null pkg is how we signal a user switch. 2596 mBinderService.cancelAllNotifications(null, sbn.getUserId()); 2597 waitForIdle(); 2598 StatusBarNotification[] notifs = 2599 mBinderService.getActiveNotifications(sbn.getPackageName()); 2600 assertEquals(1, notifs.length); 2601 assertEquals(1, mService.getNotificationRecordCount()); 2602 } 2603 2604 @Test testAppInitiatedCancelAllNotifications_CancelsNoClearFlag()2605 public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception { 2606 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2607 sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR; 2608 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2609 "testAppInitiatedCancelAllNotifications_CancelsNoClearFlag", 2610 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2611 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2612 waitForIdle(); 2613 StatusBarNotification[] notifs = 2614 mBinderService.getActiveNotifications(sbn.getPackageName()); 2615 assertEquals(0, notifs.length); 2616 } 2617 2618 @Test testCancelAllNotifications_CancelsNoClearFlag()2619 public void testCancelAllNotifications_CancelsNoClearFlag() throws Exception { 2620 final NotificationRecord notif = generateNotificationRecord( 2621 mTestNotificationChannel, 1, "group", true); 2622 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 2623 mService.addNotification(notif); 2624 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 2625 notif.getUserId(), REASON_CANCEL); 2626 waitForIdle(); 2627 StatusBarNotification[] notifs = 2628 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 2629 assertEquals(0, notifs.length); 2630 } 2631 2632 @Test testUserInitiatedCancelAllOnClearAll_NoClearFlag()2633 public void testUserInitiatedCancelAllOnClearAll_NoClearFlag() throws Exception { 2634 final NotificationRecord notif = generateNotificationRecord( 2635 mTestNotificationChannel, 1, "group", true); 2636 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 2637 mService.addNotification(notif); 2638 2639 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 2640 notif.getUserId()); 2641 waitForIdle(); 2642 StatusBarNotification[] notifs = 2643 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 2644 assertEquals(1, notifs.length); 2645 } 2646 2647 @Test testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue()2648 public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception { 2649 when(mAmi.applyForegroundServiceNotification( 2650 any(), anyString(), anyInt(), anyString(), anyInt())) 2651 .thenReturn(SHOW_IMMEDIATELY); 2652 Notification n = 2653 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2654 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2655 .build(); 2656 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, 2657 n, UserHandle.getUserHandleForUid(mUid), null, 0); 2658 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2659 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null, 2660 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2661 mInternalService.removeForegroundServiceFlagFromNotification(mPkg, sbn.getId(), 2662 sbn.getUserId()); 2663 waitForIdle(); 2664 StatusBarNotification[] notifs = 2665 mBinderService.getActiveNotifications(sbn.getPackageName()); 2666 assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE); 2667 } 2668 2669 @Test testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag()2670 public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception { 2671 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2672 sbn.getNotification().flags = 2673 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE; 2674 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 2675 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2676 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; 2677 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 2678 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2679 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 2680 sbn.getUserId()); 2681 waitForIdle(); 2682 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 2683 assertEquals(0, mService.getNotificationRecordCount()); 2684 } 2685 2686 @Test 2687 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelWithTagDoesNotCancelLifetimeExtended()2688 public void testCancelWithTagDoesNotCancelLifetimeExtended() throws Exception { 2689 final NotificationRecord notif = generateNotificationRecord(null); 2690 notif.getSbn().getNotification().flags = 2691 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 2692 mService.addNotification(notif); 2693 final StatusBarNotification sbn = notif.getSbn(); 2694 2695 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 2696 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 2697 2698 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 2699 sbn.getUserId()); 2700 waitForIdle(); 2701 2702 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 2703 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 2704 2705 // Checks that a post update is sent. 2706 verify(mWorkerHandler, times(1)) 2707 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 2708 ArgumentCaptor<NotificationRecord> captor = 2709 ArgumentCaptor.forClass(NotificationRecord.class); 2710 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 2711 anyBoolean()); 2712 assertThat(captor.getValue().getNotification().flags 2713 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 2714 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 2715 } 2716 2717 @Test 2718 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelAllClearsLifetimeExtended()2719 public void testCancelAllClearsLifetimeExtended() throws Exception { 2720 final NotificationRecord notif = generateNotificationRecord( 2721 mTestNotificationChannel, 1, "group", true); 2722 notif.getNotification().flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 2723 mService.addNotification(notif); 2724 StatusBarNotification[] notifs = 2725 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 2726 assertThat(notifs.length).isEqualTo(1); 2727 2728 // Simulate a "cancel all" received. 2729 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 2730 notif.getUserId()); 2731 waitForIdle(); 2732 notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 2733 assertThat(notifs.length).isEqualTo(0); 2734 2735 // Test that no update post is sent to System UI. 2736 verify(mWorkerHandler, never()) 2737 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 2738 } 2739 2740 @Test 2741 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testAppCancelAllDoesNotCancelLifetimeExtended()2742 public void testAppCancelAllDoesNotCancelLifetimeExtended() throws Exception { 2743 // Adds a lifetime extended notification. 2744 final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1, 2745 null, false); 2746 notif.getSbn().getNotification().flags = 2747 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 2748 mService.addNotification(notif); 2749 // Adds a second, non-lifetime extended notification. 2750 final NotificationRecord notifCancelable = generateNotificationRecord( 2751 mTestNotificationChannel, 2, null, false); 2752 mService.addNotification(notifCancelable); 2753 // Verify that both notifications have been posted and are active. 2754 assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(2); 2755 2756 mBinderService.cancelAllNotifications(mPkg, notif.getSbn().getUserId()); 2757 waitForIdle(); 2758 2759 // The non-lifetime extended notification, with id = 2, has been cancelled. 2760 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 2761 assertThat(notifs.length).isEqualTo(1); 2762 assertThat(notifs[0].getId()).isEqualTo(1); 2763 2764 // Checks that a post update is sent. 2765 verify(mWorkerHandler, times(1)) 2766 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 2767 ArgumentCaptor<NotificationRecord> captor = 2768 ArgumentCaptor.forClass(NotificationRecord.class); 2769 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 2770 anyBoolean()); 2771 assertThat(captor.getValue().getNotification().flags 2772 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 2773 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 2774 } 2775 2776 @Test testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()2777 public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild() 2778 throws Exception { 2779 when(mAmi.applyForegroundServiceNotification( 2780 any(), anyString(), anyInt(), anyString(), anyInt())) 2781 .thenReturn(SHOW_IMMEDIATELY); 2782 mService.isSystemUid = false; 2783 mService.isSystemAppId = false; 2784 final NotificationRecord parent = generateNotificationRecord( 2785 mTestNotificationChannel, 1, "group", true); 2786 final NotificationRecord child = generateNotificationRecord( 2787 mTestNotificationChannel, 2, "group", false); 2788 final NotificationRecord child2 = generateNotificationRecord( 2789 mTestNotificationChannel, 3, "group", false); 2790 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2791 mService.addNotification(parent); 2792 mService.addNotification(child); 2793 mService.addNotification(child2); 2794 mService.getBinderService().cancelNotificationWithTag( 2795 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 2796 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 2797 waitForIdle(); 2798 StatusBarNotification[] notifs = 2799 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2800 assertEquals(1, notifs.length); 2801 } 2802 2803 @Test testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()2804 public void testCancelNotificationWithTag_fromApp_cannotCancelFgsParent() 2805 throws Exception { 2806 when(mAmi.applyForegroundServiceNotification( 2807 any(), anyString(), anyInt(), anyString(), anyInt())) 2808 .thenReturn(SHOW_IMMEDIATELY); 2809 mService.isSystemUid = false; 2810 mService.isSystemAppId = false; 2811 final NotificationRecord parent = generateNotificationRecord( 2812 mTestNotificationChannel, 1, "group", true); 2813 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2814 final NotificationRecord child = generateNotificationRecord( 2815 mTestNotificationChannel, 2, "group", false); 2816 final NotificationRecord child2 = generateNotificationRecord( 2817 mTestNotificationChannel, 3, "group", false); 2818 mService.addNotification(parent); 2819 mService.addNotification(child); 2820 mService.addNotification(child2); 2821 mService.getBinderService().cancelNotificationWithTag( 2822 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 2823 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 2824 waitForIdle(); 2825 StatusBarNotification[] notifs = 2826 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2827 assertEquals(3, notifs.length); 2828 } 2829 2830 @Test testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()2831 public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild() 2832 throws Exception { 2833 mService.isSystemUid = false; 2834 mService.isSystemAppId = false; 2835 final NotificationRecord parent = generateNotificationRecord( 2836 mTestNotificationChannel, 1, "group", true); 2837 final NotificationRecord child = generateNotificationRecord( 2838 mTestNotificationChannel, 2, "group", false); 2839 final NotificationRecord child2 = generateNotificationRecord( 2840 mTestNotificationChannel, 3, "group", false); 2841 child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 2842 mService.addNotification(parent); 2843 mService.addNotification(child); 2844 mService.addNotification(child2); 2845 mService.getBinderService().cancelNotificationWithTag( 2846 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 2847 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 2848 waitForIdle(); 2849 StatusBarNotification[] notifs = 2850 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2851 assertEquals(0, notifs.length); 2852 } 2853 2854 @Test testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()2855 public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent() 2856 throws Exception { 2857 mService.isSystemUid = false; 2858 mService.isSystemAppId = false; 2859 final NotificationRecord parent = generateNotificationRecord( 2860 mTestNotificationChannel, 1, "group", true); 2861 parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 2862 final NotificationRecord child = generateNotificationRecord( 2863 mTestNotificationChannel, 2, "group", false); 2864 final NotificationRecord child2 = generateNotificationRecord( 2865 mTestNotificationChannel, 3, "group", false); 2866 mService.addNotification(parent); 2867 mService.addNotification(child); 2868 mService.addNotification(child2); 2869 mService.getBinderService().cancelNotificationWithTag( 2870 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 2871 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 2872 waitForIdle(); 2873 StatusBarNotification[] notifs = 2874 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2875 assertEquals(0, notifs.length); 2876 } 2877 2878 @Test testCancelAllNotificationsFromApp_cannotCancelFgsChild()2879 public void testCancelAllNotificationsFromApp_cannotCancelFgsChild() 2880 throws Exception { 2881 when(mAmi.applyForegroundServiceNotification( 2882 any(), anyString(), anyInt(), anyString(), anyInt())) 2883 .thenReturn(SHOW_IMMEDIATELY); 2884 mService.isSystemUid = false; 2885 mService.isSystemAppId = false; 2886 final NotificationRecord parent = generateNotificationRecord( 2887 mTestNotificationChannel, 1, "group", true); 2888 final NotificationRecord child = generateNotificationRecord( 2889 mTestNotificationChannel, 2, "group", false); 2890 final NotificationRecord child2 = generateNotificationRecord( 2891 mTestNotificationChannel, 3, "group", false); 2892 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2893 final NotificationRecord newGroup = generateNotificationRecord( 2894 mTestNotificationChannel, 4, "group2", false); 2895 mService.addNotification(parent); 2896 mService.addNotification(child); 2897 mService.addNotification(child2); 2898 mService.addNotification(newGroup); 2899 mService.getBinderService().cancelAllNotifications( 2900 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 2901 waitForIdle(); 2902 StatusBarNotification[] notifs = 2903 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2904 assertEquals(1, notifs.length); 2905 } 2906 2907 @Test testCancelAllNotifications_fromApp_cannotCancelFgsParent()2908 public void testCancelAllNotifications_fromApp_cannotCancelFgsParent() 2909 throws Exception { 2910 when(mAmi.applyForegroundServiceNotification( 2911 any(), anyString(), anyInt(), anyString(), anyInt())) 2912 .thenReturn(SHOW_IMMEDIATELY); 2913 mService.isSystemUid = false; 2914 mService.isSystemAppId = false; 2915 final NotificationRecord parent = generateNotificationRecord( 2916 mTestNotificationChannel, 1, "group", true); 2917 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 2918 final NotificationRecord child = generateNotificationRecord( 2919 mTestNotificationChannel, 2, "group", false); 2920 final NotificationRecord child2 = generateNotificationRecord( 2921 mTestNotificationChannel, 3, "group", false); 2922 final NotificationRecord newGroup = generateNotificationRecord( 2923 mTestNotificationChannel, 4, "group2", false); 2924 mService.addNotification(parent); 2925 mService.addNotification(child); 2926 mService.addNotification(child2); 2927 mService.addNotification(newGroup); 2928 mService.getBinderService().cancelAllNotifications( 2929 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 2930 waitForIdle(); 2931 StatusBarNotification[] notifs = 2932 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2933 assertEquals(1, notifs.length); 2934 } 2935 2936 @Test testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()2937 public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild() 2938 throws Exception { 2939 mService.isSystemUid = false; 2940 mService.isSystemAppId = false; 2941 final NotificationRecord parent = generateNotificationRecord( 2942 mTestNotificationChannel, 1, "group", true); 2943 final NotificationRecord child = generateNotificationRecord( 2944 mTestNotificationChannel, 2, "group", false); 2945 final NotificationRecord child2 = generateNotificationRecord( 2946 mTestNotificationChannel, 3, "group", false); 2947 child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 2948 final NotificationRecord newGroup = generateNotificationRecord( 2949 mTestNotificationChannel, 4, "group2", false); 2950 mService.addNotification(parent); 2951 mService.addNotification(child); 2952 mService.addNotification(child2); 2953 mService.addNotification(newGroup); 2954 mService.getBinderService().cancelAllNotifications( 2955 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 2956 waitForIdle(); 2957 StatusBarNotification[] notifs = 2958 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2959 assertEquals(0, notifs.length); 2960 } 2961 2962 @Test testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()2963 public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent() 2964 throws Exception { 2965 mService.isSystemUid = false; 2966 mService.isSystemAppId = false; 2967 final NotificationRecord parent = generateNotificationRecord( 2968 mTestNotificationChannel, 1, "group", true); 2969 parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 2970 final NotificationRecord child = generateNotificationRecord( 2971 mTestNotificationChannel, 2, "group", false); 2972 final NotificationRecord child2 = generateNotificationRecord( 2973 mTestNotificationChannel, 3, "group", false); 2974 final NotificationRecord newGroup = generateNotificationRecord( 2975 mTestNotificationChannel, 4, "group2", false); 2976 mService.addNotification(parent); 2977 mService.addNotification(child); 2978 mService.addNotification(child2); 2979 mService.addNotification(newGroup); 2980 mService.getBinderService().cancelAllNotifications( 2981 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 2982 waitForIdle(); 2983 StatusBarNotification[] notifs = 2984 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 2985 assertEquals(0, notifs.length); 2986 } 2987 2988 @Test testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()2989 public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent() 2990 throws Exception { 2991 final NotificationRecord parent = generateNotificationRecord( 2992 mTestNotificationChannel, 1, "group", true); 2993 parent.getNotification().flags |= FLAG_ONGOING_EVENT; 2994 final NotificationRecord child = generateNotificationRecord( 2995 mTestNotificationChannel, 2, "group", false); 2996 final NotificationRecord child2 = generateNotificationRecord( 2997 mTestNotificationChannel, 3, "group", false); 2998 final NotificationRecord newGroup = generateNotificationRecord( 2999 mTestNotificationChannel, 4, "group2", false); 3000 mService.addNotification(parent); 3001 mService.addNotification(child); 3002 mService.addNotification(child2); 3003 mService.addNotification(newGroup); 3004 mService.getBinderService().cancelNotificationsFromListener(null, null); 3005 waitForIdle(); 3006 StatusBarNotification[] notifs = 3007 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3008 assertEquals(1, notifs.length); 3009 } 3010 3011 @Test testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()3012 public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild() 3013 throws Exception { 3014 final NotificationRecord parent = generateNotificationRecord( 3015 mTestNotificationChannel, 1, "group", true); 3016 final NotificationRecord child = generateNotificationRecord( 3017 mTestNotificationChannel, 2, "group", false); 3018 final NotificationRecord child2 = generateNotificationRecord( 3019 mTestNotificationChannel, 3, "group", false); 3020 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3021 final NotificationRecord newGroup = generateNotificationRecord( 3022 mTestNotificationChannel, 4, "group2", false); 3023 mService.addNotification(parent); 3024 mService.addNotification(child); 3025 mService.addNotification(child2); 3026 mService.addNotification(newGroup); 3027 mService.getBinderService().cancelNotificationsFromListener(null, null); 3028 waitForIdle(); 3029 StatusBarNotification[] notifs = 3030 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3031 assertEquals(1, notifs.length); 3032 } 3033 3034 @Test testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()3035 public void testCancelNotificationsFromListener_clearAll_GroupWithFgsParent() 3036 throws Exception { 3037 when(mAmi.applyForegroundServiceNotification( 3038 any(), anyString(), anyInt(), anyString(), anyInt())) 3039 .thenReturn(SHOW_IMMEDIATELY); 3040 final NotificationRecord parent = generateNotificationRecord( 3041 mTestNotificationChannel, 1, "group", true); 3042 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3043 final NotificationRecord child = generateNotificationRecord( 3044 mTestNotificationChannel, 2, "group", false); 3045 final NotificationRecord child2 = generateNotificationRecord( 3046 mTestNotificationChannel, 3, "group", false); 3047 final NotificationRecord newGroup = generateNotificationRecord( 3048 mTestNotificationChannel, 4, "group2", false); 3049 mService.addNotification(parent); 3050 mService.addNotification(child); 3051 mService.addNotification(child2); 3052 mService.addNotification(newGroup); 3053 mService.getBinderService().cancelNotificationsFromListener(null, null); 3054 waitForIdle(); 3055 StatusBarNotification[] notifs = 3056 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3057 assertEquals(0, notifs.length); 3058 } 3059 3060 @Test testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()3061 public void testCancelNotificationsFromListener_clearAll_GroupWithFgsChild() 3062 throws Exception { 3063 when(mAmi.applyForegroundServiceNotification( 3064 any(), anyString(), anyInt(), anyString(), anyInt())) 3065 .thenReturn(SHOW_IMMEDIATELY); 3066 final NotificationRecord parent = generateNotificationRecord( 3067 mTestNotificationChannel, 1, "group", true); 3068 final NotificationRecord child = generateNotificationRecord( 3069 mTestNotificationChannel, 2, "group", false); 3070 final NotificationRecord child2 = generateNotificationRecord( 3071 mTestNotificationChannel, 3, "group", false); 3072 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3073 final NotificationRecord newGroup = generateNotificationRecord( 3074 mTestNotificationChannel, 4, "group2", false); 3075 mService.addNotification(parent); 3076 mService.addNotification(child); 3077 mService.addNotification(child2); 3078 mService.addNotification(newGroup); 3079 mService.getBinderService().cancelNotificationsFromListener(null, null); 3080 waitForIdle(); 3081 StatusBarNotification[] notifs = 3082 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3083 assertEquals(0, notifs.length); 3084 } 3085 3086 @Test testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()3087 public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent() 3088 throws Exception { 3089 final NotificationRecord parent = generateNotificationRecord( 3090 mTestNotificationChannel, 1, "group", true); 3091 parent.getNotification().flags |= FLAG_NO_CLEAR; 3092 final NotificationRecord child = generateNotificationRecord( 3093 mTestNotificationChannel, 2, "group", false); 3094 final NotificationRecord child2 = generateNotificationRecord( 3095 mTestNotificationChannel, 3, "group", false); 3096 final NotificationRecord newGroup = generateNotificationRecord( 3097 mTestNotificationChannel, 4, "group2", false); 3098 mService.addNotification(parent); 3099 mService.addNotification(child); 3100 mService.addNotification(child2); 3101 mService.addNotification(newGroup); 3102 mService.getBinderService().cancelNotificationsFromListener(null, null); 3103 waitForIdle(); 3104 StatusBarNotification[] notifs = 3105 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3106 assertEquals(1, notifs.length); 3107 } 3108 3109 @Test testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()3110 public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild() 3111 throws Exception { 3112 final NotificationRecord parent = generateNotificationRecord( 3113 mTestNotificationChannel, 1, "group", true); 3114 final NotificationRecord child = generateNotificationRecord( 3115 mTestNotificationChannel, 2, "group", false); 3116 final NotificationRecord child2 = generateNotificationRecord( 3117 mTestNotificationChannel, 3, "group", false); 3118 child2.getNotification().flags |= FLAG_NO_CLEAR; 3119 final NotificationRecord newGroup = generateNotificationRecord( 3120 mTestNotificationChannel, 4, "group2", false); 3121 mService.addNotification(parent); 3122 mService.addNotification(child); 3123 mService.addNotification(child2); 3124 mService.addNotification(newGroup); 3125 mService.getBinderService().cancelNotificationsFromListener(null, null); 3126 waitForIdle(); 3127 StatusBarNotification[] notifs = 3128 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3129 assertEquals(1, notifs.length); 3130 } 3131 3132 @Test testCancelNotificationsFromListener_clearAll_Ongoing()3133 public void testCancelNotificationsFromListener_clearAll_Ongoing() 3134 throws Exception { 3135 final NotificationRecord child2 = generateNotificationRecord( 3136 mTestNotificationChannel, 3, null, false); 3137 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3138 mService.addNotification(child2); 3139 String[] keys = {child2.getSbn().getKey()}; 3140 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3141 waitForIdle(); 3142 StatusBarNotification[] notifs = 3143 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3144 assertEquals(1, notifs.length); 3145 } 3146 3147 @Test testCancelNotificationsFromListener_clearAll_NoClear()3148 public void testCancelNotificationsFromListener_clearAll_NoClear() 3149 throws Exception { 3150 final NotificationRecord child2 = generateNotificationRecord( 3151 mTestNotificationChannel, 3, null, false); 3152 child2.getNotification().flags |= FLAG_NO_CLEAR; 3153 mService.addNotification(child2); 3154 mService.getBinderService().cancelNotificationsFromListener(null, null); 3155 waitForIdle(); 3156 StatusBarNotification[] notifs = 3157 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3158 assertEquals(1, notifs.length); 3159 } 3160 3161 @Test testCancelNotificationsFromListener_clearAll_Fgs()3162 public void testCancelNotificationsFromListener_clearAll_Fgs() 3163 throws Exception { 3164 when(mAmi.applyForegroundServiceNotification( 3165 any(), anyString(), anyInt(), anyString(), anyInt())) 3166 .thenReturn(SHOW_IMMEDIATELY); 3167 final NotificationRecord child2 = generateNotificationRecord( 3168 mTestNotificationChannel, 3, null, false); 3169 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3170 mService.addNotification(child2); 3171 mService.getBinderService().cancelNotificationsFromListener(null, null); 3172 waitForIdle(); 3173 StatusBarNotification[] notifs = 3174 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3175 assertEquals(0, notifs.length); 3176 } 3177 3178 @Test 3179 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()3180 public void testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt() 3181 throws Exception { 3182 final NotificationRecord notif = generateNotificationRecord( 3183 mTestNotificationChannel, 1, null, false); 3184 notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3185 mService.addNotification(notif); 3186 verify(mWorkerHandler, times(0)) 3187 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3188 mService.getBinderService().cancelNotificationsFromListener(null, null); 3189 waitForIdle(); 3190 // Notification not cancelled. 3191 StatusBarNotification[] notifs = 3192 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3193 assertThat(notifs.length).isEqualTo(1); 3194 3195 // Checks that a post update is sent. 3196 verify(mWorkerHandler, times(1)) 3197 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3198 ArgumentCaptor<NotificationRecord> captor = 3199 ArgumentCaptor.forClass(NotificationRecord.class); 3200 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3201 anyBoolean()); 3202 assertThat(captor.getValue().getNotification().flags 3203 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3204 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3205 } 3206 3207 @Test testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()3208 public void testCancelNotificationsFromListener_byKey_GroupWithOngoingParent() 3209 throws Exception { 3210 final NotificationRecord parent = generateNotificationRecord( 3211 mTestNotificationChannel, 1, "group", true); 3212 parent.getNotification().flags |= FLAG_ONGOING_EVENT; 3213 final NotificationRecord child = generateNotificationRecord( 3214 mTestNotificationChannel, 2, "group", false); 3215 final NotificationRecord child2 = generateNotificationRecord( 3216 mTestNotificationChannel, 3, "group", false); 3217 final NotificationRecord newGroup = generateNotificationRecord( 3218 mTestNotificationChannel, 4, "group2", false); 3219 mService.addNotification(parent); 3220 mService.addNotification(child); 3221 mService.addNotification(child2); 3222 mService.addNotification(newGroup); 3223 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3224 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3225 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3226 waitForIdle(); 3227 StatusBarNotification[] notifs = 3228 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3229 assertEquals(1, notifs.length); 3230 } 3231 3232 @Test testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()3233 public void testCancelNotificationsFromListener_byKey_GroupWithOngoingChild() 3234 throws Exception { 3235 final NotificationRecord parent = generateNotificationRecord( 3236 mTestNotificationChannel, 1, "group", true); 3237 final NotificationRecord child = generateNotificationRecord( 3238 mTestNotificationChannel, 2, "group", false); 3239 final NotificationRecord child2 = generateNotificationRecord( 3240 mTestNotificationChannel, 3, "group", false); 3241 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3242 final NotificationRecord newGroup = generateNotificationRecord( 3243 mTestNotificationChannel, 4, "group2", false); 3244 mService.addNotification(parent); 3245 mService.addNotification(child); 3246 mService.addNotification(child2); 3247 mService.addNotification(newGroup); 3248 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3249 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3250 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3251 waitForIdle(); 3252 StatusBarNotification[] notifs = 3253 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3254 assertEquals(1, notifs.length); 3255 } 3256 3257 @Test testCancelNotificationsFromListener_byKey_GroupWithFgsParent()3258 public void testCancelNotificationsFromListener_byKey_GroupWithFgsParent() 3259 throws Exception { 3260 when(mAmi.applyForegroundServiceNotification( 3261 any(), anyString(), anyInt(), anyString(), anyInt())) 3262 .thenReturn(SHOW_IMMEDIATELY); 3263 final NotificationRecord parent = generateNotificationRecord( 3264 mTestNotificationChannel, 1, "group", true); 3265 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3266 final NotificationRecord child = generateNotificationRecord( 3267 mTestNotificationChannel, 2, "group", false); 3268 final NotificationRecord child2 = generateNotificationRecord( 3269 mTestNotificationChannel, 3, "group", false); 3270 final NotificationRecord newGroup = generateNotificationRecord( 3271 mTestNotificationChannel, 4, "group2", false); 3272 mService.addNotification(parent); 3273 mService.addNotification(child); 3274 mService.addNotification(child2); 3275 mService.addNotification(newGroup); 3276 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3277 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3278 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3279 waitForIdle(); 3280 StatusBarNotification[] notifs = 3281 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3282 assertEquals(0, notifs.length); 3283 } 3284 3285 @Test testCancelNotificationsFromListener_byKey_GroupWithFgsChild()3286 public void testCancelNotificationsFromListener_byKey_GroupWithFgsChild() 3287 throws Exception { 3288 when(mAmi.applyForegroundServiceNotification( 3289 any(), anyString(), anyInt(), anyString(), anyInt())) 3290 .thenReturn(SHOW_IMMEDIATELY); 3291 final NotificationRecord parent = generateNotificationRecord( 3292 mTestNotificationChannel, 1, "group", true); 3293 final NotificationRecord child = generateNotificationRecord( 3294 mTestNotificationChannel, 2, "group", false); 3295 final NotificationRecord child2 = generateNotificationRecord( 3296 mTestNotificationChannel, 3, "group", false); 3297 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3298 final NotificationRecord newGroup = generateNotificationRecord( 3299 mTestNotificationChannel, 4, "group2", false); 3300 mService.addNotification(parent); 3301 mService.addNotification(child); 3302 mService.addNotification(child2); 3303 mService.addNotification(newGroup); 3304 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3305 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3306 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3307 waitForIdle(); 3308 StatusBarNotification[] notifs = 3309 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3310 assertEquals(0, notifs.length); 3311 } 3312 3313 @Test testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()3314 public void testCancelNotificationsFromListener_byKey_GroupWithNoClearParent() 3315 throws Exception { 3316 final NotificationRecord parent = generateNotificationRecord( 3317 mTestNotificationChannel, 1, "group", true); 3318 parent.getNotification().flags |= FLAG_NO_CLEAR; 3319 final NotificationRecord child = generateNotificationRecord( 3320 mTestNotificationChannel, 2, "group", false); 3321 final NotificationRecord child2 = generateNotificationRecord( 3322 mTestNotificationChannel, 3, "group", false); 3323 final NotificationRecord newGroup = generateNotificationRecord( 3324 mTestNotificationChannel, 4, "group2", false); 3325 mService.addNotification(parent); 3326 mService.addNotification(child); 3327 mService.addNotification(child2); 3328 mService.addNotification(newGroup); 3329 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3330 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3331 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3332 waitForIdle(); 3333 StatusBarNotification[] notifs = 3334 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3335 assertEquals(0, notifs.length); 3336 } 3337 3338 @Test testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()3339 public void testCancelNotificationsFromListener_byKey_GroupWithNoClearChild() 3340 throws Exception { 3341 final NotificationRecord parent = generateNotificationRecord( 3342 mTestNotificationChannel, 1, "group", true); 3343 final NotificationRecord child = generateNotificationRecord( 3344 mTestNotificationChannel, 2, "group", false); 3345 final NotificationRecord child2 = generateNotificationRecord( 3346 mTestNotificationChannel, 3, "group", false); 3347 child2.getNotification().flags |= FLAG_NO_CLEAR; 3348 final NotificationRecord newGroup = generateNotificationRecord( 3349 mTestNotificationChannel, 4, "group2", false); 3350 mService.addNotification(parent); 3351 mService.addNotification(child); 3352 mService.addNotification(child2); 3353 mService.addNotification(newGroup); 3354 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3355 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3356 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3357 waitForIdle(); 3358 StatusBarNotification[] notifs = 3359 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3360 assertEquals(0, notifs.length); 3361 } 3362 3363 @Test testCancelNotificationsFromListener_byKey_Ongoing()3364 public void testCancelNotificationsFromListener_byKey_Ongoing() 3365 throws Exception { 3366 final NotificationRecord child2 = generateNotificationRecord( 3367 mTestNotificationChannel, 3, null, false); 3368 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3369 mService.addNotification(child2); 3370 String[] keys = {child2.getSbn().getKey()}; 3371 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3372 waitForIdle(); 3373 StatusBarNotification[] notifs = 3374 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3375 assertEquals(1, notifs.length); 3376 } 3377 3378 @Test testCancelNotificationsFromListener_byKey_NoClear()3379 public void testCancelNotificationsFromListener_byKey_NoClear() 3380 throws Exception { 3381 final NotificationRecord child2 = generateNotificationRecord( 3382 mTestNotificationChannel, 3, null, false); 3383 child2.getNotification().flags |= FLAG_NO_CLEAR; 3384 mService.addNotification(child2); 3385 String[] keys = {child2.getSbn().getKey()}; 3386 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3387 waitForIdle(); 3388 StatusBarNotification[] notifs = 3389 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3390 assertEquals(0, notifs.length); 3391 } 3392 3393 @Test testCancelNotificationsFromListener_byKey_Fgs()3394 public void testCancelNotificationsFromListener_byKey_Fgs() 3395 throws Exception { 3396 when(mAmi.applyForegroundServiceNotification( 3397 any(), anyString(), anyInt(), anyString(), anyInt())) 3398 .thenReturn(SHOW_IMMEDIATELY); 3399 final NotificationRecord child2 = generateNotificationRecord( 3400 mTestNotificationChannel, 3, null, false); 3401 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3402 mService.addNotification(child2); 3403 String[] keys = {child2.getSbn().getKey()}; 3404 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3405 waitForIdle(); 3406 StatusBarNotification[] notifs = 3407 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3408 assertEquals(0, notifs.length); 3409 } 3410 3411 @Test 3412 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()3413 public void testCancelNotificationsFromListener_byKey_NoClearLifetimeExt() 3414 throws Exception { 3415 final NotificationRecord notif = generateNotificationRecord( 3416 mTestNotificationChannel, 3, null, false); 3417 notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3418 mService.addNotification(notif); 3419 String[] keys = {notif.getSbn().getKey()}; 3420 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3421 waitForIdle(); 3422 StatusBarNotification[] notifs = 3423 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3424 assertEquals(1, notifs.length); 3425 3426 // Checks that a post update is sent. 3427 verify(mWorkerHandler, times(1)) 3428 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3429 ArgumentCaptor<NotificationRecord> captor = 3430 ArgumentCaptor.forClass(NotificationRecord.class); 3431 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3432 anyBoolean()); 3433 assertThat(captor.getValue().getNotification().flags 3434 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3435 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3436 } 3437 3438 @Test testGroupInstanceIds()3439 public void testGroupInstanceIds() throws Exception { 3440 final NotificationRecord group1 = generateNotificationRecord( 3441 mTestNotificationChannel, 1, "group1", true); 3442 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds", 3443 group1.getSbn().getId(), group1.getSbn().getNotification(), 3444 group1.getSbn().getUserId()); 3445 waitForIdle(); 3446 3447 // same group, child, should be returned 3448 final NotificationRecord group1Child = generateNotificationRecord( 3449 mTestNotificationChannel, 2, "group1", false); 3450 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds", 3451 group1Child.getSbn().getId(), 3452 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); 3453 waitForIdle(); 3454 3455 assertEquals(2, mNotificationRecordLogger.numCalls()); 3456 assertEquals(mNotificationRecordLogger.get(0).getInstanceId(), 3457 mNotificationRecordLogger.get(1).groupInstanceId.getId()); 3458 } 3459 3460 @Test testFindGroupNotificationsLocked()3461 public void testFindGroupNotificationsLocked() throws Exception { 3462 // make sure the same notification can be found in both lists and returned 3463 final NotificationRecord group1 = generateNotificationRecord( 3464 mTestNotificationChannel, 1, "group1", true); 3465 mService.addEnqueuedNotification(group1); 3466 mService.addNotification(group1); 3467 3468 // should not be returned 3469 final NotificationRecord group2 = generateNotificationRecord( 3470 mTestNotificationChannel, 2, "group2", true); 3471 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 3472 group2.getSbn().getId(), group2.getSbn().getNotification(), 3473 group2.getSbn().getUserId()); 3474 waitForIdle(); 3475 3476 // should not be returned 3477 final NotificationRecord nonGroup = generateNotificationRecord( 3478 mTestNotificationChannel, 3, null, false); 3479 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 3480 nonGroup.getSbn().getId(), nonGroup.getSbn().getNotification(), 3481 nonGroup.getSbn().getUserId()); 3482 waitForIdle(); 3483 3484 // same group, child, should be returned 3485 final NotificationRecord group1Child = generateNotificationRecord( 3486 mTestNotificationChannel, 4, "group1", false); 3487 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 3488 group1Child.getSbn().getId(), 3489 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); 3490 waitForIdle(); 3491 3492 List<NotificationRecord> inGroup1 = 3493 mService.findGroupNotificationsLocked(mPkg, group1.getGroupKey(), 3494 group1.getSbn().getUserId()); 3495 assertEquals(3, inGroup1.size()); 3496 for (NotificationRecord record : inGroup1) { 3497 assertTrue(record.getGroupKey().equals(group1.getGroupKey())); 3498 assertTrue(record.getSbn().getId() == 1 || record.getSbn().getId() == 4); 3499 } 3500 } 3501 3502 @Test testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing()3503 public void testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing() throws Exception { 3504 final NotificationRecord notif = generateNotificationRecord( 3505 mTestNotificationChannel, 1, "group", true); 3506 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3507 mService.addNotification(notif); 3508 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 3509 Notification.FLAG_ONGOING_EVENT, notif.getUserId(), REASON_CANCEL); 3510 waitForIdle(); 3511 StatusBarNotification[] notifs = 3512 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3513 assertEquals(0, notifs.length); 3514 } 3515 3516 @Test testAppInitiatedCancelAllNotifications_CancelsOngoingFlag()3517 public void testAppInitiatedCancelAllNotifications_CancelsOngoingFlag() throws Exception { 3518 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3519 sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 3520 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3521 "testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag", 3522 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3523 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 3524 waitForIdle(); 3525 StatusBarNotification[] notifs = 3526 mBinderService.getActiveNotifications(sbn.getPackageName()); 3527 assertEquals(0, notifs.length); 3528 } 3529 3530 @Test testCancelAllNotificationsInt_CancelsOngoingFlag()3531 public void testCancelAllNotificationsInt_CancelsOngoingFlag() throws Exception { 3532 final NotificationRecord notif = generateNotificationRecord( 3533 mTestNotificationChannel, 1, "group", true); 3534 notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 3535 mService.addNotification(notif); 3536 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 3537 notif.getUserId(), REASON_CANCEL); 3538 waitForIdle(); 3539 StatusBarNotification[] notifs = 3540 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3541 assertEquals(0, notifs.length); 3542 } 3543 3544 @Test testUserInitiatedCancelAllWithGroup_OngoingFlag()3545 public void testUserInitiatedCancelAllWithGroup_OngoingFlag() throws Exception { 3546 final NotificationRecord parent = generateNotificationRecord( 3547 mTestNotificationChannel, 1, "group", true); 3548 final NotificationRecord child = generateNotificationRecord( 3549 mTestNotificationChannel, 2, "group", false); 3550 final NotificationRecord child2 = generateNotificationRecord( 3551 mTestNotificationChannel, 3, "group", false); 3552 child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 3553 final NotificationRecord newGroup = generateNotificationRecord( 3554 mTestNotificationChannel, 4, "group2", false); 3555 mService.addNotification(parent); 3556 mService.addNotification(child); 3557 mService.addNotification(child2); 3558 mService.addNotification(newGroup); 3559 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 3560 parent.getUserId()); 3561 waitForIdle(); 3562 StatusBarNotification[] notifs = 3563 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3564 assertEquals(1, notifs.length); 3565 } 3566 3567 @Test testUserInitiatedCancelAllWithGroup_NoClearFlag()3568 public void testUserInitiatedCancelAllWithGroup_NoClearFlag() throws Exception { 3569 final NotificationRecord parent = generateNotificationRecord( 3570 mTestNotificationChannel, 1, "group", true); 3571 final NotificationRecord child = generateNotificationRecord( 3572 mTestNotificationChannel, 2, "group", false); 3573 final NotificationRecord child2 = generateNotificationRecord( 3574 mTestNotificationChannel, 3, "group", false); 3575 child2.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3576 final NotificationRecord newGroup = generateNotificationRecord( 3577 mTestNotificationChannel, 4, "group2", false); 3578 mService.addNotification(parent); 3579 mService.addNotification(child); 3580 mService.addNotification(child2); 3581 mService.addNotification(newGroup); 3582 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 3583 parent.getUserId()); 3584 waitForIdle(); 3585 StatusBarNotification[] notifs = 3586 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3587 assertEquals(1, notifs.length); 3588 } 3589 3590 @Test testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag()3591 public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception { 3592 when(mAmi.applyForegroundServiceNotification( 3593 any(), anyString(), anyInt(), anyString(), anyInt())) 3594 .thenReturn(SHOW_IMMEDIATELY); 3595 final NotificationRecord parent = generateNotificationRecord( 3596 mTestNotificationChannel, 1, "group", true); 3597 final NotificationRecord child = generateNotificationRecord( 3598 mTestNotificationChannel, 2, "group", false); 3599 final NotificationRecord child2 = generateNotificationRecord( 3600 mTestNotificationChannel, 3, "group", false); 3601 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3602 final NotificationRecord newGroup = generateNotificationRecord( 3603 mTestNotificationChannel, 4, "group2", false); 3604 mService.addNotification(parent); 3605 mService.addNotification(child); 3606 mService.addNotification(child2); 3607 mService.addNotification(newGroup); 3608 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 3609 parent.getUserId()); 3610 waitForIdle(); 3611 StatusBarNotification[] notifs = 3612 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3613 assertEquals(0, notifs.length); 3614 } 3615 3616 @Test testDefaultChannelUpdatesApp_postMigrationToPermissions()3617 public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception { 3618 final NotificationChannel defaultChannel = mBinderService.getNotificationChannel( 3619 PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1, 3620 NotificationChannel.DEFAULT_CHANNEL_ID); 3621 defaultChannel.setImportance(IMPORTANCE_NONE); 3622 3623 mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel); 3624 3625 verify(mPermissionHelper).setNotificationPermission( 3626 PKG_N_MR1, ActivityManager.getCurrentUser(), false, true); 3627 } 3628 3629 @Test testPostNotification_appPermissionFixed()3630 public void testPostNotification_appPermissionFixed() throws Exception { 3631 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 3632 when(mPermissionHelper.isPermissionFixed(mPkg, mUserId)).thenReturn(true); 3633 3634 NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel); 3635 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3636 "testPostNotification_appPermissionFixed", 0, 3637 temp.getNotification(), mUserId); 3638 waitForIdle(); 3639 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3640 StatusBarNotification[] notifs = 3641 mBinderService.getActiveNotifications(mPkg); 3642 assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue(); 3643 } 3644 3645 @Test testSummaryNotification_appPermissionFixed()3646 public void testSummaryNotification_appPermissionFixed() { 3647 NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel); 3648 mService.addNotification(temp); 3649 3650 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 3651 when(mPermissionHelper.isPermissionFixed(mPkg, temp.getUserId())).thenReturn(true); 3652 3653 NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(), 3654 temp.getSbn().getPackageName(), temp.getKey(), 0, mock(Icon.class), 0, 3655 VISIBILITY_PRIVATE); 3656 3657 assertThat(r.isImportanceFixed()).isTrue(); 3658 } 3659 3660 @Test testTvExtenderChannelOverride_onTv()3661 public void testTvExtenderChannelOverride_onTv() throws Exception { 3662 mService.setIsTelevision(true); 3663 mService.setPreferencesHelper(mPreferencesHelper); 3664 when(mPreferencesHelper.getNotificationChannel( 3665 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn( 3666 new NotificationChannel("foo", "foo", IMPORTANCE_HIGH)); 3667 3668 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); 3669 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_onTv", 0, 3670 generateNotificationRecord(null, tv).getNotification(), mUserId); 3671 verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( 3672 anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean()); 3673 } 3674 3675 @Test testTvExtenderChannelOverride_notOnTv()3676 public void testTvExtenderChannelOverride_notOnTv() throws Exception { 3677 mService.setIsTelevision(false); 3678 mService.setPreferencesHelper(mPreferencesHelper); 3679 when(mPreferencesHelper.getNotificationChannel( 3680 anyString(), anyInt(), anyString(), anyBoolean())).thenReturn( 3681 mTestNotificationChannel); 3682 3683 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); 3684 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testTvExtenderChannelOverride_notOnTv", 3685 0, generateNotificationRecord(null, tv).getNotification(), mUserId); 3686 verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( 3687 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null), 3688 anyBoolean(), anyBoolean()); 3689 } 3690 3691 @Test onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()3692 public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage() 3693 throws RemoteException { 3694 // Have preexisting posted notifications from revoked package and other packages. 3695 mService.addNotification(new NotificationRecord(mContext, 3696 generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel)); 3697 mService.addNotification(new NotificationRecord(mContext, 3698 generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); 3699 // Have preexisting enqueued notifications from revoked package and other packages. 3700 mService.addEnqueuedNotification(new NotificationRecord(mContext, 3701 generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel)); 3702 mService.addEnqueuedNotification(new NotificationRecord(mContext, 3703 generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); 3704 assertThat(mService.mNotificationList).hasSize(2); 3705 assertThat(mService.mEnqueuedNotifications).hasSize(2); 3706 3707 when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001); 3708 when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false); 3709 3710 mOnPermissionChangeListener.onOpChanged( 3711 AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0); 3712 waitForIdle(); 3713 3714 assertThat(mService.mNotificationList).hasSize(1); 3715 assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other"); 3716 assertThat(mService.mEnqueuedNotifications).hasSize(1); 3717 assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo( 3718 "other"); 3719 } 3720 3721 @Test onOpChanged_permissionStillGranted_notificationsAreNotAffected()3722 public void onOpChanged_permissionStillGranted_notificationsAreNotAffected() 3723 throws RemoteException { 3724 // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission 3725 // being now granted, AND having previously posted notifications from said package) should 3726 // never happen (if we trust the broadcasts are correct). So this test is for a what-if 3727 // scenario, to verify we still handle it reasonably. 3728 3729 // Have preexisting posted notifications from specific package and other packages. 3730 mService.addNotification(new NotificationRecord(mContext, 3731 generateSbn("granted", 1001, 1, 0), mTestNotificationChannel)); 3732 mService.addNotification(new NotificationRecord(mContext, 3733 generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); 3734 // Have preexisting enqueued notifications from specific package and other packages. 3735 mService.addEnqueuedNotification(new NotificationRecord(mContext, 3736 generateSbn("granted", 1001, 3, 0), mTestNotificationChannel)); 3737 mService.addEnqueuedNotification(new NotificationRecord(mContext, 3738 generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); 3739 assertThat(mService.mNotificationList).hasSize(2); 3740 assertThat(mService.mEnqueuedNotifications).hasSize(2); 3741 3742 when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001); 3743 when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true); 3744 3745 mOnPermissionChangeListener.onOpChanged( 3746 AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0); 3747 waitForIdle(); 3748 3749 assertThat(mService.mNotificationList).hasSize(2); 3750 assertThat(mService.mEnqueuedNotifications).hasSize(2); 3751 } 3752 3753 @Test onOpChanged_notInitializedUser_ignored()3754 public void onOpChanged_notInitializedUser_ignored() throws RemoteException { 3755 when(mUmInternal.isUserInitialized(eq(0))).thenReturn(false); 3756 3757 mOnPermissionChangeListener.onOpChanged( 3758 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0); 3759 waitForIdle(); 3760 3761 // We early-exited and didn't even query PM for package details. 3762 verify(mPackageManagerInternal, never()).getPackageUid(any(), anyLong(), anyInt()); 3763 } 3764 3765 @Test setNotificationsEnabledForPackage_disabling_clearsNotifications()3766 public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception { 3767 mService.addNotification(new NotificationRecord(mContext, 3768 generateSbn("package", 1001, 1, 0), mTestNotificationChannel)); 3769 assertThat(mService.mNotificationList).hasSize(1); 3770 when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001); 3771 when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn( 3772 true); 3773 3774 // Start with granted permission and simulate effect of revoking it. 3775 when(mPermissionHelper.hasPermission(1001)).thenReturn(true); 3776 doAnswer(invocation -> { 3777 when(mPermissionHelper.hasPermission(1001)).thenReturn(false); 3778 mOnPermissionChangeListener.onOpChanged( 3779 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0); 3780 return null; 3781 }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true); 3782 3783 mBinderService.setNotificationsEnabledForPackage("package", 1001, false); 3784 waitForIdle(); 3785 3786 assertThat(mService.mNotificationList).hasSize(0); 3787 3788 mTestableLooper.moveTimeForward(500); 3789 waitForIdle(); 3790 verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null)); 3791 } 3792 3793 @Test testUpdateAppNotifyCreatorBlock()3794 public void testUpdateAppNotifyCreatorBlock() throws Exception { 3795 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 3796 3797 mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, false); 3798 Thread.sleep(500); 3799 waitForIdle(); 3800 3801 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 3802 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 3803 3804 assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, 3805 captor.getValue().getAction()); 3806 assertEquals(mPkg, captor.getValue().getPackage()); 3807 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); 3808 } 3809 3810 @Test testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting()3811 public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception { 3812 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 3813 3814 mBinderService.setNotificationsEnabledForPackage(mPkg, 0, false); 3815 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 3816 } 3817 3818 @Test testUpdateAppNotifyCreatorUnblock()3819 public void testUpdateAppNotifyCreatorUnblock() throws Exception { 3820 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 3821 3822 mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, true); 3823 Thread.sleep(500); 3824 waitForIdle(); 3825 3826 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 3827 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 3828 3829 assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, 3830 captor.getValue().getAction()); 3831 assertEquals(mPkg, captor.getValue().getPackage()); 3832 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); 3833 } 3834 3835 @Test testUpdateChannelNotifyCreatorBlock()3836 public void testUpdateChannelNotifyCreatorBlock() throws Exception { 3837 mService.setPreferencesHelper(mPreferencesHelper); 3838 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 3839 eq(mTestNotificationChannel.getId()), anyBoolean())) 3840 .thenReturn(mTestNotificationChannel); 3841 3842 NotificationChannel updatedChannel = 3843 new NotificationChannel(mTestNotificationChannel.getId(), 3844 mTestNotificationChannel.getName(), IMPORTANCE_NONE); 3845 3846 mBinderService.updateNotificationChannelForPackage(mPkg, 0, updatedChannel); 3847 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 3848 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 3849 3850 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED, 3851 captor.getValue().getAction()); 3852 assertEquals(mPkg, captor.getValue().getPackage()); 3853 assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra( 3854 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID)); 3855 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 3856 } 3857 3858 @Test testUpdateChannelNotifyCreatorUnblock()3859 public void testUpdateChannelNotifyCreatorUnblock() throws Exception { 3860 NotificationChannel existingChannel = 3861 new NotificationChannel(mTestNotificationChannel.getId(), 3862 mTestNotificationChannel.getName(), IMPORTANCE_NONE); 3863 mService.setPreferencesHelper(mPreferencesHelper); 3864 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 3865 eq(mTestNotificationChannel.getId()), anyBoolean())) 3866 .thenReturn(existingChannel); 3867 3868 mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel); 3869 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 3870 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 3871 3872 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED, 3873 captor.getValue().getAction()); 3874 assertEquals(mPkg, captor.getValue().getPackage()); 3875 assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra( 3876 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID)); 3877 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 3878 } 3879 3880 @Test testUpdateChannelNoNotifyCreatorOtherChanges()3881 public void testUpdateChannelNoNotifyCreatorOtherChanges() throws Exception { 3882 NotificationChannel existingChannel = 3883 new NotificationChannel(mTestNotificationChannel.getId(), 3884 mTestNotificationChannel.getName(), IMPORTANCE_MAX); 3885 mService.setPreferencesHelper(mPreferencesHelper); 3886 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 3887 eq(mTestNotificationChannel.getId()), anyBoolean())) 3888 .thenReturn(existingChannel); 3889 3890 mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel); 3891 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 3892 } 3893 3894 @Test testUpdateGroupNotifyCreatorBlock()3895 public void testUpdateGroupNotifyCreatorBlock() throws Exception { 3896 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 3897 mService.setPreferencesHelper(mPreferencesHelper); 3898 when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()), 3899 eq(mPkg), anyInt())) 3900 .thenReturn(existing); 3901 3902 NotificationChannelGroup updated = new NotificationChannelGroup("id", "name"); 3903 updated.setBlocked(true); 3904 3905 mBinderService.updateNotificationChannelGroupForPackage(mPkg, 0, updated); 3906 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 3907 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 3908 3909 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED, 3910 captor.getValue().getAction()); 3911 assertEquals(mPkg, captor.getValue().getPackage()); 3912 assertEquals(existing.getId(), captor.getValue().getStringExtra( 3913 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID)); 3914 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 3915 } 3916 3917 @Test testUpdateGroupNotifyCreatorUnblock()3918 public void testUpdateGroupNotifyCreatorUnblock() throws Exception { 3919 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 3920 existing.setBlocked(true); 3921 mService.setPreferencesHelper(mPreferencesHelper); 3922 when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()), 3923 eq(mPkg), anyInt())) 3924 .thenReturn(existing); 3925 3926 mBinderService.updateNotificationChannelGroupForPackage( 3927 mPkg, 0, new NotificationChannelGroup("id", "name")); 3928 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 3929 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 3930 3931 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED, 3932 captor.getValue().getAction()); 3933 assertEquals(mPkg, captor.getValue().getPackage()); 3934 assertEquals(existing.getId(), captor.getValue().getStringExtra( 3935 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID)); 3936 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 3937 } 3938 3939 @Test testUpdateGroupNoNotifyCreatorOtherChanges()3940 public void testUpdateGroupNoNotifyCreatorOtherChanges() throws Exception { 3941 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 3942 mService.setPreferencesHelper(mPreferencesHelper); 3943 when(mPreferencesHelper.getNotificationChannelGroup( 3944 eq(existing.getId()), eq(mPkg), anyInt())) 3945 .thenReturn(existing); 3946 3947 mBinderService.updateNotificationChannelGroupForPackage( 3948 mPkg, 0, new NotificationChannelGroup("id", "new name")); 3949 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 3950 } 3951 3952 @Test testCreateChannelNotifyListener()3953 public void testCreateChannelNotifyListener() throws Exception { 3954 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 3955 .thenReturn(singletonList(mock(AssociationInfo.class))); 3956 mService.setPreferencesHelper(mPreferencesHelper); 3957 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 3958 eq(mTestNotificationChannel.getId()), anyBoolean())) 3959 .thenReturn(mTestNotificationChannel); 3960 NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW); 3961 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 3962 eq(channel2.getId()), anyBoolean())) 3963 .thenReturn(channel2); 3964 when(mPreferencesHelper.createNotificationChannel(eq(mPkg), anyInt(), 3965 eq(channel2), anyBoolean(), anyBoolean(), anyInt(), anyBoolean())) 3966 .thenReturn(true); 3967 3968 reset(mListeners); 3969 mBinderService.createNotificationChannels(mPkg, 3970 new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2))); 3971 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 3972 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 3973 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 3974 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 3975 eq(Process.myUserHandle()), eq(channel2), 3976 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 3977 } 3978 3979 @Test testCreateChannelGroupNotifyListener()3980 public void testCreateChannelGroupNotifyListener() throws Exception { 3981 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 3982 .thenReturn(singletonList(mock(AssociationInfo.class))); 3983 mService.setPreferencesHelper(mPreferencesHelper); 3984 NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b"); 3985 NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m"); 3986 3987 reset(mListeners); 3988 mBinderService.createNotificationChannelGroups(mPkg, 3989 new ParceledListSlice(Arrays.asList(group1, group2))); 3990 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 3991 eq(Process.myUserHandle()), eq(group1), 3992 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 3993 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 3994 eq(Process.myUserHandle()), eq(group2), 3995 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 3996 } 3997 3998 @Test testUpdateChannelNotifyListener()3999 public void testUpdateChannelNotifyListener() throws Exception { 4000 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4001 .thenReturn(singletonList(mock(AssociationInfo.class))); 4002 mService.setPreferencesHelper(mPreferencesHelper); 4003 mTestNotificationChannel.setLightColor(Color.CYAN); 4004 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4005 eq(mTestNotificationChannel.getId()), anyBoolean())) 4006 .thenReturn(mTestNotificationChannel); 4007 4008 reset(mListeners); 4009 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel); 4010 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4011 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4012 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4013 } 4014 4015 @Test testDeleteChannelNotifyListener()4016 public void testDeleteChannelNotifyListener() throws Exception { 4017 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4018 .thenReturn(singletonList(mock(AssociationInfo.class))); 4019 mService.setPreferencesHelper(mPreferencesHelper); 4020 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4021 eq(mTestNotificationChannel.getId()), anyBoolean())) 4022 .thenReturn(mTestNotificationChannel); 4023 when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(), 4024 eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true); 4025 reset(mListeners); 4026 mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId()); 4027 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4028 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4029 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4030 } 4031 4032 @Test testDeleteChannelOnlyDoExtraWorkIfExisted()4033 public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception { 4034 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4035 .thenReturn(singletonList(mock(AssociationInfo.class))); 4036 mService.setPreferencesHelper(mPreferencesHelper); 4037 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4038 eq(mTestNotificationChannel.getId()), anyBoolean())) 4039 .thenReturn(null); 4040 reset(mListeners); 4041 mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId()); 4042 verifyNoMoreInteractions(mListeners); 4043 verifyNoMoreInteractions(mHistoryManager); 4044 } 4045 4046 @Test testDeleteChannelGroupNotifyListener()4047 public void testDeleteChannelGroupNotifyListener() throws Exception { 4048 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4049 .thenReturn(singletonList(mock(AssociationInfo.class))); 4050 NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c"); 4051 mService.setPreferencesHelper(mPreferencesHelper); 4052 when(mPreferencesHelper.getNotificationChannelGroupWithChannels( 4053 eq(mPkg), anyInt(), eq(ncg.getId()), anyBoolean())) 4054 .thenReturn(ncg); 4055 reset(mListeners); 4056 mBinderService.deleteNotificationChannelGroup(mPkg, ncg.getId()); 4057 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 4058 eq(Process.myUserHandle()), eq(ncg), 4059 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4060 } 4061 4062 @Test testDeleteChannelGroupChecksForFgses()4063 public void testDeleteChannelGroupChecksForFgses() throws Exception { 4064 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4065 .thenReturn(singletonList(mock(AssociationInfo.class))); 4066 CountDownLatch latch = new CountDownLatch(2); 4067 mService.createNotificationChannelGroup( 4068 mPkg, mUid, new NotificationChannelGroup("group", "group"), true, false); 4069 new Thread(() -> { 4070 NotificationChannel notificationChannel = new NotificationChannel("id", "id", 4071 NotificationManager.IMPORTANCE_HIGH); 4072 notificationChannel.setGroup("group"); 4073 ParceledListSlice<NotificationChannel> pls = 4074 new ParceledListSlice(ImmutableList.of(notificationChannel)); 4075 try { 4076 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 4077 } catch (RemoteException e) { 4078 throw new RuntimeException(e); 4079 } 4080 latch.countDown(); 4081 }).start(); 4082 new Thread(() -> { 4083 try { 4084 synchronized (this) { 4085 wait(5000); 4086 } 4087 mService.createNotificationChannelGroup(mPkg, mUid, 4088 new NotificationChannelGroup("new", "new group"), true, false); 4089 NotificationChannel notificationChannel = 4090 new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH); 4091 notificationChannel.setGroup("new"); 4092 ParceledListSlice<NotificationChannel> pls = 4093 new ParceledListSlice(ImmutableList.of(notificationChannel)); 4094 try { 4095 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 4096 mBinderService.deleteNotificationChannelGroup(mPkg, "group"); 4097 } catch (RemoteException e) { 4098 throw new RuntimeException(e); 4099 } 4100 } catch (Exception e) { 4101 e.printStackTrace(); 4102 } 4103 latch.countDown(); 4104 }).start(); 4105 4106 latch.await(); 4107 verify(mAmi).hasForegroundServiceNotification(anyString(), anyInt(), anyString()); 4108 } 4109 4110 @Test testUpdateNotificationChannelFromPrivilegedListener_success()4111 public void testUpdateNotificationChannelFromPrivilegedListener_success() throws Exception { 4112 mService.setPreferencesHelper(mPreferencesHelper); 4113 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4114 .thenReturn(singletonList(mock(AssociationInfo.class))); 4115 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4116 eq(mTestNotificationChannel.getId()), anyBoolean())) 4117 .thenReturn(mTestNotificationChannel); 4118 4119 mBinderService.updateNotificationChannelFromPrivilegedListener( 4120 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 4121 4122 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 4123 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 4124 4125 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4126 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4127 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4128 } 4129 4130 @Test testUpdateNotificationChannelFromPrivilegedListener_noAccess()4131 public void testUpdateNotificationChannelFromPrivilegedListener_noAccess() throws Exception { 4132 mService.setPreferencesHelper(mPreferencesHelper); 4133 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4134 .thenReturn(emptyList()); 4135 4136 try { 4137 mBinderService.updateNotificationChannelFromPrivilegedListener( 4138 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 4139 fail("listeners that don't have a companion device shouldn't be able to call this"); 4140 } catch (SecurityException e) { 4141 // pass 4142 } 4143 4144 verify(mPreferencesHelper, never()).updateNotificationChannel( 4145 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 4146 4147 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4148 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4149 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4150 } 4151 4152 @Test testUpdateNotificationChannelFromPrivilegedListener_badUser()4153 public void testUpdateNotificationChannelFromPrivilegedListener_badUser() throws Exception { 4154 mService.setPreferencesHelper(mPreferencesHelper); 4155 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4156 .thenReturn(singletonList(mock(AssociationInfo.class))); 4157 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4158 mListener.component = new ComponentName(mPkg, mPkg); 4159 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 4160 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4161 4162 try { 4163 mBinderService.updateNotificationChannelFromPrivilegedListener( 4164 null, mPkg, UserHandle.ALL, mTestNotificationChannel); 4165 fail("incorrectly allowed a change to a user listener cannot see"); 4166 } catch (SecurityException e) { 4167 // pass 4168 } 4169 4170 verify(mPreferencesHelper, never()).updateNotificationChannel( 4171 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 4172 4173 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4174 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4175 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4176 } 4177 4178 @Test testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission()4179 public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission() 4180 throws Exception { 4181 mService.setPreferencesHelper(mPreferencesHelper); 4182 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4183 .thenReturn(singletonList(mock(AssociationInfo.class))); 4184 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4185 eq(mTestNotificationChannel.getId()), anyBoolean())) 4186 .thenReturn(mTestNotificationChannel); 4187 4188 final Uri soundUri = Uri.parse("content://media/test/sound/uri"); 4189 final NotificationChannel updatedNotificationChannel = new NotificationChannel( 4190 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 4191 updatedNotificationChannel.setSound(soundUri, 4192 updatedNotificationChannel.getAudioAttributes()); 4193 4194 doThrow(new SecurityException("no access")).when(mUgmInternal) 4195 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), 4196 anyInt(), eq(Process.myUserHandle().getIdentifier())); 4197 4198 assertThrows(SecurityException.class, 4199 () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, mPkg, 4200 Process.myUserHandle(), updatedNotificationChannel)); 4201 4202 verify(mPreferencesHelper, never()).updateNotificationChannel( 4203 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 4204 4205 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4206 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4207 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4208 } 4209 4210 @Test testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()4211 public void testUpdateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound() 4212 throws Exception { 4213 mService.setPreferencesHelper(mPreferencesHelper); 4214 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4215 .thenReturn(singletonList(mock(AssociationInfo.class))); 4216 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4217 eq(mTestNotificationChannel.getId()), anyBoolean())) 4218 .thenReturn(mTestNotificationChannel); 4219 4220 final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 4221 final NotificationChannel updatedNotificationChannel = new NotificationChannel( 4222 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 4223 updatedNotificationChannel.setSound(soundUri, 4224 updatedNotificationChannel.getAudioAttributes()); 4225 4226 doThrow(new SecurityException("no access")).when(mUgmInternal) 4227 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), 4228 anyInt(), eq(Process.myUserHandle().getIdentifier())); 4229 4230 mBinderService.updateNotificationChannelFromPrivilegedListener( 4231 null, mPkg, Process.myUserHandle(), updatedNotificationChannel); 4232 4233 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 4234 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 4235 4236 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4237 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4238 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4239 } 4240 4241 @Test testGetNotificationChannelFromPrivilegedListener_cdm_success()4242 public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { 4243 mService.setPreferencesHelper(mPreferencesHelper); 4244 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4245 .thenReturn(singletonList(mock(AssociationInfo.class))); 4246 4247 mBinderService.getNotificationChannelsFromPrivilegedListener( 4248 null, mPkg, Process.myUserHandle()); 4249 4250 verify(mPreferencesHelper, times(1)).getNotificationChannels( 4251 anyString(), anyInt(), anyBoolean()); 4252 } 4253 4254 @Test testGetNotificationChannelFromPrivilegedListener_cdm_noAccess()4255 public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { 4256 mService.setPreferencesHelper(mPreferencesHelper); 4257 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4258 .thenReturn(emptyList()); 4259 4260 try { 4261 mBinderService.getNotificationChannelsFromPrivilegedListener( 4262 null, mPkg, Process.myUserHandle()); 4263 fail("listeners that don't have a companion device shouldn't be able to call this"); 4264 } catch (SecurityException e) { 4265 // pass 4266 } 4267 4268 verify(mPreferencesHelper, never()).getNotificationChannels( 4269 anyString(), anyInt(), anyBoolean()); 4270 } 4271 4272 @Test testGetNotificationChannelFromPrivilegedListener_assistant_success()4273 public void testGetNotificationChannelFromPrivilegedListener_assistant_success() 4274 throws Exception { 4275 mService.setPreferencesHelper(mPreferencesHelper); 4276 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4277 .thenReturn(emptyList()); 4278 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 4279 4280 mBinderService.getNotificationChannelsFromPrivilegedListener( 4281 null, mPkg, Process.myUserHandle()); 4282 4283 verify(mPreferencesHelper, times(1)).getNotificationChannels( 4284 anyString(), anyInt(), anyBoolean()); 4285 } 4286 4287 @Test testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()4288 public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() 4289 throws Exception { 4290 mService.setPreferencesHelper(mPreferencesHelper); 4291 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4292 .thenReturn(emptyList()); 4293 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); 4294 4295 try { 4296 mBinderService.getNotificationChannelsFromPrivilegedListener( 4297 null, mPkg, Process.myUserHandle()); 4298 fail("listeners that don't have a companion device shouldn't be able to call this"); 4299 } catch (SecurityException e) { 4300 // pass 4301 } 4302 4303 verify(mPreferencesHelper, never()).getNotificationChannels( 4304 anyString(), anyInt(), anyBoolean()); 4305 } 4306 4307 @Test testGetNotificationChannelFromPrivilegedListener_badUser()4308 public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { 4309 mService.setPreferencesHelper(mPreferencesHelper); 4310 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4311 .thenReturn(singletonList(mock(AssociationInfo.class))); 4312 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4313 mListener.component = new ComponentName(mPkg, mPkg); 4314 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 4315 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4316 4317 try { 4318 mBinderService.getNotificationChannelsFromPrivilegedListener( 4319 null, mPkg, Process.myUserHandle()); 4320 fail("listener getting channels from a user they cannot see"); 4321 } catch (SecurityException e) { 4322 // pass 4323 } 4324 4325 verify(mPreferencesHelper, never()).getNotificationChannels( 4326 anyString(), anyInt(), anyBoolean()); 4327 } 4328 4329 @Test testGetNotificationChannelGroupsFromPrivilegedListener_success()4330 public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception { 4331 mService.setPreferencesHelper(mPreferencesHelper); 4332 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4333 .thenReturn(singletonList(mock(AssociationInfo.class))); 4334 4335 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 4336 null, mPkg, Process.myUserHandle()); 4337 4338 verify(mPreferencesHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt()); 4339 } 4340 4341 @Test testGetNotificationChannelGroupsFromPrivilegedListener_noAccess()4342 public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception { 4343 mService.setPreferencesHelper(mPreferencesHelper); 4344 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4345 .thenReturn(emptyList()); 4346 4347 try { 4348 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 4349 null, mPkg, Process.myUserHandle()); 4350 fail("listeners that don't have a companion device shouldn't be able to call this"); 4351 } catch (SecurityException e) { 4352 // pass 4353 } 4354 4355 verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt()); 4356 } 4357 4358 @Test testGetNotificationChannelGroupsFromPrivilegedListener_badUser()4359 public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { 4360 mService.setPreferencesHelper(mPreferencesHelper); 4361 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4362 .thenReturn(emptyList()); 4363 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4364 mListener.component = new ComponentName(mPkg, mPkg); 4365 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 4366 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4367 try { 4368 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 4369 null, mPkg, Process.myUserHandle()); 4370 fail("listeners that don't have a companion device shouldn't be able to call this"); 4371 } catch (SecurityException e) { 4372 // pass 4373 } 4374 4375 verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt()); 4376 } 4377 4378 @Test testHasCompanionDevice_failure()4379 public void testHasCompanionDevice_failure() throws Exception { 4380 when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow( 4381 new IllegalArgumentException()); 4382 mService.hasCompanionDevice(mListener); 4383 } 4384 4385 @Test testHasCompanionDevice_noService()4386 public void testHasCompanionDevice_noService() { 4387 NotificationManagerService noManService = 4388 new TestableNotificationManagerService(mContext, mNotificationRecordLogger, 4389 mNotificationInstanceIdSequence); 4390 4391 assertFalse(noManService.hasCompanionDevice(mListener)); 4392 } 4393 4394 @Test testCrossUserSnooze()4395 public void testCrossUserSnooze() { 4396 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); 4397 mService.addNotification(r); 4398 NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); 4399 mService.addNotification(r2); 4400 4401 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4402 mListener.component = new ComponentName(mPkg, mPkg); 4403 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 4404 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4405 4406 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 4407 r.getKey(), 1000, null); 4408 4409 verify(mWorkerHandler, never()).post( 4410 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 4411 } 4412 4413 @Test testSameUserSnooze()4414 public void testSameUserSnooze() { 4415 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); 4416 mService.addNotification(r); 4417 NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); 4418 mService.addNotification(r2); 4419 4420 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4421 mListener.component = new ComponentName(mPkg, mPkg); 4422 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 4423 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4424 4425 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 4426 r2.getKey(), 1000, null); 4427 4428 verify(mWorkerHandler).post( 4429 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 4430 } 4431 4432 @Test snoozeNotificationInt_rapidSnooze_new()4433 public void snoozeNotificationInt_rapidSnooze_new() { 4434 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 4435 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 4436 4437 // Create recent notification. 4438 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 4439 System.currentTimeMillis()); 4440 mService.addNotification(nr1); 4441 4442 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4443 mListener.component = new ComponentName(mPkg, mPkg); 4444 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 4445 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4446 4447 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 4448 nr1.getKey(), 1000, null); 4449 4450 verify(mWorkerHandler).post( 4451 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 4452 // Ensure cancel event is logged. 4453 verify(mAppOpsManager).noteOpNoThrow( 4454 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, 4455 null); 4456 } 4457 4458 @Test snoozeNotificationInt_rapidSnooze_old()4459 public void snoozeNotificationInt_rapidSnooze_old() { 4460 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 4461 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 4462 4463 // Create old notification. 4464 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 4465 System.currentTimeMillis() - 60000); 4466 mService.addNotification(nr1); 4467 4468 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4469 mListener.component = new ComponentName(mPkg, mPkg); 4470 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 4471 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4472 4473 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 4474 nr1.getKey(), 1000, null); 4475 4476 verify(mWorkerHandler).post( 4477 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 4478 // Ensure cancel event is not logged. 4479 verify(mAppOpsManager, never()).noteOpNoThrow( 4480 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 4481 any(), any()); 4482 } 4483 4484 @Test snoozeNotificationInt_rapidSnooze_new_flagDisabled()4485 public void snoozeNotificationInt_rapidSnooze_new_flagDisabled() { 4486 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 4487 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 4488 4489 // Create recent notification. 4490 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 4491 System.currentTimeMillis()); 4492 mService.addNotification(nr1); 4493 4494 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4495 mListener.component = new ComponentName(mPkg, mPkg); 4496 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 4497 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4498 4499 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 4500 nr1.getKey(), 1000, null); 4501 4502 verify(mWorkerHandler).post( 4503 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 4504 // Ensure cancel event is not logged. 4505 verify(mAppOpsManager, never()).noteOpNoThrow( 4506 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 4507 any(), any()); 4508 } 4509 4510 @Test snoozeNotificationInt_rapidSnooze_old_flagDisabled()4511 public void snoozeNotificationInt_rapidSnooze_old_flagDisabled() { 4512 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 4513 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 4514 4515 // Create old notification. 4516 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 4517 System.currentTimeMillis() - 60000); 4518 mService.addNotification(nr1); 4519 4520 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4521 mListener.component = new ComponentName(mPkg, mPkg); 4522 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 4523 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4524 4525 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 4526 nr1.getKey(), 1000, null); 4527 4528 verify(mWorkerHandler).post( 4529 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 4530 // Ensure cancel event is not logged. 4531 verify(mAppOpsManager, never()).noteOpNoThrow( 4532 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 4533 any(), any()); 4534 } 4535 4536 @Test testSnoozeRunnable_tooManySnoozed_singleNotification()4537 public void testSnoozeRunnable_tooManySnoozed_singleNotification() { 4538 final NotificationRecord notification = generateNotificationRecord( 4539 mTestNotificationChannel, 1, null, true); 4540 mService.addNotification(notification); 4541 4542 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4543 when(mSnoozeHelper.canSnooze(1)).thenReturn(false); 4544 4545 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4546 mService.new SnoozeNotificationRunnable( 4547 notification.getKey(), 100, null); 4548 snoozeNotificationRunnable.run(); 4549 4550 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 4551 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 4552 } 4553 4554 @Test testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification()4555 public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() { 4556 final NotificationRecord notification = generateNotificationRecord( 4557 mTestNotificationChannel, 1, "group", true); 4558 final NotificationRecord notificationChild = generateNotificationRecord( 4559 mTestNotificationChannel, 1, "group", false); 4560 mService.addNotification(notification); 4561 mService.addNotification(notificationChild); 4562 4563 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4564 when(mSnoozeHelper.canSnooze(2)).thenReturn(false); 4565 4566 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4567 mService.new SnoozeNotificationRunnable( 4568 notificationChild.getKey(), 100, null); 4569 snoozeNotificationRunnable.run(); 4570 4571 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 4572 assertThat(mService.getNotificationRecordCount()).isEqualTo(2); 4573 } 4574 4575 @Test testSnoozeRunnable_tooManySnoozed_summaryNotification()4576 public void testSnoozeRunnable_tooManySnoozed_summaryNotification() { 4577 final NotificationRecord notification = generateNotificationRecord( 4578 mTestNotificationChannel, 1, "group", true); 4579 final NotificationRecord notificationChild = generateNotificationRecord( 4580 mTestNotificationChannel, 12, "group", false); 4581 final NotificationRecord notificationChild2 = generateNotificationRecord( 4582 mTestNotificationChannel, 13, "group", false); 4583 mService.addNotification(notification); 4584 mService.addNotification(notificationChild); 4585 mService.addNotification(notificationChild2); 4586 4587 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4588 when(mSnoozeHelper.canSnooze(3)).thenReturn(false); 4589 4590 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4591 mService.new SnoozeNotificationRunnable( 4592 notification.getKey(), 100, null); 4593 snoozeNotificationRunnable.run(); 4594 4595 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 4596 assertThat(mService.getNotificationRecordCount()).isEqualTo(3); 4597 } 4598 4599 @Test testSnoozeRunnable_reSnoozeASingleSnoozedNotification()4600 public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() { 4601 final NotificationRecord notification = generateNotificationRecord( 4602 mTestNotificationChannel, 1, null, true); 4603 mService.addNotification(notification); 4604 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 4605 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4606 4607 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4608 mService.new SnoozeNotificationRunnable( 4609 notification.getKey(), 100, null); 4610 snoozeNotificationRunnable.run(); 4611 snoozeNotificationRunnable.run(); 4612 4613 // snooze twice 4614 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 4615 } 4616 4617 @Test testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey()4618 public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() { 4619 final NotificationRecord notification = generateNotificationRecord( 4620 mTestNotificationChannel, 1, "group", true); 4621 mService.addNotification(notification); 4622 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 4623 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4624 4625 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4626 mService.new SnoozeNotificationRunnable( 4627 notification.getKey(), 100, null); 4628 snoozeNotificationRunnable.run(); 4629 snoozeNotificationRunnable.run(); 4630 4631 // snooze twice 4632 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 4633 } 4634 4635 @Test testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey()4636 public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception { 4637 final NotificationRecord notification = generateNotificationRecord( 4638 mTestNotificationChannel, 1, "group", true); 4639 final NotificationRecord notification2 = generateNotificationRecord( 4640 mTestNotificationChannel, 2, "group", true); 4641 mService.addNotification(notification); 4642 mService.addNotification(notification2); 4643 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 4644 when(mSnoozeHelper.getNotifications( 4645 anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>()); 4646 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4647 4648 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4649 mService.new SnoozeNotificationRunnable( 4650 notification.getKey(), 100, null); 4651 snoozeNotificationRunnable.run(); 4652 when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt())) 4653 .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2))); 4654 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = 4655 mService.new SnoozeNotificationRunnable( 4656 notification2.getKey(), 100, null); 4657 snoozeNotificationRunnable2.run(); 4658 4659 // snooze twice 4660 verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong()); 4661 } 4662 4663 @Test testSnoozeRunnable_snoozeNonGrouped()4664 public void testSnoozeRunnable_snoozeNonGrouped() throws Exception { 4665 final NotificationRecord nonGrouped = generateNotificationRecord( 4666 mTestNotificationChannel, 1, null, false); 4667 final NotificationRecord grouped = generateNotificationRecord( 4668 mTestNotificationChannel, 2, "group", false); 4669 mService.addNotification(grouped); 4670 mService.addNotification(nonGrouped); 4671 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4672 4673 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4674 mService.new SnoozeNotificationRunnable( 4675 nonGrouped.getKey(), 100, null); 4676 snoozeNotificationRunnable.run(); 4677 4678 // only snooze the one notification 4679 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 4680 assertTrue(nonGrouped.getStats().hasSnoozed()); 4681 4682 assertEquals(2, mNotificationRecordLogger.numCalls()); 4683 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 4684 mNotificationRecordLogger.event(0)); 4685 assertEquals( 4686 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 4687 mNotificationRecordLogger.event(1)); 4688 } 4689 4690 @Test testSnoozeRunnable_snoozeSummary_withChildren()4691 public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception { 4692 final NotificationRecord parent = generateNotificationRecord( 4693 mTestNotificationChannel, 1, "group", true); 4694 final NotificationRecord child = generateNotificationRecord( 4695 mTestNotificationChannel, 2, "group", false); 4696 final NotificationRecord child2 = generateNotificationRecord( 4697 mTestNotificationChannel, 3, "group", false); 4698 mService.addNotification(parent); 4699 mService.addNotification(child); 4700 mService.addNotification(child2); 4701 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4702 4703 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4704 mService.new SnoozeNotificationRunnable( 4705 parent.getKey(), 100, null); 4706 snoozeNotificationRunnable.run(); 4707 4708 // snooze parent and children 4709 verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong()); 4710 } 4711 4712 @Test testSnoozeRunnable_snoozeGroupChild_fellowChildren()4713 public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception { 4714 final NotificationRecord parent = generateNotificationRecord( 4715 mTestNotificationChannel, 1, "group", true); 4716 final NotificationRecord child = generateNotificationRecord( 4717 mTestNotificationChannel, 2, "group", false); 4718 final NotificationRecord child2 = generateNotificationRecord( 4719 mTestNotificationChannel, 3, "group", false); 4720 mService.addNotification(parent); 4721 mService.addNotification(child); 4722 mService.addNotification(child2); 4723 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4724 4725 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4726 mService.new SnoozeNotificationRunnable( 4727 child2.getKey(), 100, null); 4728 snoozeNotificationRunnable.run(); 4729 4730 // only snooze the one child 4731 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 4732 4733 assertEquals(2, mNotificationRecordLogger.numCalls()); 4734 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 4735 mNotificationRecordLogger.event(0)); 4736 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 4737 .NOTIFICATION_CANCEL_SNOOZED, mNotificationRecordLogger.event(1)); 4738 } 4739 4740 @Test testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary()4741 public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception { 4742 final NotificationRecord parent = generateNotificationRecord( 4743 mTestNotificationChannel, 1, "group", true); 4744 assertTrue(parent.getSbn().getNotification().isGroupSummary()); 4745 final NotificationRecord child = generateNotificationRecord( 4746 mTestNotificationChannel, 2, "group", false); 4747 mService.addNotification(parent); 4748 mService.addNotification(child); 4749 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4750 4751 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4752 mService.new SnoozeNotificationRunnable( 4753 child.getKey(), 100, null); 4754 snoozeNotificationRunnable.run(); 4755 4756 // snooze child and summary 4757 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 4758 4759 assertEquals(4, mNotificationRecordLogger.numCalls()); 4760 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 4761 mNotificationRecordLogger.event(0)); 4762 assertEquals( 4763 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 4764 mNotificationRecordLogger.event(1)); 4765 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 4766 mNotificationRecordLogger.event(2)); 4767 assertEquals( 4768 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 4769 mNotificationRecordLogger.event(3)); 4770 } 4771 4772 @Test testSnoozeRunnable_snoozeGroupChild_noOthersInGroup()4773 public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception { 4774 final NotificationRecord child = generateNotificationRecord( 4775 mTestNotificationChannel, 2, "group", false); 4776 mService.addNotification(child); 4777 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4778 4779 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4780 mService.new SnoozeNotificationRunnable( 4781 child.getKey(), 100, null); 4782 snoozeNotificationRunnable.run(); 4783 4784 // snooze child only 4785 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 4786 4787 assertEquals(2, mNotificationRecordLogger.numCalls()); 4788 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 4789 mNotificationRecordLogger.event(0)); 4790 assertEquals( 4791 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 4792 mNotificationRecordLogger.event(1)); 4793 } 4794 4795 @Test testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed()4796 public void testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed() throws Exception { 4797 final NotificationRecord parent = generateNotificationRecord( 4798 mTestNotificationChannel, 1, GroupHelper.AUTOGROUP_KEY, true); 4799 final NotificationRecord child = generateNotificationRecord( 4800 mTestNotificationChannel, 2, GroupHelper.AUTOGROUP_KEY, false); 4801 mService.addNotification(parent); 4802 mService.addNotification(child); 4803 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 4804 4805 // snooze child only 4806 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4807 mService.new SnoozeNotificationRunnable( 4808 child.getKey(), 100, null); 4809 snoozeNotificationRunnable.run(); 4810 4811 // only child should be snoozed 4812 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 4813 4814 // both group summary and child should be cancelled 4815 assertNull(mService.getNotificationRecord(parent.getKey())); 4816 assertNull(mService.getNotificationRecord(child.getKey())); 4817 4818 assertEquals(4, mNotificationRecordLogger.numCalls()); 4819 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 4820 mNotificationRecordLogger.event(0)); 4821 assertEquals( 4822 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 4823 mNotificationRecordLogger.event(1)); 4824 } 4825 4826 @Test testPostGroupChild_unsnoozeParent()4827 public void testPostGroupChild_unsnoozeParent() throws Exception { 4828 final NotificationRecord child = generateNotificationRecord( 4829 mTestNotificationChannel, 2, "group", false); 4830 4831 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing", 4832 child.getSbn().getId(), child.getSbn().getNotification(), 4833 child.getSbn().getUserId()); 4834 waitForIdle(); 4835 4836 verify(mSnoozeHelper, times(1)).repostGroupSummary( 4837 anyString(), anyInt(), eq(child.getGroupKey())); 4838 } 4839 4840 @Test testPostNonGroup_noUnsnoozing()4841 public void testPostNonGroup_noUnsnoozing() throws Exception { 4842 final NotificationRecord record = generateNotificationRecord( 4843 mTestNotificationChannel, 2, null, false); 4844 4845 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing", 4846 record.getSbn().getId(), record.getSbn().getNotification(), 4847 record.getSbn().getUserId()); 4848 waitForIdle(); 4849 4850 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString()); 4851 } 4852 4853 @Test testPostGroupSummary_noUnsnoozing()4854 public void testPostGroupSummary_noUnsnoozing() throws Exception { 4855 final NotificationRecord parent = generateNotificationRecord( 4856 mTestNotificationChannel, 2, "group", true); 4857 4858 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostGroupSummary_noUnsnoozing", 4859 parent.getSbn().getId(), parent.getSbn().getNotification(), 4860 parent.getSbn().getUserId()); 4861 waitForIdle(); 4862 4863 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString()); 4864 } 4865 4866 @Test testSystemNotificationListenerCanUnsnooze()4867 public void testSystemNotificationListenerCanUnsnooze() throws Exception { 4868 final NotificationRecord nr = generateNotificationRecord( 4869 mTestNotificationChannel, 2, "group", false); 4870 4871 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 4872 "testSystemNotificationListenerCanUnsnooze", 4873 nr.getSbn().getId(), nr.getSbn().getNotification(), 4874 nr.getSbn().getUserId()); 4875 waitForIdle(); 4876 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 4877 mService.new SnoozeNotificationRunnable( 4878 nr.getKey(), 100, null); 4879 snoozeNotificationRunnable.run(); 4880 4881 ManagedServices.ManagedServiceInfo listener = mListeners.new ManagedServiceInfo( 4882 null, new ComponentName(mPkg, "test_class"), mUid, true, null, 0, 234); 4883 listener.isSystem = true; 4884 when(mListeners.checkServiceTokenLocked(any())).thenReturn(listener); 4885 4886 mBinderService.unsnoozeNotificationFromSystemListener(null, nr.getKey()); 4887 waitForIdle(); 4888 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 4889 assertEquals(1, notifs.length); 4890 assertNotNull(notifs[0].getKey());//mService.getNotificationRecord(nr.getSbn().getKey())); 4891 } 4892 4893 @Test testSetListenerAccessForUser()4894 public void testSetListenerAccessForUser() throws Exception { 4895 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 4896 ComponentName c = ComponentName.unflattenFromString("package/Component"); 4897 mBinderService.setNotificationListenerAccessGrantedForUser( 4898 c, user.getIdentifier(), true, true); 4899 4900 4901 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 4902 verify(mListeners, times(1)).setPackageOrComponentEnabled( 4903 c.flattenToString(), user.getIdentifier(), true, true, true); 4904 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 4905 c.flattenToString(), user.getIdentifier(), false, true, true); 4906 verify(mAssistants, never()).setPackageOrComponentEnabled( 4907 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 4908 } 4909 4910 @Test testSetListenerAccessForUser_grantWithNameTooLong_throws()4911 public void testSetListenerAccessForUser_grantWithNameTooLong_throws() { 4912 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 4913 ComponentName c = new ComponentName("com.example.package", 4914 com.google.common.base.Strings.repeat("Blah", 150)); 4915 4916 assertThrows(IllegalArgumentException.class, 4917 () -> mBinderService.setNotificationListenerAccessGrantedForUser( 4918 c, user.getIdentifier(), /* enabled= */ true, true)); 4919 } 4920 4921 @Test testSetListenerAccessForUser_revokeWithNameTooLong_okay()4922 public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception { 4923 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 4924 ComponentName c = new ComponentName("com.example.package", 4925 com.google.common.base.Strings.repeat("Blah", 150)); 4926 4927 mBinderService.setNotificationListenerAccessGrantedForUser( 4928 c, user.getIdentifier(), /* enabled= */ false, true); 4929 4930 verify(mListeners).setPackageOrComponentEnabled( 4931 c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true); 4932 } 4933 4934 @Test testSetAssistantAccessForUser()4935 public void testSetAssistantAccessForUser() throws Exception { 4936 UserInfo ui = new UserInfo(); 4937 ui.id = mContext.getUserId() + 10; 4938 UserHandle user = UserHandle.of(ui.id); 4939 List<UserInfo> uis = new ArrayList<>(); 4940 uis.add(ui); 4941 ComponentName c = ComponentName.unflattenFromString("package/Component"); 4942 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 4943 4944 mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true); 4945 4946 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 4947 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 4948 c.flattenToString(), user.getIdentifier(), true, true, true); 4949 verify(mAssistants).setUserSet(ui.id, true); 4950 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 4951 c.flattenToString(), user.getIdentifier(), false, true); 4952 verify(mListeners, never()).setPackageOrComponentEnabled( 4953 any(), anyInt(), anyBoolean(), anyBoolean()); 4954 } 4955 4956 @Test testGetAssistantAllowedForUser()4957 public void testGetAssistantAllowedForUser() throws Exception { 4958 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 4959 try { 4960 mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier()); 4961 } catch (IllegalStateException e) { 4962 if (!e.getMessage().contains("At most one NotificationAssistant")) { 4963 throw e; 4964 } 4965 } 4966 verify(mAssistants, times(1)).getAllowedComponents(user.getIdentifier()); 4967 } 4968 4969 @Test testGetAssistantAllowed()4970 public void testGetAssistantAllowed() throws Exception { 4971 try { 4972 mBinderService.getAllowedNotificationAssistant(); 4973 } catch (IllegalStateException e) { 4974 if (!e.getMessage().contains("At most one NotificationAssistant")) { 4975 throw e; 4976 } 4977 } 4978 verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId()); 4979 } 4980 4981 @Test testSetNASMigrationDoneAndResetDefault_enableNAS()4982 public void testSetNASMigrationDoneAndResetDefault_enableNAS() throws Exception { 4983 int userId = 10; 4984 setNASMigrationDone(false, userId); 4985 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 4986 4987 mBinderService.setNASMigrationDoneAndResetDefault(userId, true); 4988 4989 assertTrue(mService.isNASMigrationDone(userId)); 4990 verify(mAssistants, times(1)).resetDefaultFromConfig(); 4991 } 4992 4993 @Test testSetNASMigrationDoneAndResetDefault_disableNAS()4994 public void testSetNASMigrationDoneAndResetDefault_disableNAS() throws Exception { 4995 int userId = 10; 4996 setNASMigrationDone(false, userId); 4997 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 4998 4999 mBinderService.setNASMigrationDoneAndResetDefault(userId, false); 5000 5001 assertTrue(mService.isNASMigrationDone(userId)); 5002 verify(mAssistants, times(1)).clearDefaults(); 5003 } 5004 5005 @Test testSetNASMigrationDoneAndResetDefault_multiProfile()5006 public void testSetNASMigrationDoneAndResetDefault_multiProfile() throws Exception { 5007 int userId1 = 11; 5008 int userId2 = 12; //work profile 5009 setNASMigrationDone(false, userId1); 5010 setNASMigrationDone(false, userId2); 5011 setUsers(new int[]{userId1, userId2}); 5012 when(mUm.isManagedProfile(userId2)).thenReturn(true); 5013 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2}); 5014 5015 mBinderService.setNASMigrationDoneAndResetDefault(userId1, true); 5016 assertTrue(mService.isNASMigrationDone(userId1)); 5017 assertTrue(mService.isNASMigrationDone(userId2)); 5018 } 5019 5020 @Test testSetNASMigrationDoneAndResetDefault_multiUser()5021 public void testSetNASMigrationDoneAndResetDefault_multiUser() throws Exception { 5022 int userId1 = 11; 5023 int userId2 = 12; 5024 setNASMigrationDone(false, userId1); 5025 setNASMigrationDone(false, userId2); 5026 setUsers(new int[]{userId1, userId2}); 5027 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1}); 5028 when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2}); 5029 5030 mBinderService.setNASMigrationDoneAndResetDefault(userId1, true); 5031 assertTrue(mService.isNASMigrationDone(userId1)); 5032 assertFalse(mService.isNASMigrationDone(userId2)); 5033 } 5034 5035 @Test testSetDndAccessForUser()5036 public void testSetDndAccessForUser() throws Exception { 5037 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5038 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5039 mBinderService.setNotificationPolicyAccessGrantedForUser( 5040 c.getPackageName(), user.getIdentifier(), true); 5041 5042 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 5043 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5044 c.getPackageName(), user.getIdentifier(), true, true); 5045 verify(mAssistants, never()).setPackageOrComponentEnabled( 5046 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5047 verify(mListeners, never()).setPackageOrComponentEnabled( 5048 any(), anyInt(), anyBoolean(), anyBoolean()); 5049 } 5050 5051 @Test testSetListenerAccess()5052 public void testSetListenerAccess() throws Exception { 5053 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5054 mBinderService.setNotificationListenerAccessGranted(c, true, true); 5055 5056 verify(mListeners, times(1)).setPackageOrComponentEnabled( 5057 c.flattenToString(), mContext.getUserId(), true, true, true); 5058 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5059 c.flattenToString(), mContext.getUserId(), false, true, true); 5060 verify(mAssistants, never()).setPackageOrComponentEnabled( 5061 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5062 } 5063 5064 @Test testSetAssistantAccess()5065 public void testSetAssistantAccess() throws Exception { 5066 List<UserInfo> uis = new ArrayList<>(); 5067 UserInfo ui = new UserInfo(); 5068 ui.id = mContext.getUserId(); 5069 uis.add(ui); 5070 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5071 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5072 5073 mBinderService.setNotificationAssistantAccessGranted(c, true); 5074 5075 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5076 c.flattenToString(), ui.id, true, true, true); 5077 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5078 c.flattenToString(), ui.id, false, true); 5079 verify(mListeners, never()).setPackageOrComponentEnabled( 5080 any(), anyInt(), anyBoolean(), anyBoolean()); 5081 } 5082 5083 @Test testSetAssistantAccess_multiProfile()5084 public void testSetAssistantAccess_multiProfile() throws Exception { 5085 List<UserInfo> uis = new ArrayList<>(); 5086 UserInfo ui = new UserInfo(); 5087 ui.id = mContext.getUserId(); 5088 uis.add(ui); 5089 UserInfo ui10 = new UserInfo(); 5090 ui10.id = mContext.getUserId() + 10; 5091 uis.add(ui10); 5092 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5093 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5094 5095 mBinderService.setNotificationAssistantAccessGranted(c, true); 5096 5097 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5098 c.flattenToString(), ui.id, true, true, true); 5099 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5100 c.flattenToString(), ui10.id, true, true, true); 5101 5102 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5103 c.flattenToString(), ui.id, false, true); 5104 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5105 c.flattenToString(), ui10.id, false, true); 5106 verify(mListeners, never()).setPackageOrComponentEnabled( 5107 any(), anyInt(), anyBoolean(), anyBoolean()); 5108 } 5109 5110 @Test testSetAssistantAccess_nullWithAllowedAssistant()5111 public void testSetAssistantAccess_nullWithAllowedAssistant() throws Exception { 5112 ArrayList<ComponentName> componentList = new ArrayList<>(); 5113 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5114 componentList.add(c); 5115 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 5116 List<UserInfo> uis = new ArrayList<>(); 5117 UserInfo ui = new UserInfo(); 5118 ui.id = mContext.getUserId(); 5119 uis.add(ui); 5120 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5121 5122 mBinderService.setNotificationAssistantAccessGranted(null, true); 5123 5124 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5125 c.flattenToString(), ui.id, true, false, true); 5126 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5127 c.flattenToString(), ui.id, false, false); 5128 verify(mListeners, never()).setPackageOrComponentEnabled( 5129 any(), anyInt(), anyBoolean(), anyBoolean()); 5130 } 5131 5132 @Test testSetAssistantAccessForUser_nullWithAllowedAssistant()5133 public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception { 5134 List<UserInfo> uis = new ArrayList<>(); 5135 UserInfo ui = new UserInfo(); 5136 ui.id = mContext.getUserId() + 10; 5137 uis.add(ui); 5138 UserHandle user = ui.getUserHandle(); 5139 ArrayList<ComponentName> componentList = new ArrayList<>(); 5140 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5141 componentList.add(c); 5142 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 5143 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5144 5145 mBinderService.setNotificationAssistantAccessGrantedForUser( 5146 null, user.getIdentifier(), true); 5147 5148 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5149 c.flattenToString(), user.getIdentifier(), true, false, true); 5150 verify(mAssistants).setUserSet(ui.id, true); 5151 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5152 c.flattenToString(), user.getIdentifier(), false, false); 5153 verify(mListeners, never()).setPackageOrComponentEnabled( 5154 any(), anyInt(), anyBoolean(), anyBoolean()); 5155 } 5156 5157 @Test testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()5158 public void testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant() 5159 throws Exception { 5160 List<UserInfo> uis = new ArrayList<>(); 5161 UserInfo ui = new UserInfo(); 5162 ui.id = mContext.getUserId(); 5163 uis.add(ui); 5164 UserInfo ui10 = new UserInfo(); 5165 ui10.id = mContext.getUserId() + 10; 5166 uis.add(ui10); 5167 UserHandle user = ui.getUserHandle(); 5168 ArrayList<ComponentName> componentList = new ArrayList<>(); 5169 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5170 componentList.add(c); 5171 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 5172 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5173 5174 mBinderService.setNotificationAssistantAccessGrantedForUser( 5175 null, user.getIdentifier(), true); 5176 5177 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5178 c.flattenToString(), user.getIdentifier(), true, false, true); 5179 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5180 c.flattenToString(), ui10.id, true, false, true); 5181 verify(mAssistants).setUserSet(ui.id, true); 5182 verify(mAssistants).setUserSet(ui10.id, true); 5183 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5184 c.flattenToString(), user.getIdentifier(), false, false); 5185 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5186 c.flattenToString(), ui10.id, false, false); 5187 verify(mListeners, never()).setPackageOrComponentEnabled( 5188 any(), anyInt(), anyBoolean(), anyBoolean()); 5189 } 5190 5191 @Test testSetDndAccess()5192 public void testSetDndAccess() throws Exception { 5193 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5194 5195 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 5196 5197 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5198 c.getPackageName(), mContext.getUserId(), true, true); 5199 verify(mAssistants, never()).setPackageOrComponentEnabled( 5200 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5201 verify(mListeners, never()).setPackageOrComponentEnabled( 5202 any(), anyInt(), anyBoolean(), anyBoolean()); 5203 } 5204 5205 @Test testSetListenerAccess_onLowRam()5206 public void testSetListenerAccess_onLowRam() throws Exception { 5207 when(mActivityManager.isLowRamDevice()).thenReturn(true); 5208 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5209 mBinderService.setNotificationListenerAccessGranted(c, true, true); 5210 5211 verify(mListeners).setPackageOrComponentEnabled( 5212 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5213 verify(mConditionProviders).setPackageOrComponentEnabled( 5214 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5215 verify(mAssistants).migrateToXml(); 5216 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 5217 } 5218 5219 @Test testSetAssistantAccess_onLowRam()5220 public void testSetAssistantAccess_onLowRam() throws Exception { 5221 when(mActivityManager.isLowRamDevice()).thenReturn(true); 5222 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5223 List<UserInfo> uis = new ArrayList<>(); 5224 UserInfo ui = new UserInfo(); 5225 ui.id = mContext.getUserId(); 5226 uis.add(ui); 5227 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5228 5229 mBinderService.setNotificationAssistantAccessGranted(c, true); 5230 5231 verify(mListeners).migrateToXml(); 5232 verify(mConditionProviders).setPackageOrComponentEnabled( 5233 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5234 verify(mAssistants).migrateToXml(); 5235 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 5236 } 5237 5238 @Test testSetDndAccess_onLowRam()5239 public void testSetDndAccess_onLowRam() throws Exception { 5240 when(mActivityManager.isLowRamDevice()).thenReturn(true); 5241 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5242 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 5243 5244 verify(mListeners).migrateToXml(); 5245 verify(mConditionProviders).setPackageOrComponentEnabled( 5246 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5247 verify(mAssistants).migrateToXml(); 5248 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 5249 } 5250 5251 @Test testSetListenerAccess_doesNothingOnLowRam_exceptWatch()5252 public void testSetListenerAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 5253 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 5254 when(mActivityManager.isLowRamDevice()).thenReturn(true); 5255 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5256 5257 mBinderService.setNotificationListenerAccessGranted(c, true, true); 5258 5259 verify(mListeners, times(1)).setPackageOrComponentEnabled( 5260 c.flattenToString(), mContext.getUserId(), true, true, true); 5261 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5262 c.flattenToString(), mContext.getUserId(), false, true, true); 5263 verify(mAssistants, never()).setPackageOrComponentEnabled( 5264 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5265 } 5266 5267 @Test testSetAssistantAccess_doesNothingOnLowRam_exceptWatch()5268 public void testSetAssistantAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 5269 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 5270 when(mActivityManager.isLowRamDevice()).thenReturn(true); 5271 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5272 List<UserInfo> uis = new ArrayList<>(); 5273 UserInfo ui = new UserInfo(); 5274 ui.id = mContext.getUserId(); 5275 uis.add(ui); 5276 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5277 5278 mBinderService.setNotificationAssistantAccessGranted(c, true); 5279 5280 verify(mListeners, never()).setPackageOrComponentEnabled( 5281 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5282 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5283 c.flattenToString(), ui.id, false, true); 5284 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5285 c.flattenToString(), ui.id, true, true, true); 5286 } 5287 5288 @Test testSetDndAccess_doesNothingOnLowRam_exceptWatch()5289 public void testSetDndAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 5290 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 5291 when(mActivityManager.isLowRamDevice()).thenReturn(true); 5292 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5293 5294 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 5295 5296 verify(mListeners, never()).setPackageOrComponentEnabled( 5297 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5298 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5299 c.getPackageName(), mContext.getUserId(), true, true); 5300 verify(mAssistants, never()).setPackageOrComponentEnabled( 5301 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5302 } 5303 5304 @Test testOnlyAutogroupIfNeeded_newNotification_ghUpdate()5305 public void testOnlyAutogroupIfNeeded_newNotification_ghUpdate() { 5306 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 5307 mService.addEnqueuedNotification(r); 5308 NotificationManagerService.PostNotificationRunnable runnable = 5309 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 5310 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 5311 runnable.run(); 5312 waitForIdle(); 5313 5314 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 5315 } 5316 5317 @Test testOnlyAutogroupIfNeeded_groupChanged_ghUpdate()5318 public void testOnlyAutogroupIfNeeded_groupChanged_ghUpdate() { 5319 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 5320 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", "group", false); 5321 mService.addNotification(r); 5322 5323 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 5324 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", null, false); 5325 mService.addEnqueuedNotification(update); 5326 NotificationManagerService.PostNotificationRunnable runnable = 5327 mService.new PostNotificationRunnable(update.getKey(), 5328 update.getSbn().getPackageName(), update.getUid(), 5329 mPostNotificationTrackerFactory.newTracker(null)); 5330 runnable.run(); 5331 waitForIdle(); 5332 5333 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 5334 } 5335 5336 @Test testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate()5337 public void testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate() { 5338 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 5339 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", "group", false); 5340 mService.addNotification(r); 5341 5342 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 5343 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", null, false); 5344 update.getNotification().flags = FLAG_AUTO_CANCEL; 5345 mService.addEnqueuedNotification(update); 5346 NotificationManagerService.PostNotificationRunnable runnable = 5347 mService.new PostNotificationRunnable(update.getKey(), 5348 update.getSbn().getPackageName(), update.getUid(), 5349 mPostNotificationTrackerFactory.newTracker(null)); 5350 runnable.run(); 5351 waitForIdle(); 5352 5353 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 5354 } 5355 5356 @Test testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate()5357 public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() { 5358 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 5359 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); 5360 mService.addNotification(r); 5361 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 5362 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); 5363 update.getNotification().color = Color.BLACK; 5364 mService.addEnqueuedNotification(update); 5365 5366 NotificationManagerService.PostNotificationRunnable runnable = 5367 mService.new PostNotificationRunnable(update.getKey(), 5368 update.getSbn().getPackageName(), 5369 update.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 5370 runnable.run(); 5371 waitForIdle(); 5372 5373 verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean()); 5374 } 5375 5376 @Test testDontAutogroupIfCritical()5377 public void testDontAutogroupIfCritical() throws Exception { 5378 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 5379 r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW); 5380 mService.addEnqueuedNotification(r); 5381 NotificationManagerService.PostNotificationRunnable runnable = 5382 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 5383 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 5384 runnable.run(); 5385 5386 r = generateNotificationRecord(mTestNotificationChannel, 1, null, false); 5387 r.setCriticality(CriticalNotificationExtractor.CRITICAL); 5388 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 5389 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 5390 mService.addEnqueuedNotification(r); 5391 5392 runnable.run(); 5393 waitForIdle(); 5394 5395 verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean()); 5396 } 5397 5398 @Test testNoNotificationDuringSetupPermission()5399 public void testNoNotificationDuringSetupPermission() throws Exception { 5400 mContext.getTestablePermissions().setPermission( 5401 android.Manifest.permission.NOTIFICATION_DURING_SETUP, PERMISSION_GRANTED); 5402 Bundle extras = new Bundle(); 5403 extras.putBoolean(EXTRA_ALLOW_DURING_SETUP, true); 5404 Notification.Builder nb = new Notification.Builder(mContext, 5405 mTestNotificationChannel.getId()) 5406 .setContentTitle("foo") 5407 .addExtras(extras) 5408 .setSmallIcon(android.R.drawable.sym_def_app_icon); 5409 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 5410 "testNoNotificationDuringSetupPermission", mUid, 0, 5411 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 5412 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 5413 5414 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 5415 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 5416 waitForIdle(); 5417 5418 NotificationRecord posted = mService.findNotificationLocked( 5419 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 5420 5421 assertTrue(posted.getNotification().extras.containsKey(EXTRA_ALLOW_DURING_SETUP)); 5422 } 5423 5424 @Test testNoFakeColorizedPermission()5425 public void testNoFakeColorizedPermission() throws Exception { 5426 mContext.getTestablePermissions().setPermission( 5427 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_DENIED); 5428 Notification.Builder nb = new Notification.Builder(mContext, 5429 mTestNotificationChannel.getId()) 5430 .setContentTitle("foo") 5431 .setColorized(true).setColor(Color.WHITE) 5432 .setFlag(FLAG_CAN_COLORIZE, true) 5433 .setSmallIcon(android.R.drawable.sym_def_app_icon); 5434 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 5435 "testNoFakeColorizedPermission", mUid, 0, 5436 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 5437 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 5438 5439 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 5440 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 5441 waitForIdle(); 5442 5443 NotificationRecord posted = mService.findNotificationLocked( 5444 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 5445 5446 assertFalse(posted.getNotification().isColorized()); 5447 } 5448 5449 @Test 5450 @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION}) testMediaStyle_enforceNoClearFlagEnabled()5451 public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException { 5452 Notification.MediaStyle style = new Notification.MediaStyle(); 5453 Notification.Builder nb = new Notification.Builder(mContext, 5454 mTestNotificationChannel.getId()) 5455 .setStyle(style); 5456 5457 NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag"); 5458 5459 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR); 5460 } 5461 5462 @Test 5463 @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION}) testCustomMediaStyle_enforceNoClearFlagEnabled()5464 public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException { 5465 Notification.DecoratedMediaCustomViewStyle style = 5466 new Notification.DecoratedMediaCustomViewStyle(); 5467 Notification.Builder nb = new Notification.Builder(mContext, 5468 mTestNotificationChannel.getId()) 5469 .setStyle(style); 5470 5471 NotificationRecord posted = createAndPostNotification(nb, 5472 "testCustomMediaStyleSetNoClearFlag"); 5473 5474 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR); 5475 } 5476 5477 @Test 5478 @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION) testMediaStyle_enforceNoClearFlagDisabled()5479 public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException { 5480 Notification.MediaStyle style = new Notification.MediaStyle(); 5481 Notification.Builder nb = new Notification.Builder(mContext, 5482 mTestNotificationChannel.getId()) 5483 .setStyle(style); 5484 5485 NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag"); 5486 5487 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR); 5488 } 5489 5490 @Test 5491 @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION) testCustomMediaStyle_enforceNoClearFlagDisabled()5492 public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException { 5493 Notification.DecoratedMediaCustomViewStyle style = 5494 new Notification.DecoratedMediaCustomViewStyle(); 5495 Notification.Builder nb = new Notification.Builder(mContext, 5496 mTestNotificationChannel.getId()) 5497 .setStyle(style); 5498 5499 NotificationRecord posted = createAndPostNotification(nb, 5500 "testCustomMediaStyleSetNoClearFlag"); 5501 5502 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR); 5503 } 5504 5505 @Test testMediaStyleRemote_hasPermission()5506 public void testMediaStyleRemote_hasPermission() throws RemoteException { 5507 String deviceName = "device"; 5508 mContext.getTestablePermissions().setPermission( 5509 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_GRANTED); 5510 Notification.MediaStyle style = new Notification.MediaStyle(); 5511 style.setRemotePlaybackInfo(deviceName, 0, null); 5512 Notification.Builder nb = new Notification.Builder(mContext, 5513 mTestNotificationChannel.getId()) 5514 .setStyle(style); 5515 5516 NotificationRecord posted = createAndPostNotification(nb, 5517 "testMediaStyleRemoteHasPermission"); 5518 Bundle extras = posted.getNotification().extras; 5519 5520 assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 5521 assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 5522 } 5523 5524 @Test testMediaStyleRemote_noPermission()5525 public void testMediaStyleRemote_noPermission() throws RemoteException { 5526 String deviceName = "device"; 5527 mContext.getTestablePermissions().setPermission( 5528 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_DENIED); 5529 Notification.MediaStyle style = new Notification.MediaStyle(); 5530 style.setRemotePlaybackInfo(deviceName, 0, null); 5531 Notification.Builder nb = new Notification.Builder(mContext, 5532 mTestNotificationChannel.getId()) 5533 .setStyle(style); 5534 5535 NotificationRecord posted = createAndPostNotification(nb, 5536 "testMediaStyleRemoteNoPermission"); 5537 5538 assertFalse(posted.getNotification().extras 5539 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 5540 assertFalse(posted.getNotification().extras 5541 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); 5542 assertFalse(posted.getNotification().extras 5543 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); 5544 } 5545 5546 @Test testCustomMediaStyleRemote_noPermission()5547 public void testCustomMediaStyleRemote_noPermission() throws RemoteException { 5548 String deviceName = "device"; 5549 when(mPackageManager.checkPermission( 5550 eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt())) 5551 .thenReturn(PERMISSION_DENIED); 5552 Notification.DecoratedMediaCustomViewStyle style = 5553 new Notification.DecoratedMediaCustomViewStyle(); 5554 style.setRemotePlaybackInfo(deviceName, 0, null); 5555 Notification.Builder nb = new Notification.Builder(mContext, 5556 mTestNotificationChannel.getId()) 5557 .setStyle(style); 5558 5559 NotificationRecord posted = createAndPostNotification(nb, 5560 "testCustomMediaStyleRemoteNoPermission"); 5561 5562 assertFalse(posted.getNotification().extras 5563 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 5564 assertFalse(posted.getNotification().extras 5565 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); 5566 assertFalse(posted.getNotification().extras 5567 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); 5568 } 5569 5570 @Test testSubstituteAppName_hasPermission()5571 public void testSubstituteAppName_hasPermission() throws RemoteException { 5572 String subName = "Substitute Name"; 5573 mContext.getTestablePermissions().setPermission( 5574 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_GRANTED); 5575 Bundle extras = new Bundle(); 5576 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName); 5577 Notification.Builder nb = new Notification.Builder(mContext, 5578 mTestNotificationChannel.getId()) 5579 .addExtras(extras); 5580 5581 NotificationRecord posted = createAndPostNotification(nb, 5582 "testSubstituteAppNameHasPermission"); 5583 5584 assertTrue(posted.getNotification().extras 5585 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)); 5586 assertEquals(posted.getNotification().extras 5587 .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName); 5588 } 5589 5590 @Test testSubstituteAppName_noPermission()5591 public void testSubstituteAppName_noPermission() throws RemoteException { 5592 mContext.getTestablePermissions().setPermission( 5593 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_DENIED); 5594 Bundle extras = new Bundle(); 5595 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name"); 5596 Notification.Builder nb = new Notification.Builder(mContext, 5597 mTestNotificationChannel.getId()) 5598 .addExtras(extras); 5599 5600 NotificationRecord posted = createAndPostNotification(nb, 5601 "testSubstituteAppNameNoPermission"); 5602 5603 assertFalse(posted.getNotification().extras 5604 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)); 5605 } 5606 5607 @Test testGetNotificationCountLocked()5608 public void testGetNotificationCountLocked() { 5609 String sampleTagToExclude = null; 5610 int sampleIdToExclude = 0; 5611 for (int i = 0; i < 20; i++) { 5612 NotificationRecord r = 5613 generateNotificationRecord(mTestNotificationChannel, i, null, false); 5614 mService.addEnqueuedNotification(r); 5615 5616 } 5617 for (int i = 0; i < 20; i++) { 5618 NotificationRecord r = 5619 generateNotificationRecord(mTestNotificationChannel, i, null, false); 5620 mService.addNotification(r); 5621 sampleTagToExclude = r.getSbn().getTag(); 5622 sampleIdToExclude = i; 5623 } 5624 5625 // another package 5626 Notification n = 5627 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 5628 .setSmallIcon(android.R.drawable.sym_def_app_icon) 5629 .build(); 5630 5631 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0, 5632 n, UserHandle.getUserHandleForUid(mUid), null, 0); 5633 NotificationRecord otherPackage = 5634 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 5635 mService.addEnqueuedNotification(otherPackage); 5636 mService.addNotification(otherPackage); 5637 5638 // Same notifications are enqueued as posted, everything counts b/c id and tag don't match 5639 // anything that's currently enqueued or posted 5640 int userId = mUserId; 5641 assertEquals(40, 5642 mService.getNotificationCount(mPkg, userId, 0, null)); 5643 assertEquals(40, 5644 mService.getNotificationCount(mPkg, userId, 0, "tag2")); 5645 5646 // return all for package "a" - "banana" tag isn't used 5647 assertEquals(2, 5648 mService.getNotificationCount("a", userId, 0, "banana")); 5649 5650 // exclude a known notification - it's excluded from only the posted list, not enqueued 5651 assertEquals(39, mService.getNotificationCount( 5652 mPkg, userId, sampleIdToExclude, sampleTagToExclude)); 5653 } 5654 5655 @Test testAddAutogroup_requestsSort()5656 public void testAddAutogroup_requestsSort() throws Exception { 5657 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 5658 mService.addNotification(r); 5659 mService.addAutogroupKeyLocked(r.getKey(), true); 5660 5661 verify(mRankingHandler, times(1)).requestSort(); 5662 } 5663 5664 @Test testRemoveAutogroup_requestsSort()5665 public void testRemoveAutogroup_requestsSort() throws Exception { 5666 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 5667 r.setOverrideGroupKey("TEST"); 5668 mService.addNotification(r); 5669 mService.removeAutogroupKeyLocked(r.getKey()); 5670 5671 verify(mRankingHandler, times(1)).requestSort(); 5672 } 5673 5674 @Test testReaddAutogroup_noSort()5675 public void testReaddAutogroup_noSort() throws Exception { 5676 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 5677 r.setOverrideGroupKey("TEST"); 5678 mService.addNotification(r); 5679 mService.addAutogroupKeyLocked(r.getKey(), true); 5680 5681 verify(mRankingHandler, never()).requestSort(); 5682 } 5683 5684 @Test 5685 @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST) testAutogroupSuppressSort_noSort()5686 public void testAutogroupSuppressSort_noSort() throws Exception { 5687 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 5688 mService.addNotification(r); 5689 mService.addAutogroupKeyLocked(r.getKey(), false); 5690 5691 verify(mRankingHandler, never()).requestSort(); 5692 } 5693 5694 @Test 5695 @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST) testAutogroupOnPost_skipManualSort()5696 public void testAutogroupOnPost_skipManualSort() throws Exception { 5697 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 5698 mService.addNotification(r); 5699 verify(mRankingHandler, never()).requestSort(); 5700 } 5701 5702 @Test testHandleRankingSort_sendsUpdateOnSignalExtractorChange()5703 public void testHandleRankingSort_sendsUpdateOnSignalExtractorChange() throws Exception { 5704 mService.setPreferencesHelper(mPreferencesHelper); 5705 NotificationManagerService.WorkerHandler handler = mock( 5706 NotificationManagerService.WorkerHandler.class); 5707 mService.setHandler(handler); 5708 5709 Map<String, Answer> answers = getSignalExtractorSideEffects(); 5710 for (String message : answers.keySet()) { 5711 mService.clearNotifications(); 5712 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 5713 mService.addNotification(r); 5714 5715 doAnswer(answers.get(message)).when(mRankingHelper).extractSignals(r); 5716 5717 mService.handleRankingSort(); 5718 } 5719 verify(handler, times(answers.size())).scheduleSendRankingUpdate(); 5720 } 5721 5722 @Test testHandleRankingSort_noUpdateWhenNoSignalChange()5723 public void testHandleRankingSort_noUpdateWhenNoSignalChange() throws Exception { 5724 mService.setRankingHelper(mRankingHelper); 5725 NotificationManagerService.WorkerHandler handler = mock( 5726 NotificationManagerService.WorkerHandler.class); 5727 mService.setHandler(handler); 5728 5729 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 5730 mService.addNotification(r); 5731 5732 mService.handleRankingSort(); 5733 verify(handler, never()).scheduleSendRankingUpdate(); 5734 } 5735 5736 @Test testReadPolicyXml_readApprovedServicesFromXml()5737 public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception { 5738 final String upgradeXml = "<notification-policy version=\"1\">" 5739 + "<ranking></ranking>" 5740 + "<enabled_listeners>" 5741 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 5742 + "</enabled_listeners>" 5743 + "<enabled_assistants>" 5744 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 5745 + "</enabled_assistants>" 5746 + "<dnd_apps>" 5747 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 5748 + "</dnd_apps>" 5749 + "</notification-policy>"; 5750 mService.readPolicyXml( 5751 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), 5752 false, 5753 UserHandle.USER_ALL); 5754 verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 5755 verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 5756 verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 5757 5758 // numbers are inflated for setup 5759 verify(mListeners, times(1)).migrateToXml(); 5760 verify(mConditionProviders, times(1)).migrateToXml(); 5761 verify(mAssistants, times(1)).migrateToXml(); 5762 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 5763 } 5764 5765 @Test testReadPolicyXml_readSnoozedNotificationsFromXml()5766 public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception { 5767 final String upgradeXml = "<notification-policy version=\"1\">" 5768 + "<snoozed-notifications>></snoozed-notifications>" 5769 + "</notification-policy>"; 5770 mService.readPolicyXml( 5771 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), 5772 false, 5773 UserHandle.USER_ALL); 5774 verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong()); 5775 } 5776 5777 @Test testReadPolicyXml_readApprovedServicesFromSettings()5778 public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception { 5779 final String preupgradeXml = "<notification-policy version=\"1\">" 5780 + "<ranking></ranking>" 5781 + "</notification-policy>"; 5782 mService.readPolicyXml( 5783 new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), 5784 false, 5785 UserHandle.USER_ALL); 5786 verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt()); 5787 verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt()); 5788 verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt()); 5789 5790 // numbers are inflated for setup 5791 verify(mListeners, times(2)).migrateToXml(); 5792 verify(mConditionProviders, times(2)).migrateToXml(); 5793 verify(mAssistants, times(2)).migrateToXml(); 5794 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 5795 } 5796 5797 @Test testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser()5798 public void testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser() throws Exception { 5799 final String policyXml = "<notification-policy version=\"1\">" 5800 + "<ranking></ranking>" 5801 + "<enabled_listeners>" 5802 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5803 + "</enabled_listeners>" 5804 + "<enabled_assistants>" 5805 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5806 + "</enabled_assistants>" 5807 + "<dnd_apps>" 5808 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5809 + "</dnd_apps>" 5810 + "</notification-policy>"; 5811 UserInfo ui = new UserInfo(10, "Clone", UserInfo.FLAG_PROFILE); 5812 ui.userType = USER_TYPE_PROFILE_CLONE; 5813 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 5814 mService.readPolicyXml( 5815 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 5816 true, 5817 10); 5818 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 5819 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 5820 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 5821 } 5822 5823 @Test testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser()5824 public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception { 5825 final String policyXml = "<notification-policy version=\"1\">" 5826 + "<ranking></ranking>" 5827 + "<enabled_listeners>" 5828 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5829 + "</enabled_listeners>" 5830 + "<enabled_assistants>" 5831 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5832 + "</enabled_assistants>" 5833 + "<dnd_apps>" 5834 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5835 + "</dnd_apps>" 5836 + "</notification-policy>"; 5837 UserInfo ui = new UserInfo(10, "Work", UserInfo.FLAG_PROFILE); 5838 ui.userType = USER_TYPE_PROFILE_MANAGED; 5839 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 5840 mService.readPolicyXml( 5841 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 5842 true, 5843 10); 5844 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 5845 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 5846 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 5847 } 5848 5849 @Test testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser()5850 public void testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser() throws Exception { 5851 mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, 5852 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 5853 final String policyXml = "<notification-policy version=\"1\">" 5854 + "<ranking></ranking>" 5855 + "<enabled_listeners>" 5856 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5857 + "</enabled_listeners>" 5858 + "<enabled_assistants>" 5859 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5860 + "</enabled_assistants>" 5861 + "<dnd_apps>" 5862 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5863 + "</dnd_apps>" 5864 + "</notification-policy>"; 5865 UserInfo ui = new UserInfo(10, "Private", UserInfo.FLAG_PROFILE); 5866 ui.userType = USER_TYPE_PROFILE_PRIVATE; 5867 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 5868 mService.readPolicyXml( 5869 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 5870 true, 5871 10); 5872 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 5873 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 5874 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 5875 } 5876 5877 @Test testReadPolicyXml_restoresManagedServicesForNonManagedUser()5878 public void testReadPolicyXml_restoresManagedServicesForNonManagedUser() throws Exception { 5879 final String policyXml = "<notification-policy version=\"1\">" 5880 + "<ranking></ranking>" 5881 + "<enabled_listeners>" 5882 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5883 + "</enabled_listeners>" 5884 + "<enabled_assistants>" 5885 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5886 + "</enabled_assistants>" 5887 + "<dnd_apps>" 5888 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 5889 + "</dnd_apps>" 5890 + "</notification-policy>"; 5891 UserInfo ui = new UserInfo(); 5892 ui.id = 10; 5893 ui.userType = USER_TYPE_FULL_SECONDARY; 5894 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 5895 mService.readPolicyXml( 5896 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 5897 true, 5898 10); 5899 verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10)); 5900 verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10)); 5901 verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10)); 5902 } 5903 5904 @Test testLocaleChangedCallsUpdateDefaultZenModeRules()5905 public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception { 5906 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 5907 mService.mZenModeHelper = mZenModeHelper; 5908 mService.mLocaleChangeReceiver.onReceive(mContext, 5909 new Intent(Intent.ACTION_LOCALE_CHANGED)); 5910 5911 verify(mZenModeHelper).updateZenRulesOnLocaleChange(); 5912 } 5913 simulateNotificationTimeout(String notificationKey)5914 private void simulateNotificationTimeout(String notificationKey) { 5915 if (Flags.allNotifsNeedTtl()) { 5916 mService.mNotificationManagerPrivate.timeoutNotification(notificationKey); 5917 } else { 5918 final Bundle extras = new Bundle(); 5919 extras.putString(EXTRA_KEY, notificationKey); 5920 final Intent intent = new Intent(ACTION_NOTIFICATION_TIMEOUT); 5921 intent.putExtras(extras); 5922 mNotificationTimeoutReceiver.onReceive(getContext(), intent); 5923 } 5924 } 5925 5926 @Test testTimeout_CancelsNotification()5927 public void testTimeout_CancelsNotification() throws Exception { 5928 final NotificationRecord notif = generateNotificationRecord( 5929 mTestNotificationChannel, 1, null, false); 5930 mService.addNotification(notif); 5931 5932 simulateNotificationTimeout(notif.getKey()); 5933 waitForIdle(); 5934 5935 // Check that the notification was cancelled. 5936 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 5937 assertThat(notifsAfter.length).isEqualTo(0); 5938 assertThat(mService.getNotificationRecord(notif.getKey())).isNull(); 5939 } 5940 5941 @Test testTimeout_NoCancelForegroundServiceNotification()5942 public void testTimeout_NoCancelForegroundServiceNotification() throws Exception { 5943 // Creates a notification with FLAG_FOREGROUND_SERVICE 5944 final NotificationRecord notif = generateNotificationRecord(null); 5945 notif.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; 5946 mService.addNotification(notif); 5947 5948 simulateNotificationTimeout(notif.getKey()); 5949 waitForIdle(); 5950 5951 // Check that the notification was not cancelled. 5952 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 5953 assertThat(notifsAfter.length).isEqualTo(1); 5954 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 5955 } 5956 5957 @Test testTimeout_NoCancelUserInitJobNotification()5958 public void testTimeout_NoCancelUserInitJobNotification() throws Exception { 5959 // Create a notification with FLAG_USER_INITIATED_JOB 5960 final NotificationRecord notif = generateNotificationRecord(null); 5961 notif.getSbn().getNotification().flags = Notification.FLAG_USER_INITIATED_JOB; 5962 mService.addNotification(notif); 5963 5964 simulateNotificationTimeout(notif.getKey()); 5965 waitForIdle(); 5966 5967 // Check that the notification was not cancelled. 5968 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 5969 assertThat(notifsAfter.length).isEqualTo(1); 5970 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 5971 } 5972 5973 @Test 5974 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testTimeout_NoCancelLifetimeExtensionNotification()5975 public void testTimeout_NoCancelLifetimeExtensionNotification() throws Exception { 5976 // Create a notification with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY 5977 final NotificationRecord notif = generateNotificationRecord(null); 5978 notif.getSbn().getNotification().flags = 5979 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 5980 mService.addNotification(notif); 5981 5982 simulateNotificationTimeout(notif.getKey()); 5983 waitForIdle(); 5984 5985 // Check that the notification was not cancelled. 5986 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 5987 assertThat(notifsAfter.length).isEqualTo(1); 5988 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 5989 5990 // Checks that a post update is sent. 5991 verify(mWorkerHandler, times(1)) 5992 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 5993 ArgumentCaptor<NotificationRecord> captor = 5994 ArgumentCaptor.forClass(NotificationRecord.class); 5995 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 5996 anyBoolean()); 5997 assertThat(captor.getValue().getNotification().flags 5998 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 5999 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 6000 } 6001 6002 @Test testBumpFGImportance_channelChangePreOApp()6003 public void testBumpFGImportance_channelChangePreOApp() throws Exception { 6004 Notification.Builder nb = new Notification.Builder(mContext, 6005 NotificationChannel.DEFAULT_CHANNEL_ID) 6006 .setContentTitle("foo") 6007 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6008 .setFlag(FLAG_FOREGROUND_SERVICE, true) 6009 .setPriority(Notification.PRIORITY_MIN); 6010 6011 StatusBarNotification sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, 6012 "testBumpFGImportance_channelChangePreOApp", 6013 Binder.getCallingUid(), 0, nb.build(), 6014 UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); 6015 6016 mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(), 6017 sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId()); 6018 waitForIdle(); 6019 6020 assertEquals(IMPORTANCE_LOW, 6021 mService.getNotificationRecord(sbn.getKey()).getImportance()); 6022 assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance( 6023 sbn.getPackageName())); 6024 6025 nb = new Notification.Builder(mContext) 6026 .setContentTitle("foo") 6027 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6028 .setFlag(FLAG_FOREGROUND_SERVICE, true) 6029 .setPriority(Notification.PRIORITY_MIN); 6030 6031 sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, 6032 "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(), 6033 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); 6034 6035 mBinderService.enqueueNotificationWithTag(PKG_N_MR1, PKG_N_MR1, 6036 "testBumpFGImportance_channelChangePreOApp", 6037 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 6038 waitForIdle(); 6039 assertEquals(IMPORTANCE_LOW, 6040 mService.getNotificationRecord(sbn.getKey()).getImportance()); 6041 6042 NotificationChannel defaultChannel = mBinderService.getNotificationChannel( 6043 PKG_N_MR1, mContext.getUserId(), PKG_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID); 6044 assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance()); 6045 } 6046 6047 @Test testStats_updatedOnDirectReply()6048 public void testStats_updatedOnDirectReply() throws Exception { 6049 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6050 mService.addNotification(r); 6051 6052 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 6053 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied()); 6054 verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r)); 6055 6056 assertEquals(1, mNotificationRecordLogger.numCalls()); 6057 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED, 6058 mNotificationRecordLogger.event(0)); 6059 } 6060 6061 @Test 6062 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_DirectReplyLifetimeExtendedPostsUpdate()6063 public void testStats_DirectReplyLifetimeExtendedPostsUpdate() throws Exception { 6064 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6065 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 6066 mService.addNotification(r); 6067 6068 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 6069 waitForIdle(); 6070 6071 assertThat(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied()) 6072 .isTrue(); 6073 // Checks that a post update is sent. 6074 verify(mWorkerHandler, times(1)) 6075 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 6076 ArgumentCaptor<NotificationRecord> captor = 6077 ArgumentCaptor.forClass(NotificationRecord.class); 6078 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 6079 anyBoolean()); 6080 assertThat(captor.getValue().getNotification().flags 6081 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 6082 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 6083 assertThat(captor.getValue().getNotification().flags 6084 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 6085 assertThat(captor.getValue().shouldPostSilently()).isTrue(); 6086 } 6087 6088 @Test 6089 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds()6090 public void testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds() throws Exception { 6091 // Creates a lifetime extended notification. 6092 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 6093 original.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 6094 mService.addNotification(original); 6095 6096 // Post an update for that notification. 6097 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(), 6098 original.getSbn().getTag(), mUid, 0, 6099 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 6100 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6101 .setContentTitle("new title").build(), 6102 UserHandle.getUserHandleForUid(mUid), null, 0); 6103 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6104 mService.addEnqueuedNotification(update); 6105 6106 NotificationManagerService.PostNotificationRunnable runnable = 6107 mService.new PostNotificationRunnable(update.getKey(), 6108 update.getSbn().getPackageName(), 6109 update.getUid(), 6110 mPostNotificationTrackerFactory.newTracker(null)); 6111 runnable.run(); 6112 waitForIdle(); 6113 6114 // Checks the update was sent, and that update contains the new title, and does not contain 6115 // the lifetime extension flag. 6116 ArgumentCaptor<NotificationRecord> captor = 6117 ArgumentCaptor.forClass(NotificationRecord.class); 6118 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 6119 anyBoolean()); 6120 assertThat(captor.getValue().getNotification().flags 6121 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0); 6122 assertThat(captor.getValue() 6123 .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString()) 6124 .isEqualTo("new title"); 6125 } 6126 6127 @Test testStats_updatedOnUserExpansion()6128 public void testStats_updatedOnUserExpansion() throws Exception { 6129 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6130 mService.addNotification(r); 6131 6132 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true, 6133 NOTIFICATION_LOCATION_UNKNOWN); 6134 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 6135 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((true))); 6136 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 6137 6138 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false, 6139 NOTIFICATION_LOCATION_UNKNOWN); 6140 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 6141 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((false))); 6142 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 6143 6144 assertEquals(2, mNotificationRecordLogger.numCalls()); 6145 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_OPEN_USER, 6146 mNotificationRecordLogger.event(0)); 6147 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_CLOSE_USER, 6148 mNotificationRecordLogger.event(1)); 6149 } 6150 6151 @Test testStats_notUpdatedOnAutoExpansion()6152 public void testStats_notUpdatedOnAutoExpansion() throws Exception { 6153 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6154 mService.addNotification(r); 6155 6156 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 6157 NOTIFICATION_LOCATION_UNKNOWN); 6158 assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 6159 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 6160 eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((true))); 6161 6162 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false, 6163 NOTIFICATION_LOCATION_UNKNOWN); 6164 assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 6165 verify(mAssistants).notifyAssistantExpansionChangedLocked( 6166 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((false))); 6167 } 6168 6169 @Test testStats_updatedOnViewSettings()6170 public void testStats_updatedOnViewSettings() throws Exception { 6171 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6172 mService.addNotification(r); 6173 6174 mService.mNotificationDelegate.onNotificationSettingsViewed(r.getKey()); 6175 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasViewedSettings()); 6176 } 6177 6178 @Test testStats_updatedOnVisibilityChanged()6179 public void testStats_updatedOnVisibilityChanged() throws Exception { 6180 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6181 mService.addNotification(r); 6182 6183 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true); 6184 mService.mNotificationDelegate.onNotificationVisibilityChanged( 6185 new NotificationVisibility[] {nv}, new NotificationVisibility[]{}); 6186 verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(true)); 6187 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen()); 6188 mService.mNotificationDelegate.onNotificationVisibilityChanged( 6189 new NotificationVisibility[] {}, new NotificationVisibility[]{nv}); 6190 verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(false)); 6191 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen()); 6192 } 6193 6194 @Test testStats_dismissalSurface()6195 public void testStats_dismissalSurface() throws Exception { 6196 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6197 r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6198 mService.addNotification(r); 6199 6200 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); 6201 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(), 6202 r.getKey(), NotificationStats.DISMISSAL_AOD, 6203 NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv); 6204 waitForIdle(); 6205 6206 assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface()); 6207 6208 // Using mService.addNotification() does not generate a NotificationRecordLogger log, 6209 // so we only get the cancel notification. 6210 assertEquals(1, mNotificationRecordLogger.numCalls()); 6211 6212 assertEquals( 6213 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD, 6214 mNotificationRecordLogger.event(0)); 6215 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 6216 } 6217 6218 @Test testStats_dismissalSentiment()6219 public void testStats_dismissalSentiment() throws Exception { 6220 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6221 mService.addNotification(r); 6222 6223 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); 6224 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(), 6225 r.getKey(), NotificationStats.DISMISSAL_AOD, 6226 NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv); 6227 waitForIdle(); 6228 6229 assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE, 6230 r.getStats().getDismissalSentiment()); 6231 } 6232 6233 @Test testTextChangedSet_forNewNotifs()6234 public void testTextChangedSet_forNewNotifs() throws Exception { 6235 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 6236 mService.addEnqueuedNotification(original); 6237 6238 NotificationManagerService.PostNotificationRunnable runnable = 6239 mService.new PostNotificationRunnable(original.getKey(), 6240 original.getSbn().getPackageName(), 6241 original.getUid(), 6242 mPostNotificationTrackerFactory.newTracker(null)); 6243 runnable.run(); 6244 waitForIdle(); 6245 6246 assertTrue(original.isTextChanged()); 6247 } 6248 6249 @Test testVisuallyInterruptive_notSeen()6250 public void testVisuallyInterruptive_notSeen() throws Exception { 6251 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 6252 mService.addNotification(original); 6253 6254 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(), 6255 original.getSbn().getTag(), mUid, 0, 6256 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 6257 .setContentTitle("new title").build(), 6258 UserHandle.getUserHandleForUid(mUid), null, 0); 6259 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6260 mService.addEnqueuedNotification(update); 6261 6262 NotificationManagerService.PostNotificationRunnable runnable = 6263 mService.new PostNotificationRunnable(update.getKey(), 6264 update.getSbn().getPackageName(), 6265 update.getUid(), 6266 mPostNotificationTrackerFactory.newTracker(null)); 6267 runnable.run(); 6268 waitForIdle(); 6269 6270 assertFalse(update.isInterruptive()); 6271 } 6272 6273 @Test testApplyAdjustmentMultiUser()6274 public void testApplyAdjustmentMultiUser() throws Exception { 6275 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6276 mService.addNotification(r); 6277 NotificationManagerService.WorkerHandler handler = mock( 6278 NotificationManagerService.WorkerHandler.class); 6279 mService.setHandler(handler); 6280 6281 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false); 6282 6283 Bundle signals = new Bundle(); 6284 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 6285 USER_SENTIMENT_NEGATIVE); 6286 Adjustment adjustment = new Adjustment( 6287 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6288 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 6289 6290 waitForIdle(); 6291 6292 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 6293 } 6294 6295 @Test testAssistantBlockingTriggersCancel()6296 public void testAssistantBlockingTriggersCancel() throws Exception { 6297 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6298 mService.addNotification(r); 6299 NotificationManagerService.WorkerHandler handler = mock( 6300 NotificationManagerService.WorkerHandler.class); 6301 mService.setHandler(handler); 6302 6303 Bundle signals = new Bundle(); 6304 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE); 6305 Adjustment adjustment = new Adjustment( 6306 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6307 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 6308 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 6309 6310 waitForIdle(); 6311 6312 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 6313 verify(handler, times(1)).scheduleCancelNotification(any(), eq(0)); 6314 } 6315 6316 @Test testApplyEnqueuedAdjustmentFromAssistant_singleUser()6317 public void testApplyEnqueuedAdjustmentFromAssistant_singleUser() throws Exception { 6318 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6319 mService.addEnqueuedNotification(r); 6320 NotificationManagerService.WorkerHandler handler = mock( 6321 NotificationManagerService.WorkerHandler.class); 6322 mService.setHandler(handler); 6323 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6324 6325 Bundle signals = new Bundle(); 6326 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 6327 USER_SENTIMENT_NEGATIVE); 6328 Adjustment adjustment = new Adjustment( 6329 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6330 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 6331 6332 assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment()); 6333 } 6334 6335 @Test testApplyEnqueuedAdjustmentFromAssistant_importance()6336 public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception { 6337 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6338 mService.addEnqueuedNotification(r); 6339 NotificationManagerService.WorkerHandler handler = mock( 6340 NotificationManagerService.WorkerHandler.class); 6341 mService.setHandler(handler); 6342 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6343 6344 Bundle signals = new Bundle(); 6345 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); 6346 Adjustment adjustment = new Adjustment( 6347 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6348 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 6349 6350 assertEquals(IMPORTANCE_LOW, r.getImportance()); 6351 } 6352 6353 @Test testApplyEnqueuedAdjustmentFromAssistant_crossUser()6354 public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception { 6355 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6356 mService.addEnqueuedNotification(r); 6357 NotificationManagerService.WorkerHandler handler = mock( 6358 NotificationManagerService.WorkerHandler.class); 6359 mService.setHandler(handler); 6360 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false); 6361 6362 Bundle signals = new Bundle(); 6363 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 6364 USER_SENTIMENT_NEGATIVE); 6365 Adjustment adjustment = new Adjustment( 6366 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6367 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 6368 6369 assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment()); 6370 6371 waitForIdle(); 6372 6373 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 6374 } 6375 6376 @Test testUserSentimentChangeTriggersUpdate()6377 public void testUserSentimentChangeTriggersUpdate() throws Exception { 6378 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6379 mService.addNotification(r); 6380 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6381 6382 Bundle signals = new Bundle(); 6383 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 6384 USER_SENTIMENT_NEGATIVE); 6385 Adjustment adjustment = new Adjustment( 6386 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6387 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 6388 6389 waitForIdle(); 6390 6391 verify(mRankingHandler, timeout(300).times(1)).requestSort(); 6392 } 6393 6394 @Test testTooLateAdjustmentTriggersUpdate()6395 public void testTooLateAdjustmentTriggersUpdate() throws Exception { 6396 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6397 mService.addNotification(r); 6398 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6399 6400 Bundle signals = new Bundle(); 6401 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 6402 USER_SENTIMENT_NEGATIVE); 6403 Adjustment adjustment = new Adjustment( 6404 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6405 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 6406 6407 waitForIdle(); 6408 6409 verify(mRankingHandler, times(1)).requestSort(); 6410 } 6411 6412 @Test testApplyAdjustmentsLogged()6413 public void testApplyAdjustmentsLogged() throws Exception { 6414 NotificationManagerService.WorkerHandler handler = mock( 6415 NotificationManagerService.WorkerHandler.class); 6416 mService.setHandler(handler); 6417 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6418 6419 // Set up notifications that will be adjusted 6420 final NotificationRecord r1 = generateNotificationRecord( 6421 mTestNotificationChannel, 1, null, true); 6422 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6423 mService.addNotification(r1); 6424 final NotificationRecord r2 = generateNotificationRecord( 6425 mTestNotificationChannel, 2, null, true); 6426 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6427 mService.addNotification(r2); 6428 6429 // Third notification that's NOT adjusted, just to make sure that doesn't get spuriously 6430 // logged. 6431 final NotificationRecord r3 = generateNotificationRecord( 6432 mTestNotificationChannel, 3, null, true); 6433 r3.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6434 mService.addNotification(r3); 6435 6436 List<Adjustment> adjustments = new ArrayList<>(); 6437 6438 // Test an adjustment that's associated with a ranking change and one that's not 6439 Bundle signals1 = new Bundle(); 6440 signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_HIGH); 6441 Adjustment adjustment1 = new Adjustment( 6442 r1.getSbn().getPackageName(), r1.getKey(), signals1, "", 6443 r1.getUser().getIdentifier()); 6444 adjustments.add(adjustment1); 6445 6446 // This one wouldn't trigger a ranking change, but should still trigger a log. 6447 Bundle signals2 = new Bundle(); 6448 signals2.putFloat(Adjustment.KEY_RANKING_SCORE, -0.5f); 6449 Adjustment adjustment2 = new Adjustment( 6450 r2.getSbn().getPackageName(), r2.getKey(), signals2, "", 6451 r2.getUser().getIdentifier()); 6452 adjustments.add(adjustment2); 6453 6454 mBinderService.applyAdjustmentsFromAssistant(null, adjustments); 6455 verify(mRankingHandler, times(1)).requestSort(); 6456 6457 // Actually apply the adjustments & recalculate importance when run 6458 doAnswer(invocationOnMock -> { 6459 ((NotificationRecord) invocationOnMock.getArguments()[0]) 6460 .applyAdjustments(); 6461 ((NotificationRecord) invocationOnMock.getArguments()[0]) 6462 .calculateImportance(); 6463 return null; 6464 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 6465 6466 // Now make sure that when the sort happens, we actually log the changes. 6467 mService.handleRankingSort(); 6468 6469 // Even though the ranking score change is not meant to trigger a ranking update, 6470 // during this process the package visibility & canShowBadge values are changing 6471 // in all notifications, so all 3 seem to trigger a ranking change. Here we check instead 6472 // that scheduleSendRankingUpdate is sent and that the relevant fields have been changed 6473 // accordingly to confirm the adjustments happened to the 2 relevant notifications. 6474 verify(handler, times(3)).scheduleSendRankingUpdate(); 6475 assertEquals(IMPORTANCE_HIGH, r1.getImportance()); 6476 assertTrue(r2.rankingScoreMatches(-0.5f)); 6477 assertEquals(2, mNotificationRecordLogger.numCalls()); 6478 assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(0)); 6479 assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(1)); 6480 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 6481 assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId()); 6482 } 6483 6484 @Test testSensitiveAdjustmentsLogged()6485 public void testSensitiveAdjustmentsLogged() throws Exception { 6486 NotificationManagerService.WorkerHandler handler = mock( 6487 NotificationManagerService.WorkerHandler.class); 6488 mService.setHandler(handler); 6489 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 6490 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 6491 6492 // Set up notifications that will be adjusted 6493 final NotificationRecord r1 = spy(generateNotificationRecord( 6494 mTestNotificationChannel, 1, null, true)); 6495 when(r1.getLifespanMs(anyLong())).thenReturn(1); 6496 6497 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6498 mService.addEnqueuedNotification(r1); 6499 6500 // Test an adjustment for an enqueued notification 6501 Bundle signals = new Bundle(); 6502 signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true); 6503 Adjustment adjustment1 = new Adjustment( 6504 r1.getSbn().getPackageName(), r1.getKey(), signals, "", 6505 r1.getUser().getIdentifier()); 6506 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); 6507 assertTrue(mService.checkLastSensitiveLog(false, true, 1)); 6508 6509 // Set up notifications that will be adjusted 6510 final NotificationRecord r2 = spy(generateNotificationRecord( 6511 mTestNotificationChannel, 1, null, true)); 6512 when(r2.getLifespanMs(anyLong())).thenReturn(2); 6513 6514 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6515 mService.addNotification(r2); 6516 Adjustment adjustment2 = new Adjustment( 6517 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 6518 r2.getUser().getIdentifier()); 6519 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); 6520 assertTrue(mService.checkLastSensitiveLog(true, true, 2)); 6521 6522 signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, false); 6523 Adjustment adjustment3 = new Adjustment( 6524 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 6525 r2.getUser().getIdentifier()); 6526 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); 6527 assertTrue(mService.checkLastSensitiveLog(true, false, 2)); 6528 } 6529 6530 @Test testAdjustmentToImportanceNone_cancelsNotification()6531 public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception { 6532 NotificationManagerService.WorkerHandler handler = mock( 6533 NotificationManagerService.WorkerHandler.class); 6534 mService.setHandler(handler); 6535 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6536 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 6537 6538 // Set up notifications: r1 is adjusted, r2 is not 6539 final NotificationRecord r1 = generateNotificationRecord( 6540 mTestNotificationChannel, 1, null, true); 6541 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6542 mService.addNotification(r1); 6543 final NotificationRecord r2 = generateNotificationRecord( 6544 mTestNotificationChannel, 2, null, true); 6545 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 6546 mService.addNotification(r2); 6547 6548 // Test an adjustment that sets importance to none (meaning it's cancelling) 6549 Bundle signals1 = new Bundle(); 6550 signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE); 6551 Adjustment adjustment1 = new Adjustment( 6552 r1.getSbn().getPackageName(), r1.getKey(), signals1, "", 6553 r1.getUser().getIdentifier()); 6554 6555 mBinderService.applyAdjustmentFromAssistant(null, adjustment1); 6556 6557 // Actually apply the adjustments & recalculate importance when run 6558 doAnswer(invocationOnMock -> { 6559 ((NotificationRecord) invocationOnMock.getArguments()[0]) 6560 .applyAdjustments(); 6561 ((NotificationRecord) invocationOnMock.getArguments()[0]) 6562 .calculateImportance(); 6563 return null; 6564 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 6565 6566 // run the CancelNotificationRunnable when it happens 6567 ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor = 6568 ArgumentCaptor.forClass( 6569 NotificationManagerService.CancelNotificationRunnable.class); 6570 6571 verify(handler, times(1)).scheduleCancelNotification( 6572 captor.capture(), eq(0)); 6573 6574 // Run the runnable given to the cancel notification, and see if it logs properly 6575 NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue(); 6576 runnable.run(); 6577 assertEquals(1, mNotificationRecordLogger.numCalls()); 6578 assertEquals( 6579 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT, 6580 mNotificationRecordLogger.event(0)); 6581 } 6582 6583 @Test testEnqueuedAdjustmentAppliesAdjustments()6584 public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception { 6585 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6586 mService.addEnqueuedNotification(r); 6587 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6588 6589 Bundle signals = new Bundle(); 6590 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 6591 USER_SENTIMENT_NEGATIVE); 6592 Adjustment adjustment = new Adjustment( 6593 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 6594 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 6595 6596 assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment()); 6597 } 6598 6599 @Test testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications()6600 public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception { 6601 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel); 6602 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel); 6603 mService.addEnqueuedNotification(r1); 6604 mService.addEnqueuedNotification(r2); 6605 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 6606 6607 Bundle signals = new Bundle(); 6608 signals.putInt(Adjustment.KEY_IMPORTANCE, 6609 IMPORTANCE_HIGH); 6610 Adjustment adjustment = new Adjustment( 6611 r1.getSbn().getPackageName(), r1.getKey(), signals, 6612 "", r1.getUser().getIdentifier()); 6613 6614 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 6615 6616 assertEquals(IMPORTANCE_HIGH, r1.getImportance()); 6617 assertEquals(IMPORTANCE_HIGH, r2.getImportance()); 6618 } 6619 6620 @Test testRestore()6621 public void testRestore() throws Exception { 6622 int systemChecks = mService.countSystemChecks; 6623 mBinderService.applyRestore(null, USER_SYSTEM); 6624 assertEquals(1, mService.countSystemChecks - systemChecks); 6625 } 6626 6627 @Test testBackupEmptySound()6628 public void testBackupEmptySound() throws Exception { 6629 NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 6630 channel.setSound(Uri.EMPTY, null); 6631 6632 TypedXmlSerializer serializer = Xml.newFastSerializer(); 6633 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 6634 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 6635 channel.writeXmlForBackup(serializer, getContext()); 6636 6637 TypedXmlPullParser parser = Xml.newFastPullParser(); 6638 parser.setInput(new BufferedInputStream( 6639 new ByteArrayInputStream(baos.toByteArray())), null); 6640 NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 6641 restored.populateFromXmlForRestore(parser, true, getContext()); 6642 6643 assertNull(restored.getSound()); 6644 } 6645 6646 @Test testBackup()6647 public void testBackup() throws Exception { 6648 mService.setPreferencesHelper(mPreferencesHelper); 6649 int systemChecks = mService.countSystemChecks; 6650 when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt())) 6651 .thenReturn(new ArraySet<>()); 6652 mBinderService.getBackupPayload(1); 6653 assertEquals(1, mService.countSystemChecks - systemChecks); 6654 } 6655 6656 @Test testEmptyVibration_noException()6657 public void testEmptyVibration_noException() throws Exception { 6658 NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 6659 channel.setVibrationPattern(new long[0]); 6660 6661 TypedXmlSerializer serializer = Xml.newFastSerializer(); 6662 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 6663 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 6664 channel.writeXml(serializer); 6665 } 6666 6667 @Test updateUriPermissions_update()6668 public void updateUriPermissions_update() throws Exception { 6669 NotificationChannel c = new NotificationChannel( 6670 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 6671 c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT); 6672 Message message1 = new Message("", 0, ""); 6673 message1.setData("", 6674 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1)); 6675 Message message2 = new Message("", 1, ""); 6676 message2.setData("", 6677 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2)); 6678 6679 Notification.Builder nbA = new Notification.Builder(mContext, c.getId()) 6680 .setContentTitle("foo") 6681 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6682 .setStyle(new Notification.MessagingStyle("") 6683 .addMessage(message1) 6684 .addMessage(message2)); 6685 NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification( 6686 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid), 6687 null, 0), c); 6688 6689 // First post means we grant access to both 6690 reset(mUgm); 6691 reset(mUgmInternal); 6692 when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder()); 6693 mService.updateUriPermissions(recordA, null, mContext.getPackageName(), 6694 USER_SYSTEM); 6695 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 6696 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt()); 6697 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 6698 eq(message2.getDataUri()), anyInt(), anyInt(), anyInt()); 6699 6700 Notification.Builder nbB = new Notification.Builder(mContext, c.getId()) 6701 .setContentTitle("foo") 6702 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6703 .setStyle(new Notification.MessagingStyle("").addMessage(message2)); 6704 NotificationRecord recordB = new NotificationRecord(mContext, new StatusBarNotification(mPkg, 6705 mPkg, 0, "tag", mUid, 0, nbB.build(), UserHandle.getUserHandleForUid(mUid), null, 0), 6706 c); 6707 6708 // Update means we drop access to first 6709 reset(mUgmInternal); 6710 mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(), 6711 USER_SYSTEM); 6712 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), 6713 eq(message1.getDataUri()), anyInt(), anyInt(), eq(null), eq(-1)); 6714 6715 // Update back means we grant access to first again 6716 reset(mUgm); 6717 mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(), 6718 USER_SYSTEM); 6719 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 6720 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt()); 6721 6722 // And update to empty means we drop everything 6723 reset(mUgmInternal); 6724 mService.updateUriPermissions(null, recordB, mContext.getPackageName(), 6725 USER_SYSTEM); 6726 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null), 6727 anyInt(), anyInt()); 6728 } 6729 6730 @Test updateUriPermissions_posterDoesNotOwnUri()6731 public void updateUriPermissions_posterDoesNotOwnUri() throws Exception { 6732 NotificationChannel c = new NotificationChannel( 6733 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 6734 c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT); 6735 Message message1 = new Message("", 0, ""); 6736 message1.setData("", 6737 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1)); 6738 6739 Notification.Builder nbA = new Notification.Builder(mContext, c.getId()) 6740 .setContentTitle("foo") 6741 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6742 .setStyle(new Notification.MessagingStyle("") 6743 .addMessage(message1)); 6744 NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification( 6745 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid), 6746 null, 0), c); 6747 6748 doThrow(new SecurityException("no access")).when(mUgm) 6749 .grantUriPermissionFromOwner( 6750 any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt()); 6751 6752 when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder()); 6753 mService.updateUriPermissions(recordA, null, mContext.getPackageName(), USER_SYSTEM); 6754 6755 // yay, no crash 6756 } 6757 6758 @Test testVisitUris()6759 public void testVisitUris() throws Exception { 6760 final Uri audioContents = Uri.parse("content://com.example/audio"); 6761 final Uri backgroundImage = Uri.parse("content://com.example/background"); 6762 final Icon smallIcon = Icon.createWithContentUri("content://media/small/icon"); 6763 final Icon largeIcon = Icon.createWithContentUri("content://media/large/icon"); 6764 final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); 6765 final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); 6766 final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); 6767 final Person person1 = new Person.Builder() 6768 .setName("Messaging Person") 6769 .setIcon(personIcon1) 6770 .build(); 6771 final Person person2 = new Person.Builder() 6772 .setName("People List Person 1") 6773 .setIcon(personIcon2) 6774 .build(); 6775 final Person person3 = new Person.Builder() 6776 .setName("People List Person 2") 6777 .setIcon(personIcon3) 6778 .build(); 6779 final Uri historyUri1 = Uri.parse("content://com.example/history1"); 6780 final Uri historyUri2 = Uri.parse("content://com.example/history2"); 6781 final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1, 6782 "a"); 6783 final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2, 6784 "b"); 6785 6786 Bundle extras = new Bundle(); 6787 extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents); 6788 extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString()); 6789 extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1); 6790 extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, 6791 new ArrayList<>(Arrays.asList(person2, person3))); 6792 extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, 6793 new RemoteInputHistoryItem[]{historyItem1, historyItem2}); 6794 6795 Notification n = new Notification.Builder(mContext, "a") 6796 .setContentTitle("notification with uris") 6797 .setSmallIcon(smallIcon) 6798 .setLargeIcon(largeIcon) 6799 .addExtras(extras) 6800 .build(); 6801 6802 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 6803 n.visitUris(visitor); 6804 verify(visitor, times(1)).accept(eq(audioContents)); 6805 verify(visitor, times(1)).accept(eq(backgroundImage)); 6806 verify(visitor, times(1)).accept(eq(smallIcon.getUri())); 6807 verify(visitor, times(1)).accept(eq(largeIcon.getUri())); 6808 verify(visitor, times(1)).accept(eq(personIcon1.getUri())); 6809 verify(visitor, times(1)).accept(eq(personIcon2.getUri())); 6810 verify(visitor, times(1)).accept(eq(personIcon3.getUri())); 6811 verify(visitor, times(1)).accept(eq(historyUri1)); 6812 verify(visitor, times(1)).accept(eq(historyUri2)); 6813 } 6814 6815 @Test testVisitUris_publicVersion()6816 public void testVisitUris_publicVersion() throws Exception { 6817 final Icon smallIconPublic = Icon.createWithContentUri("content://media/small/icon"); 6818 final Icon largeIconPrivate = Icon.createWithContentUri("content://media/large/icon"); 6819 6820 Notification publicVersion = new Notification.Builder(mContext, "a") 6821 .setContentTitle("notification with uris") 6822 .setSmallIcon(smallIconPublic) 6823 .build(); 6824 Notification n = new Notification.Builder(mContext, "a") 6825 .setLargeIcon(largeIconPrivate) 6826 .setPublicVersion(publicVersion) 6827 .build(); 6828 6829 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 6830 n.visitUris(visitor); 6831 verify(visitor, times(1)).accept(eq(smallIconPublic.getUri())); 6832 verify(visitor, times(1)).accept(eq(largeIconPrivate.getUri())); 6833 } 6834 6835 @Test testVisitUris_audioContentsString()6836 public void testVisitUris_audioContentsString() throws Exception { 6837 final Uri audioContents = Uri.parse("content://com.example/audio"); 6838 6839 Bundle extras = new Bundle(); 6840 extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString()); 6841 6842 Notification n = new Notification.Builder(mContext, "a") 6843 .setContentTitle("notification with uris") 6844 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6845 .addExtras(extras) 6846 .build(); 6847 6848 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 6849 n.visitUris(visitor); 6850 verify(visitor, times(1)).accept(eq(audioContents)); 6851 } 6852 6853 @Test testVisitUris_messagingStyle()6854 public void testVisitUris_messagingStyle() { 6855 final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); 6856 final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); 6857 final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); 6858 final Person person1 = new Person.Builder() 6859 .setName("Messaging Person 1") 6860 .setIcon(personIcon1) 6861 .build(); 6862 final Person person2 = new Person.Builder() 6863 .setName("Messaging Person 2") 6864 .setIcon(personIcon2) 6865 .build(); 6866 final Person person3 = new Person.Builder() 6867 .setName("Messaging Person 3") 6868 .setIcon(personIcon3) 6869 .build(); 6870 Icon shortcutIcon = Icon.createWithContentUri("content://media/shortcut"); 6871 6872 Notification.Builder builder = new Notification.Builder(mContext, "a") 6873 .setCategory(Notification.CATEGORY_MESSAGE) 6874 .setContentTitle("new message!") 6875 .setContentText("Conversation Notification") 6876 .setSmallIcon(android.R.drawable.sym_def_app_icon); 6877 Notification.MessagingStyle.Message message1 = new Notification.MessagingStyle.Message( 6878 "Marco?", System.currentTimeMillis(), person2); 6879 Notification.MessagingStyle.Message message2 = new Notification.MessagingStyle.Message( 6880 "Polo!", System.currentTimeMillis(), person3); 6881 Notification.MessagingStyle style = new Notification.MessagingStyle(person1) 6882 .addMessage(message1) 6883 .addMessage(message2) 6884 .setShortcutIcon(shortcutIcon); 6885 builder.setStyle(style); 6886 Notification n = builder.build(); 6887 6888 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 6889 n.visitUris(visitor); 6890 6891 verify(visitor, times(1)).accept(eq(shortcutIcon.getUri())); 6892 verify(visitor, times(1)).accept(eq(personIcon1.getUri())); 6893 verify(visitor, times(1)).accept(eq(personIcon2.getUri())); 6894 verify(visitor, times(1)).accept(eq(personIcon3.getUri())); 6895 } 6896 6897 @Test testVisitUris_callStyle()6898 public void testVisitUris_callStyle() { 6899 Icon personIcon = Icon.createWithContentUri("content://media/person"); 6900 Icon verificationIcon = Icon.createWithContentUri("content://media/verification"); 6901 Person callingPerson = new Person.Builder().setName("Someone") 6902 .setIcon(personIcon) 6903 .build(); 6904 PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 6905 PendingIntent.FLAG_IMMUTABLE); 6906 Notification n = new Notification.Builder(mContext, "a") 6907 .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent) 6908 .setVerificationIcon(verificationIcon)) 6909 .setContentTitle("Calling...") 6910 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6911 .build(); 6912 6913 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 6914 n.visitUris(visitor); 6915 6916 verify(visitor, times(1)).accept(eq(personIcon.getUri())); 6917 verify(visitor, times(1)).accept(eq(verificationIcon.getUri())); 6918 hangUpIntent.cancel(); 6919 } 6920 6921 @Test testVisitUris_styleExtrasWithoutStyle()6922 public void testVisitUris_styleExtrasWithoutStyle() { 6923 Notification.Builder notification = new Notification.Builder(mContext, "a") 6924 .setSmallIcon(android.R.drawable.sym_def_app_icon); 6925 6926 Bundle messagingExtras = new Bundle(); 6927 messagingExtras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, 6928 personWithIcon("content://user")); 6929 messagingExtras.putParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES, 6930 new Bundle[] { new Notification.MessagingStyle.Message("Heyhey!", 6931 System.currentTimeMillis() - 100, 6932 personWithIcon("content://historicalMessenger")).toBundle()}); 6933 messagingExtras.putParcelableArray(Notification.EXTRA_MESSAGES, 6934 new Bundle[] { new Notification.MessagingStyle.Message("Are you there?", 6935 System.currentTimeMillis(), 6936 personWithIcon("content://messenger")).toBundle()}); 6937 messagingExtras.putParcelable(Notification.EXTRA_CONVERSATION_ICON, 6938 Icon.createWithContentUri("content://conversationShortcut")); 6939 notification.addExtras(messagingExtras); 6940 6941 Bundle callExtras = new Bundle(); 6942 callExtras.putParcelable(Notification.EXTRA_CALL_PERSON, 6943 personWithIcon("content://caller")); 6944 callExtras.putParcelable(Notification.EXTRA_VERIFICATION_ICON, 6945 Icon.createWithContentUri("content://callVerification")); 6946 notification.addExtras(callExtras); 6947 6948 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 6949 notification.build().visitUris(visitor); 6950 6951 verify(visitor).accept(eq(Uri.parse("content://user"))); 6952 verify(visitor).accept(eq(Uri.parse("content://historicalMessenger"))); 6953 verify(visitor).accept(eq(Uri.parse("content://messenger"))); 6954 verify(visitor).accept(eq(Uri.parse("content://conversationShortcut"))); 6955 verify(visitor).accept(eq(Uri.parse("content://caller"))); 6956 verify(visitor).accept(eq(Uri.parse("content://callVerification"))); 6957 } 6958 personWithIcon(String iconUri)6959 private static Person personWithIcon(String iconUri) { 6960 return new Person.Builder() 6961 .setName("Mr " + iconUri) 6962 .setIcon(Icon.createWithContentUri(iconUri)) 6963 .build(); 6964 } 6965 6966 @Test testVisitUris_wearableExtender()6967 public void testVisitUris_wearableExtender() { 6968 Icon actionIcon = Icon.createWithContentUri("content://media/action"); 6969 Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction"); 6970 PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(), 6971 PendingIntent.FLAG_IMMUTABLE); 6972 Notification n = new Notification.Builder(mContext, "a") 6973 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6974 .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build()) 6975 .extend(new Notification.WearableExtender().addAction( 6976 new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build())) 6977 .build(); 6978 6979 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 6980 n.visitUris(visitor); 6981 6982 verify(visitor).accept(eq(actionIcon.getUri())); 6983 verify(visitor).accept(eq(wearActionIcon.getUri())); 6984 } 6985 6986 @Test testSetNotificationPolicy_preP_setOldFields()6987 public void testSetNotificationPolicy_preP_setOldFields() { 6988 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 6989 mService.mZenModeHelper = mZenModeHelper; 6990 NotificationManager.Policy userPolicy = 6991 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 6992 when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy); 6993 6994 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 6995 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); 6996 6997 int expected = SUPPRESSED_EFFECT_BADGE 6998 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF 6999 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS 7000 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 7001 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 7002 7003 assertEquals(expected, actual); 7004 } 7005 7006 @Test testSetNotificationPolicy_preP_setNewFields()7007 public void testSetNotificationPolicy_preP_setNewFields() { 7008 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 7009 mService.mZenModeHelper = mZenModeHelper; 7010 NotificationManager.Policy userPolicy = 7011 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 7012 when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy); 7013 7014 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 7015 SUPPRESSED_EFFECT_NOTIFICATION_LIST); 7016 7017 int expected = SUPPRESSED_EFFECT_BADGE; 7018 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 7019 7020 assertEquals(expected, actual); 7021 } 7022 7023 @Test testSetNotificationPolicy_preP_setOldNewFields()7024 public void testSetNotificationPolicy_preP_setOldNewFields() { 7025 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 7026 mService.mZenModeHelper = mZenModeHelper; 7027 NotificationManager.Policy userPolicy = 7028 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 7029 when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy); 7030 7031 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 7032 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR); 7033 7034 int expected = 7035 SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK; 7036 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 7037 7038 assertEquals(expected, actual); 7039 } 7040 7041 @Test testSetNotificationPolicy_P_setOldFields()7042 public void testSetNotificationPolicy_P_setOldFields() { 7043 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 7044 mService.mZenModeHelper = mZenModeHelper; 7045 NotificationManager.Policy userPolicy = 7046 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 7047 when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy); 7048 7049 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 7050 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); 7051 7052 int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF 7053 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT 7054 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 7055 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 7056 7057 assertEquals(expected, actual); 7058 } 7059 7060 @Test testSetNotificationPolicy_P_setNewFields()7061 public void testSetNotificationPolicy_P_setNewFields() { 7062 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 7063 mService.mZenModeHelper = mZenModeHelper; 7064 NotificationManager.Policy userPolicy = 7065 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 7066 when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy); 7067 7068 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 7069 SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT 7070 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 7071 7072 int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF 7073 | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS 7074 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 7075 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 7076 7077 assertEquals(expected, actual); 7078 } 7079 7080 @Test testSetNotificationPolicy_P_setOldNewFields()7081 public void testSetNotificationPolicy_P_setOldNewFields() { 7082 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 7083 mService.mZenModeHelper = mZenModeHelper; 7084 NotificationManager.Policy userPolicy = 7085 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 7086 when(mZenModeHelper.getNotificationPolicy()).thenReturn(userPolicy); 7087 7088 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 7089 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR); 7090 7091 int expected = SUPPRESSED_EFFECT_STATUS_BAR; 7092 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 7093 7094 assertEquals(expected, actual); 7095 7096 appPolicy = new NotificationManager.Policy(0, 0, 0, 7097 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT 7098 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 7099 7100 expected = SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT 7101 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 7102 actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 7103 7104 assertEquals(expected, actual); 7105 } 7106 7107 @Test testVisualDifference_foreground()7108 public void testVisualDifference_foreground() { 7109 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7110 .setContentTitle("foo"); 7111 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7112 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7113 NotificationRecord r1 = 7114 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7115 7116 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7117 .setFlag(FLAG_FOREGROUND_SERVICE, true) 7118 .setContentTitle("bar"); 7119 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7120 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7121 NotificationRecord r2 = 7122 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7123 7124 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 7125 } 7126 7127 @Test testVisualDifference_diffTitle()7128 public void testVisualDifference_diffTitle() { 7129 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7130 .setContentTitle("foo"); 7131 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7132 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7133 NotificationRecord r1 = 7134 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7135 7136 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7137 .setContentTitle("bar"); 7138 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7139 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7140 NotificationRecord r2 = 7141 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7142 7143 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 7144 } 7145 7146 @Test testVisualDifference_inboxStyle()7147 public void testVisualDifference_inboxStyle() { 7148 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7149 .setStyle(new Notification.InboxStyle() 7150 .addLine("line1").addLine("line2")); 7151 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7152 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7153 NotificationRecord r1 = 7154 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7155 7156 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7157 .setStyle(new Notification.InboxStyle() 7158 .addLine("line1").addLine("line2_changed")); 7159 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7160 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7161 NotificationRecord r2 = 7162 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7163 7164 assertTrue(mService.isVisuallyInterruptive(r1, r2)); // line 2 changed unnoticed 7165 7166 Notification.Builder nb3 = new Notification.Builder(mContext, "") 7167 .setStyle(new Notification.InboxStyle() 7168 .addLine("line1")); 7169 StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7170 nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7171 NotificationRecord r3 = 7172 new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class)); 7173 7174 assertTrue(mService.isVisuallyInterruptive(r1, r3)); // line 2 removed unnoticed 7175 7176 Notification.Builder nb4 = new Notification.Builder(mContext, "") 7177 .setStyle(new Notification.InboxStyle() 7178 .addLine("line1").addLine("line2").addLine("line3")); 7179 StatusBarNotification sbn4 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7180 nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7181 NotificationRecord r4 = 7182 new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class)); 7183 7184 assertTrue(mService.isVisuallyInterruptive(r1, r4)); // line 3 added unnoticed 7185 7186 Notification.Builder nb5 = new Notification.Builder(mContext, "") 7187 .setContentText("not an inbox"); 7188 StatusBarNotification sbn5 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7189 nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7190 NotificationRecord r5 = 7191 new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class)); 7192 7193 assertTrue(mService.isVisuallyInterruptive(r1, r5)); // changed Styles, went unnoticed 7194 } 7195 7196 @Test testVisualDifference_diffText()7197 public void testVisualDifference_diffText() { 7198 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7199 .setContentText("foo"); 7200 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7201 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7202 NotificationRecord r1 = 7203 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7204 7205 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7206 .setContentText("bar"); 7207 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7208 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7209 NotificationRecord r2 = 7210 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7211 7212 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 7213 } 7214 7215 @Test testVisualDifference_sameText()7216 public void testVisualDifference_sameText() { 7217 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7218 .setContentText("foo"); 7219 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7220 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7221 NotificationRecord r1 = 7222 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7223 7224 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7225 .setContentText("foo"); 7226 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7227 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7228 NotificationRecord r2 = 7229 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7230 7231 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 7232 } 7233 7234 @Test testVisualDifference_sameTextButStyled()7235 public void testVisualDifference_sameTextButStyled() { 7236 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7237 .setContentText(Html.fromHtml("<b>foo</b>")); 7238 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7239 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7240 NotificationRecord r1 = 7241 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7242 7243 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7244 .setContentText(Html.fromHtml("<b>foo</b>")); 7245 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7246 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7247 NotificationRecord r2 = 7248 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7249 7250 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 7251 } 7252 7253 @Test testVisualDifference_diffTextButStyled()7254 public void testVisualDifference_diffTextButStyled() { 7255 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7256 .setContentText(Html.fromHtml("<b>foo</b>")); 7257 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7258 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7259 NotificationRecord r1 = 7260 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7261 7262 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7263 .setContentText(Html.fromHtml("<b>bar</b>")); 7264 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7265 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7266 NotificationRecord r2 = 7267 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7268 7269 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 7270 } 7271 7272 @Test testVisualDifference_diffProgress()7273 public void testVisualDifference_diffProgress() { 7274 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7275 .setProgress(100, 90, false); 7276 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7277 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7278 NotificationRecord r1 = 7279 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7280 7281 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7282 .setProgress(100, 100, false); 7283 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7284 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7285 NotificationRecord r2 = 7286 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7287 7288 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 7289 } 7290 7291 @Test testVisualDifference_diffProgressNotDone()7292 public void testVisualDifference_diffProgressNotDone() { 7293 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7294 .setProgress(100, 90, false); 7295 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7296 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7297 NotificationRecord r1 = 7298 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7299 7300 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7301 .setProgress(100, 91, false); 7302 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7303 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7304 NotificationRecord r2 = 7305 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7306 7307 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 7308 } 7309 7310 @Test testVisualDifference_sameProgressStillDone()7311 public void testVisualDifference_sameProgressStillDone() { 7312 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7313 .setProgress(100, 100, false); 7314 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7315 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7316 NotificationRecord r1 = 7317 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7318 7319 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7320 .setProgress(100, 100, false); 7321 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7322 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7323 NotificationRecord r2 = 7324 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7325 7326 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 7327 } 7328 7329 @Test testVisualDifference_summary()7330 public void testVisualDifference_summary() { 7331 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7332 .setGroup("bananas") 7333 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 7334 .setContentText("foo"); 7335 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7336 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7337 NotificationRecord r1 = 7338 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7339 7340 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7341 .setGroup("bananas") 7342 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 7343 .setContentText("bar"); 7344 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7345 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7346 NotificationRecord r2 = 7347 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7348 7349 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 7350 } 7351 7352 @Test testVisualDifference_summaryNewNotification()7353 public void testVisualDifference_summaryNewNotification() { 7354 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7355 .setGroup("bananas") 7356 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 7357 .setContentText("bar"); 7358 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7359 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7360 NotificationRecord r2 = 7361 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7362 7363 assertFalse(mService.isVisuallyInterruptive(null, r2)); 7364 } 7365 7366 @Test testVisualDifference_sameImages()7367 public void testVisualDifference_sameImages() { 7368 Icon large = Icon.createWithResource(mContext, 1); 7369 Notification n1 = new Notification.Builder(mContext, "channel") 7370 .setSmallIcon(1).setLargeIcon(large).build(); 7371 Notification n2 = new Notification.Builder(mContext, "channel") 7372 .setSmallIcon(1).setLargeIcon(large).build(); 7373 7374 NotificationRecord r1 = notificationToRecord(n1); 7375 NotificationRecord r2 = notificationToRecord(n2); 7376 7377 assertThat(mService.isVisuallyInterruptive(r1, r2)).isFalse(); 7378 } 7379 7380 @Test testVisualDifference_differentSmallImage()7381 public void testVisualDifference_differentSmallImage() { 7382 Icon large = Icon.createWithResource(mContext, 1); 7383 Notification n1 = new Notification.Builder(mContext, "channel") 7384 .setSmallIcon(1).setLargeIcon(large).build(); 7385 Notification n2 = new Notification.Builder(mContext, "channel") 7386 .setSmallIcon(2).setLargeIcon(large).build(); 7387 7388 NotificationRecord r1 = notificationToRecord(n1); 7389 NotificationRecord r2 = notificationToRecord(n2); 7390 7391 assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue(); 7392 } 7393 7394 @Test testVisualDifference_differentLargeImage()7395 public void testVisualDifference_differentLargeImage() { 7396 Icon large1 = Icon.createWithResource(mContext, 1); 7397 Icon large2 = Icon.createWithResource(mContext, 2); 7398 Notification n1 = new Notification.Builder(mContext, "channel") 7399 .setSmallIcon(1).setLargeIcon(large1).build(); 7400 Notification n2 = new Notification.Builder(mContext, "channel") 7401 .setSmallIcon(1).setLargeIcon(large2).build(); 7402 7403 NotificationRecord r1 = notificationToRecord(n1); 7404 NotificationRecord r2 = notificationToRecord(n2); 7405 7406 assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue(); 7407 } 7408 7409 @Test 7410 @EnableFlags({android.app.Flags.FLAG_SORT_SECTION_BY_TIME}) testVisualDifference_userInitiatedJob()7411 public void testVisualDifference_userInitiatedJob() { 7412 Notification.Builder nb1 = new Notification.Builder(mContext, "") 7413 .setContentTitle("foo"); 7414 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7415 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7416 NotificationRecord r1 = 7417 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 7418 7419 Notification.Builder nb2 = new Notification.Builder(mContext, "") 7420 .setFlag(FLAG_USER_INITIATED_JOB, true) 7421 .setContentTitle("bar"); 7422 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 7423 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 7424 NotificationRecord r2 = 7425 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 7426 7427 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 7428 } 7429 notificationToRecord(Notification n)7430 private NotificationRecord notificationToRecord(Notification n) { 7431 return new NotificationRecord( 7432 mContext, 7433 new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, n, 7434 UserHandle.getUserHandleForUid(mUid), null, 0), 7435 mock(NotificationChannel.class)); 7436 } 7437 7438 @Test testHideAndUnhideNotificationsOnSuspendedPackageBroadcast()7439 public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() { 7440 // post 2 notification from this package 7441 final NotificationRecord notif1 = generateNotificationRecord( 7442 mTestNotificationChannel, 1, null, true); 7443 final NotificationRecord notif2 = generateNotificationRecord( 7444 mTestNotificationChannel, 2, null, false); 7445 mService.addNotification(notif1); 7446 mService.addNotification(notif2); 7447 7448 // on broadcast, hide the 2 notifications 7449 simulatePackageSuspendBroadcast(true, mPkg, notif1.getUid()); 7450 ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class); 7451 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 7452 assertEquals(2, captorHide.getValue().size()); 7453 7454 // on broadcast, unhide the 2 notifications 7455 simulatePackageSuspendBroadcast(false, mPkg, notif1.getUid()); 7456 ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class); 7457 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 7458 assertEquals(2, captorUnhide.getValue().size()); 7459 } 7460 7461 @Test testNoNotificationsHiddenOnSuspendedPackageBroadcast()7462 public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() { 7463 // post 2 notification from this package 7464 final NotificationRecord notif1 = generateNotificationRecord( 7465 mTestNotificationChannel, 1, null, true); 7466 final NotificationRecord notif2 = generateNotificationRecord( 7467 mTestNotificationChannel, 2, null, false); 7468 mService.addNotification(notif1); 7469 mService.addNotification(notif2); 7470 7471 // on broadcast, nothing is hidden since no notifications are of package "test_package" 7472 simulatePackageSuspendBroadcast(true, "test_package", notif1.getUid()); 7473 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 7474 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 7475 assertEquals(0, captor.getValue().size()); 7476 } 7477 7478 @Test testNotificationFromDifferentUserHidden()7479 public void testNotificationFromDifferentUserHidden() { 7480 // post 2 notification from this package 7481 final NotificationRecord notif1 = generateNotificationRecord( 7482 mTestNotificationChannel, 1, null, true); 7483 final NotificationRecord notif2 = generateNotificationRecord( 7484 mTestNotificationChannel, 2, null, false); 7485 mService.addNotification(notif1); 7486 mService.addNotification(notif2); 7487 7488 // on broadcast, nothing is hidden since no notifications are of user 10 with package PKG 7489 simulatePackageSuspendBroadcast(true, mPkg, 10); 7490 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 7491 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 7492 assertEquals(0, captor.getValue().size()); 7493 } 7494 7495 @Test testHideAndUnhideNotificationsOnDistractingPackageBroadcast()7496 public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() { 7497 // Post 2 notifications from 2 packages 7498 NotificationRecord pkgA = new NotificationRecord(mContext, 7499 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 7500 mService.addNotification(pkgA); 7501 NotificationRecord pkgB = new NotificationRecord(mContext, 7502 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 7503 mService.addNotification(pkgB); 7504 7505 // on broadcast, hide one of the packages 7506 simulatePackageDistractionBroadcast( 7507 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"}, 7508 new int[] {1000}); 7509 ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class); 7510 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 7511 assertEquals(1, captorHide.getValue().size()); 7512 assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName()); 7513 7514 // on broadcast, unhide the package 7515 simulatePackageDistractionBroadcast( 7516 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"}, 7517 new int[] {1000}); 7518 ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class); 7519 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 7520 assertEquals(1, captorUnhide.getValue().size()); 7521 assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName()); 7522 } 7523 7524 @Test testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg()7525 public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() { 7526 // Post 2 notifications from 2 packages 7527 NotificationRecord pkgA = new NotificationRecord(mContext, 7528 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 7529 mService.addNotification(pkgA); 7530 NotificationRecord pkgB = new NotificationRecord(mContext, 7531 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 7532 mService.addNotification(pkgB); 7533 7534 // on broadcast, hide one of the packages 7535 simulatePackageDistractionBroadcast( 7536 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"}, 7537 new int[] {1000, 1001}); 7538 ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class); 7539 7540 // should be called only once. 7541 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 7542 assertEquals(2, captorHide.getValue().size()); 7543 assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName()); 7544 assertEquals("b", captorHide.getValue().get(1).getSbn().getPackageName()); 7545 7546 // on broadcast, unhide the package 7547 simulatePackageDistractionBroadcast( 7548 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"}, 7549 new int[] {1000, 1001}); 7550 ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class); 7551 7552 // should be called only once. 7553 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 7554 assertEquals(2, captorUnhide.getValue().size()); 7555 assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName()); 7556 assertEquals("b", captorUnhide.getValue().get(1).getSbn().getPackageName()); 7557 } 7558 7559 @Test testNoNotificationsHiddenOnDistractingPackageBroadcast()7560 public void testNoNotificationsHiddenOnDistractingPackageBroadcast() { 7561 // post notification from this package 7562 final NotificationRecord notif1 = generateNotificationRecord( 7563 mTestNotificationChannel, 1, null, true); 7564 mService.addNotification(notif1); 7565 7566 // on broadcast, nothing is hidden since no notifications are of package "test_package" 7567 simulatePackageDistractionBroadcast( 7568 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"}, 7569 new int[]{notif1.getUid()}); 7570 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 7571 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 7572 assertEquals(0, captor.getValue().size()); 7573 } 7574 7575 @Test testCanUseManagedServicesNullPkg()7576 public void testCanUseManagedServicesNullPkg() { 7577 assertEquals(true, mService.canUseManagedServices(null, 0, null)); 7578 } 7579 7580 7581 @Test testCanUseManagedServicesNoValidPkg()7582 public void testCanUseManagedServicesNoValidPkg() { 7583 assertEquals(true, mService.canUseManagedServices("d", 0, null)); 7584 } 7585 7586 @Test testCanUseManagedServices_hasPermission()7587 public void testCanUseManagedServices_hasPermission() throws Exception { 7588 when(mPackageManager.checkPermission("perm", "pkg", 0)) 7589 .thenReturn(PackageManager.PERMISSION_GRANTED); 7590 7591 assertEquals(true, mService.canUseManagedServices("pkg", 0, "perm")); 7592 } 7593 7594 @Test testCanUseManagedServices_noPermission()7595 public void testCanUseManagedServices_noPermission() throws Exception { 7596 when(mPackageManager.checkPermission("perm", "pkg", 0)) 7597 .thenReturn(PackageManager.PERMISSION_DENIED); 7598 7599 assertEquals(false, mService.canUseManagedServices("pkg", 0, "perm")); 7600 } 7601 7602 @Test testCanUseManagedServices_permDoesNotMatter()7603 public void testCanUseManagedServices_permDoesNotMatter() { 7604 assertEquals(true, mService.canUseManagedServices("pkg", 0, null)); 7605 } 7606 7607 @Test testOnNotificationVisibilityChanged_triggersInterruptionUsageStat()7608 public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() { 7609 final NotificationRecord r = generateNotificationRecord( 7610 mTestNotificationChannel, 1, null, true); 7611 r.setTextChanged(true); 7612 mService.addNotification(r); 7613 7614 mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[] 7615 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}, 7616 new NotificationVisibility[]{}); 7617 7618 verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt()); 7619 } 7620 7621 @Test testOnNotificationVisibilityChanged_triggersVisibilityLog()7622 public void testOnNotificationVisibilityChanged_triggersVisibilityLog() { 7623 final NotificationRecord r = generateNotificationRecord( 7624 mTestNotificationChannel, 1, null, true); 7625 r.setTextChanged(true); 7626 r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7627 mService.addNotification(r); 7628 7629 mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[] 7630 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}, 7631 new NotificationVisibility[]{}); 7632 7633 assertEquals(1, mNotificationRecordLogger.numCalls()); 7634 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN, 7635 mNotificationRecordLogger.event(0)); 7636 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 7637 7638 mService.mNotificationDelegate.onNotificationVisibilityChanged( 7639 new NotificationVisibility[]{}, 7640 new NotificationVisibility[] 7641 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)} 7642 ); 7643 7644 assertEquals(2, mNotificationRecordLogger.numCalls()); 7645 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE, 7646 mNotificationRecordLogger.event(1)); 7647 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 7648 } 7649 7650 @Test testSetNotificationsShownFromListener_triggersInterruptionUsageStat()7651 public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat() 7652 throws RemoteException { 7653 final NotificationRecord r = generateNotificationRecord( 7654 mTestNotificationChannel, 1, null, true); 7655 r.setTextChanged(true); 7656 mService.addNotification(r); 7657 7658 mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()}); 7659 7660 verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt()); 7661 } 7662 7663 @Test testSetNotificationsShownFromListener_protectsCrossUserInformation()7664 public void testSetNotificationsShownFromListener_protectsCrossUserInformation() 7665 throws RemoteException { 7666 Notification.Builder nb = new Notification.Builder( 7667 mContext, mTestNotificationChannel.getId()) 7668 .setContentTitle("foo") 7669 .setSmallIcon(android.R.drawable.sym_def_app_icon); 7670 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 7671 "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, 7672 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), 7673 null, 0); 7674 final NotificationRecord r = 7675 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7676 r.setTextChanged(true); 7677 mService.addNotification(r); 7678 7679 // no security exception! 7680 mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()}); 7681 7682 verify(mAppUsageStats, never()).reportInterruptiveNotification( 7683 anyString(), anyString(), anyInt()); 7684 } 7685 7686 @Test testCancelNotificationsFromListener_protectsCrossUserInformation()7687 public void testCancelNotificationsFromListener_protectsCrossUserInformation() 7688 throws RemoteException { 7689 Notification.Builder nb = new Notification.Builder( 7690 mContext, mTestNotificationChannel.getId()) 7691 .setContentTitle("foo") 7692 .setSmallIcon(android.R.drawable.sym_def_app_icon); 7693 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 7694 "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, 7695 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), 7696 null, 0); 7697 final NotificationRecord r = 7698 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7699 r.setTextChanged(true); 7700 mService.addNotification(r); 7701 7702 // no security exception! 7703 mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()}); 7704 7705 waitForIdle(); 7706 assertEquals(1, mService.getNotificationRecordCount()); 7707 } 7708 7709 @Test testMaybeRecordInterruptionLocked_doesNotRecordTwice()7710 public void testMaybeRecordInterruptionLocked_doesNotRecordTwice() 7711 throws RemoteException { 7712 final NotificationRecord r = generateNotificationRecord( 7713 mTestNotificationChannel, 1, null, true); 7714 r.setInterruptive(true); 7715 mService.addNotification(r); 7716 7717 mService.maybeRecordInterruptionLocked(r); 7718 mService.maybeRecordInterruptionLocked(r); 7719 7720 verify(mAppUsageStats, times(1)).reportInterruptiveNotification( 7721 anyString(), anyString(), anyInt()); 7722 verify(mHistoryManager, times(1)).addNotification(any()); 7723 } 7724 7725 @Test testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()7726 public void testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory() 7727 throws RemoteException { 7728 final NotificationRecord r = generateNotificationRecord( 7729 mTestNotificationChannel, 1, null, true); 7730 r.setInterruptive(true); 7731 r.getSbn().getNotification().setSmallIcon(null); 7732 mService.addNotification(r); 7733 7734 mService.maybeRecordInterruptionLocked(r); 7735 7736 verify(mAppUsageStats, times(1)).reportInterruptiveNotification( 7737 anyString(), anyString(), anyInt()); 7738 verify(mHistoryManager, never()).addNotification(any()); 7739 } 7740 7741 @Test testBubble()7742 public void testBubble() throws Exception { 7743 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE); 7744 assertFalse(mBinderService.areBubblesAllowed(mPkg)); 7745 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 7746 BUBBLE_PREFERENCE_NONE); 7747 } 7748 7749 @Test testUserApprovedBubblesForPackageSelected()7750 public void testUserApprovedBubblesForPackageSelected() throws Exception { 7751 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_SELECTED); 7752 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 7753 BUBBLE_PREFERENCE_SELECTED); 7754 } 7755 7756 @Test testUserApprovedBubblesForPackageAll()7757 public void testUserApprovedBubblesForPackageAll() throws Exception { 7758 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_ALL); 7759 assertTrue(mBinderService.areBubblesAllowed(mPkg)); 7760 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 7761 BUBBLE_PREFERENCE_ALL); 7762 } 7763 7764 @Test testUserRejectsBubblesForPackage()7765 public void testUserRejectsBubblesForPackage() throws Exception { 7766 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE); 7767 assertFalse(mBinderService.areBubblesAllowed(mPkg)); 7768 } 7769 7770 @Test testAreBubblesEnabled()7771 public void testAreBubblesEnabled() throws Exception { 7772 Settings.Secure.putInt(mContext.getContentResolver(), 7773 Settings.Secure.NOTIFICATION_BUBBLES, 1); 7774 mService.mPreferencesHelper.updateBubblesEnabled(); 7775 assertTrue(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid))); 7776 } 7777 7778 @Test testAreBubblesEnabled_false()7779 public void testAreBubblesEnabled_false() throws Exception { 7780 Settings.Secure.putInt(mContext.getContentResolver(), 7781 Settings.Secure.NOTIFICATION_BUBBLES, 0); 7782 mService.mPreferencesHelper.updateBubblesEnabled(); 7783 assertFalse(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid))); 7784 } 7785 7786 @Test testAreBubblesEnabled_exception()7787 public void testAreBubblesEnabled_exception() throws Exception { 7788 try { 7789 assertTrue(mBinderService.areBubblesEnabled( 7790 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE))); 7791 fail("Cannot call cross user without permission"); 7792 } catch (SecurityException e) { 7793 // pass 7794 } 7795 // cross user, with permission, no problem 7796 enableInteractAcrossUsers(); 7797 assertTrue(mBinderService.areBubblesEnabled( 7798 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE))); 7799 } 7800 7801 @Test testIsCallerInstantApp_primaryUser()7802 public void testIsCallerInstantApp_primaryUser() throws Exception { 7803 ApplicationInfo info = new ApplicationInfo(); 7804 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 7805 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 7806 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 7807 7808 assertTrue(mService.isCallerInstantApp(45770, 0)); 7809 7810 info.privateFlags = 0; 7811 assertFalse(mService.isCallerInstantApp(575370, 0)); 7812 } 7813 7814 @Test testIsCallerInstantApp_secondaryUser()7815 public void testIsCallerInstantApp_secondaryUser() throws Exception { 7816 ApplicationInfo info = new ApplicationInfo(); 7817 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 7818 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info); 7819 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null); 7820 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 7821 7822 assertTrue(mService.isCallerInstantApp(68638450, 10)); 7823 } 7824 7825 @Test testIsCallerInstantApp_userAllNotification()7826 public void testIsCallerInstantApp_userAllNotification() throws Exception { 7827 ApplicationInfo info = new ApplicationInfo(); 7828 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 7829 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(USER_SYSTEM))) 7830 .thenReturn(info); 7831 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 7832 7833 assertTrue(mService.isCallerInstantApp(45770, UserHandle.USER_ALL)); 7834 7835 info.privateFlags = 0; 7836 assertFalse(mService.isCallerInstantApp(575370, UserHandle.USER_ALL )); 7837 } 7838 7839 @Test testResolveNotificationUid_sameApp_nonSystemUser()7840 public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception { 7841 ApplicationInfo info = new ApplicationInfo(); 7842 info.uid = Binder.getCallingUid(); 7843 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info); 7844 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null); 7845 7846 int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10); 7847 7848 assertEquals(info.uid, actualUid); 7849 } 7850 7851 @Test testResolveNotificationUid_sameApp()7852 public void testResolveNotificationUid_sameApp() throws Exception { 7853 ApplicationInfo info = new ApplicationInfo(); 7854 info.uid = Binder.getCallingUid(); 7855 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 7856 7857 int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0); 7858 7859 assertEquals(info.uid, actualUid); 7860 } 7861 7862 @Test testResolveNotificationUid_sameAppDiffPackage()7863 public void testResolveNotificationUid_sameAppDiffPackage() throws Exception { 7864 ApplicationInfo info = new ApplicationInfo(); 7865 info.uid = Binder.getCallingUid(); 7866 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 7867 7868 int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0); 7869 7870 assertEquals(info.uid, actualUid); 7871 } 7872 7873 @Test testResolveNotificationUid_sameAppWrongUid()7874 public void testResolveNotificationUid_sameAppWrongUid() throws Exception { 7875 ApplicationInfo info = new ApplicationInfo(); 7876 info.uid = 1356347; 7877 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(info); 7878 7879 try { 7880 mService.resolveNotificationUid("caller", "caller", 9, 0); 7881 fail("Incorrect uid didn't throw security exception"); 7882 } catch (SecurityException e) { 7883 // yay 7884 } 7885 } 7886 7887 @Test testResolveNotificationUid_delegateAllowed()7888 public void testResolveNotificationUid_delegateAllowed() throws Exception { 7889 int expectedUid = 123; 7890 7891 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid); 7892 mService.setPreferencesHelper(mPreferencesHelper); 7893 when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt())) 7894 .thenReturn(true); 7895 7896 assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0)); 7897 } 7898 7899 @Test testResolveNotificationUid_androidAllowed()7900 public void testResolveNotificationUid_androidAllowed() throws Exception { 7901 int expectedUid = 123; 7902 7903 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid); 7904 // no delegate 7905 7906 assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0)); 7907 } 7908 7909 @Test testPostFromAndroidForNonExistentPackage()7910 public void testPostFromAndroidForNonExistentPackage() throws Exception { 7911 final String notReal = "NOT REAL"; 7912 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())).thenThrow( 7913 PackageManager.NameNotFoundException.class); 7914 ApplicationInfo ai = new ApplicationInfo(); 7915 ai.uid = -1; 7916 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai); 7917 7918 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 7919 try { 7920 mInternalService.enqueueNotification(notReal, "android", 0, 0, 7921 "testPostFromAndroidForNonExistentPackage", 7922 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 7923 fail("can't post notifications for nonexistent packages, even if you exist"); 7924 } catch (SecurityException e) { 7925 // yay 7926 } 7927 } 7928 7929 @Test testCancelFromAndroidForNonExistentPackage()7930 public void testCancelFromAndroidForNonExistentPackage() throws Exception { 7931 final String notReal = "NOT REAL"; 7932 when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( 7933 PackageManager.NameNotFoundException.class); 7934 ApplicationInfo ai = new ApplicationInfo(); 7935 ai.uid = -1; 7936 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai); 7937 7938 // unlike the post case, ignore instead of throwing 7939 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 7940 7941 mInternalService.cancelNotification(notReal, "android", 0, 0, "tag", 7942 sbn.getId(), sbn.getUserId()); 7943 } 7944 7945 @Test testResolveNotificationUid_delegateNotAllowed()7946 public void testResolveNotificationUid_delegateNotAllowed() throws Exception { 7947 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123); 7948 // no delegate 7949 7950 try { 7951 mService.resolveNotificationUid("caller", "target", 9, 0); 7952 fail("Incorrect uid didn't throw security exception"); 7953 } catch (SecurityException e) { 7954 // yay 7955 } 7956 } 7957 7958 @Test testRemoveForegroundServiceFlagFromNotification_enqueued()7959 public void testRemoveForegroundServiceFlagFromNotification_enqueued() { 7960 when(mAmi.applyForegroundServiceNotification( 7961 any(), anyString(), anyInt(), anyString(), anyInt())) 7962 .thenReturn(SHOW_IMMEDIATELY); 7963 Notification n = new Notification.Builder(mContext, "").build(); 7964 n.flags |= FLAG_FOREGROUND_SERVICE; 7965 7966 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 7967 n, UserHandle.getUserHandleForUid(mUid), null, 0); 7968 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7969 7970 mService.addEnqueuedNotification(r); 7971 7972 mInternalService.removeForegroundServiceFlagFromNotification( 7973 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 7974 7975 waitForIdle(); 7976 7977 verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); 7978 } 7979 7980 @Test testRemoveForegroundServiceFlagFromNotification_posted()7981 public void testRemoveForegroundServiceFlagFromNotification_posted() { 7982 when(mAmi.applyForegroundServiceNotification( 7983 any(), anyString(), anyInt(), anyString(), anyInt())) 7984 .thenReturn(SHOW_IMMEDIATELY); 7985 Notification n = new Notification.Builder(mContext, "").build(); 7986 n.flags |= FLAG_FOREGROUND_SERVICE; 7987 7988 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 7989 n, UserHandle.getUserHandleForUid(mUid), null, 0); 7990 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7991 7992 mService.addNotification(r); 7993 7994 mInternalService.removeForegroundServiceFlagFromNotification( 7995 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 7996 7997 waitForIdle(); 7998 7999 ArgumentCaptor<NotificationRecord> captor = 8000 ArgumentCaptor.forClass(NotificationRecord.class); 8001 verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); 8002 8003 assertEquals(0, captor.getValue().getNotification().flags); 8004 } 8005 8006 @Test testCannotRemoveForegroundFlagWhenOverLimit_enqueued()8007 public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() { 8008 when(mAmi.applyForegroundServiceNotification( 8009 any(), anyString(), anyInt(), anyString(), anyInt())) 8010 .thenReturn(SHOW_IMMEDIATELY); 8011 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 8012 Notification n = new Notification.Builder(mContext, "").build(); 8013 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 8014 n, UserHandle.getUserHandleForUid(mUid), null, 0); 8015 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8016 mService.addEnqueuedNotification(r); 8017 } 8018 Notification n = new Notification.Builder(mContext, "").build(); 8019 n.flags |= FLAG_FOREGROUND_SERVICE; 8020 8021 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8022 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 8023 n, UserHandle.getUserHandleForUid(mUid), null, 0); 8024 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8025 8026 mService.addEnqueuedNotification(r); 8027 8028 mInternalService.removeForegroundServiceFlagFromNotification( 8029 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 8030 8031 waitForIdle(); 8032 8033 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 8034 mService.getNotificationRecordCount()); 8035 } 8036 8037 @Test testCannotRemoveForegroundFlagWhenOverLimit_posted()8038 public void testCannotRemoveForegroundFlagWhenOverLimit_posted() { 8039 when(mAmi.applyForegroundServiceNotification( 8040 any(), anyString(), anyInt(), anyString(), anyInt())) 8041 .thenReturn(SHOW_IMMEDIATELY); 8042 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 8043 Notification n = new Notification.Builder(mContext, "").build(); 8044 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 8045 n, UserHandle.getUserHandleForUid(mUid), null, 0); 8046 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8047 mService.addNotification(r); 8048 } 8049 Notification n = new Notification.Builder(mContext, "").build(); 8050 n.flags |= FLAG_FOREGROUND_SERVICE; 8051 8052 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8053 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 8054 n, UserHandle.getUserHandleForUid(mUid), null, 0); 8055 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8056 8057 mService.addNotification(r); 8058 8059 mInternalService.removeForegroundServiceFlagFromNotification( 8060 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 8061 8062 waitForIdle(); 8063 8064 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 8065 mService.getNotificationRecordCount()); 8066 } 8067 8068 @Test testAllowForegroundCustomToasts()8069 public void testAllowForegroundCustomToasts() throws Exception { 8070 final String testPackage = "testPackageName"; 8071 assertEquals(0, mService.mToastQueue.size()); 8072 mService.isSystemUid = false; 8073 mService.isSystemAppId = false; 8074 setToastRateIsWithinQuota(true); 8075 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8076 8077 // package is not suspended 8078 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8079 .thenReturn(false); 8080 8081 // notifications from this package are blocked by the user 8082 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 8083 8084 setAppInForegroundForToasts(mUid, true); 8085 8086 // enqueue toast -> toast should still enqueue 8087 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 8088 assertEquals(1, mService.mToastQueue.size()); 8089 assertThat(wasEnqueued).isTrue(); 8090 } 8091 8092 @Test testDisallowBackgroundCustomToasts()8093 public void testDisallowBackgroundCustomToasts() throws Exception { 8094 final String testPackage = "testPackageName"; 8095 assertEquals(0, mService.mToastQueue.size()); 8096 mService.isSystemUid = false; 8097 mService.isSystemAppId = false; 8098 setToastRateIsWithinQuota(true); 8099 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8100 8101 // package is not suspended 8102 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8103 .thenReturn(false); 8104 8105 setAppInForegroundForToasts(mUid, false); 8106 8107 // enqueue toast -> no toasts enqueued 8108 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 8109 assertEquals(0, mService.mToastQueue.size()); 8110 assertThat(wasEnqueued).isFalse(); 8111 } 8112 8113 @Test testDontCallShowToastAgainOnTheSameCustomToast()8114 public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception { 8115 final String testPackage = "testPackageName"; 8116 assertEquals(0, mService.mToastQueue.size()); 8117 mService.isSystemUid = false; 8118 mService.isSystemAppId = false; 8119 setToastRateIsWithinQuota(true); 8120 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8121 8122 // package is not suspended 8123 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8124 .thenReturn(false); 8125 8126 setAppInForegroundForToasts(mUid, true); 8127 8128 Binder token = new Binder(); 8129 ITransientNotification callback = mock(ITransientNotification.class); 8130 INotificationManager nmService = (INotificationManager) mService.mService; 8131 8132 // first time trying to show the toast, showToast gets called 8133 enqueueToast(nmService, testPackage, token, callback); 8134 verify(callback, times(1)).show(any()); 8135 8136 // second time trying to show the same toast, showToast isn't called again (total number of 8137 // invocations stays at one) 8138 enqueueToast(nmService, testPackage, token, callback); 8139 verify(callback, times(1)).show(any()); 8140 } 8141 8142 @Test testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()8143 public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground() 8144 throws Exception { 8145 final String testPackage = "testPackageName"; 8146 assertEquals(0, mService.mToastQueue.size()); 8147 mService.isSystemUid = false; 8148 mService.isSystemAppId = false; 8149 setToastRateIsWithinQuota(false); // rate limit reached 8150 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8151 8152 // package is not suspended 8153 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8154 .thenReturn(false); 8155 8156 setAppInForegroundForToasts(mUid, true); 8157 8158 Binder token = new Binder(); 8159 ITransientNotification callback = mock(ITransientNotification.class); 8160 INotificationManager nmService = (INotificationManager) mService.mService; 8161 8162 enqueueToast(nmService, testPackage, token, callback); 8163 verify(callback, times(1)).show(any()); 8164 } 8165 8166 @Test testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()8167 public void testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground() 8168 throws Exception { 8169 final String testPackage = "testPackageName"; 8170 assertEquals(0, mService.mToastQueue.size()); 8171 mService.isSystemUid = false; 8172 mService.isSystemAppId = false; 8173 setToastRateIsWithinQuota(true); 8174 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8175 8176 // package is not suspended 8177 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8178 .thenReturn(false); 8179 8180 setAppInForegroundForToasts(mUid, true); 8181 8182 Binder token1 = new Binder(); 8183 Binder token2 = new Binder(); 8184 ITransientNotification callback1 = mock(ITransientNotification.class); 8185 ITransientNotification callback2 = mock(ITransientNotification.class); 8186 INotificationManager nmService = (INotificationManager) mService.mService; 8187 8188 enqueueToast(nmService, testPackage, token1, callback1); 8189 enqueueToast(nmService, testPackage, token2, callback2); 8190 8191 assertEquals(2, mService.mToastQueue.size()); // Both toasts enqueued. 8192 verify(callback1, times(1)).show(any()); // First toast shown. 8193 8194 setAppInForegroundForToasts(mUid, false); 8195 8196 mService.cancelToastLocked(0); // Remove the first toast, and show next. 8197 8198 assertEquals(0, mService.mToastQueue.size()); // Both toasts processed. 8199 verify(callback2, never()).show(any()); // Second toast was never shown. 8200 } 8201 8202 @Test testAllowForegroundTextToasts()8203 public void testAllowForegroundTextToasts() throws Exception { 8204 final String testPackage = "testPackageName"; 8205 assertEquals(0, mService.mToastQueue.size()); 8206 mService.isSystemUid = false; 8207 mService.isSystemAppId = false; 8208 setToastRateIsWithinQuota(true); 8209 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8210 8211 // package is not suspended 8212 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8213 .thenReturn(false); 8214 8215 setAppInForegroundForToasts(mUid, true); 8216 8217 // enqueue toast -> toast should still enqueue 8218 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 8219 assertEquals(1, mService.mToastQueue.size()); 8220 assertThat(wasEnqueued).isTrue(); 8221 } 8222 8223 @Test testAllowBackgroundTextToasts()8224 public void testAllowBackgroundTextToasts() throws Exception { 8225 final String testPackage = "testPackageName"; 8226 assertEquals(0, mService.mToastQueue.size()); 8227 mService.isSystemUid = false; 8228 mService.isSystemAppId = false; 8229 setToastRateIsWithinQuota(true); 8230 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8231 8232 // package is not suspended 8233 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8234 .thenReturn(false); 8235 8236 setAppInForegroundForToasts(mUid, false); 8237 8238 // enqueue toast -> toast should still enqueue 8239 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 8240 assertEquals(1, mService.mToastQueue.size()); 8241 assertThat(wasEnqueued).isTrue(); 8242 } 8243 8244 @Test testDontCallShowToastAgainOnTheSameTextToast()8245 public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception { 8246 final String testPackage = "testPackageName"; 8247 assertEquals(0, mService.mToastQueue.size()); 8248 mService.isSystemUid = false; 8249 mService.isSystemAppId = false; 8250 setToastRateIsWithinQuota(true); 8251 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8252 8253 // package is not suspended 8254 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8255 .thenReturn(false); 8256 8257 setAppInForegroundForToasts(mUid, true); 8258 8259 Binder token = new Binder(); 8260 INotificationManager nmService = (INotificationManager) mService.mService; 8261 8262 // first time trying to show the toast, showToast gets called 8263 enqueueTextToast(testPackage, "Text"); 8264 verify(mStatusBar, times(1)) 8265 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 8266 8267 // second time trying to show the same toast, showToast isn't called again (total number of 8268 // invocations stays at one) 8269 enqueueTextToast(testPackage, "Text"); 8270 verify(mStatusBar, times(1)) 8271 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 8272 } 8273 8274 @Test testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()8275 public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground() 8276 throws Exception { 8277 final String testPackage = "testPackageName"; 8278 assertEquals(0, mService.mToastQueue.size()); 8279 mService.isSystemUid = false; 8280 mService.isSystemAppId = false; 8281 setToastRateIsWithinQuota(false); // rate limit reached 8282 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8283 setAppInForegroundForToasts(mUid, false); 8284 8285 // package is not suspended 8286 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8287 .thenReturn(false); 8288 8289 Binder token = new Binder(); 8290 INotificationManager nmService = (INotificationManager) mService.mService; 8291 8292 enqueueTextToast(testPackage, "Text"); 8293 verify(mStatusBar, times(0)) 8294 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 8295 } 8296 8297 @Test testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()8298 public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground() 8299 throws Exception { 8300 final String testPackage = "testPackageName"; 8301 assertEquals(0, mService.mToastQueue.size()); 8302 mService.isSystemUid = false; 8303 mService.isSystemAppId = false; 8304 setToastRateIsWithinQuota(false); // rate limit reached 8305 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8306 setAppInForegroundForToasts(mUid, true); 8307 8308 // package is not suspended 8309 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8310 .thenReturn(false); 8311 8312 Binder token = new Binder(); 8313 INotificationManager nmService = (INotificationManager) mService.mService; 8314 8315 enqueueTextToast(testPackage, "Text"); 8316 verify(mStatusBar, times(1)) 8317 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 8318 } 8319 8320 @Test testTextToastRateLimiterAllowsLimitAvoidanceWithPermission()8321 public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception { 8322 final String testPackage = "testPackageName"; 8323 assertEquals(0, mService.mToastQueue.size()); 8324 mService.isSystemUid = false; 8325 mService.isSystemAppId = false; 8326 setToastRateIsWithinQuota(false); // rate limit reached 8327 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true); 8328 setAppInForegroundForToasts(mUid, false); 8329 8330 // package is not suspended 8331 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8332 .thenReturn(false); 8333 8334 Binder token = new Binder(); 8335 INotificationManager nmService = (INotificationManager) mService.mService; 8336 8337 enqueueTextToast(testPackage, "Text"); 8338 verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 8339 anyInt()); 8340 } 8341 8342 @Test testRateLimitedToasts_windowsRemoved()8343 public void testRateLimitedToasts_windowsRemoved() throws Exception { 8344 final String testPackage = "testPackageName"; 8345 assertEquals(0, mService.mToastQueue.size()); 8346 mService.isSystemUid = false; 8347 mService.isSystemAppId = false; 8348 setToastRateIsWithinQuota(false); // rate limit reached 8349 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8350 setAppInForegroundForToasts(mUid, false); 8351 8352 // package is not suspended 8353 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8354 .thenReturn(false); 8355 8356 Binder token = new Binder(); 8357 INotificationManager nmService = (INotificationManager) mService.mService; 8358 8359 enqueueTextToast(testPackage, "Text"); 8360 8361 // window token was added when enqueued 8362 ArgumentCaptor<Binder> binderCaptor = 8363 ArgumentCaptor.forClass(Binder.class); 8364 verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(), 8365 eq(TYPE_TOAST), anyInt(), eq(null)); 8366 8367 // but never shown 8368 verify(mStatusBar, times(0)) 8369 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 8370 8371 // and removed when rate limited 8372 verify(mWindowManagerInternal) 8373 .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt()); 8374 } 8375 8376 @Test backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast()8377 public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws 8378 Exception { 8379 final String testPackage = "testPackageName"; 8380 assertEquals(0, mService.mToastQueue.size()); 8381 mService.isSystemUid = true; 8382 setToastRateIsWithinQuota(true); 8383 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8384 8385 // package is not suspended 8386 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8387 .thenReturn(false); 8388 8389 // notifications from this package are blocked by the user 8390 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 8391 8392 setAppInForegroundForToasts(mUid, false); 8393 8394 // enqueue toast -> toast should still enqueue 8395 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 8396 assertEquals(1, mService.mToastQueue.size()); 8397 assertThat(wasEnqueued).isTrue(); 8398 verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any()); 8399 } 8400 8401 @Test foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast()8402 public void foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws 8403 Exception { 8404 final String testPackage = "testPackageName"; 8405 assertEquals(0, mService.mToastQueue.size()); 8406 mService.isSystemUid = false; 8407 mService.isSystemAppId = false; 8408 setToastRateIsWithinQuota(true); 8409 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8410 8411 // package is not suspended 8412 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8413 .thenReturn(false); 8414 8415 setAppInForegroundForToasts(mUid, true); 8416 8417 // enqueue toast -> toast should still enqueue 8418 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 8419 assertEquals(1, mService.mToastQueue.size()); 8420 assertThat(wasEnqueued).isTrue(); 8421 verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); 8422 } 8423 8424 @Test backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast()8425 public void backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws 8426 Exception { 8427 final String testPackage = "testPackageName"; 8428 assertEquals(0, mService.mToastQueue.size()); 8429 mService.isSystemUid = false; 8430 mService.isSystemAppId = false; 8431 setToastRateIsWithinQuota(true); 8432 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8433 8434 // package is not suspended 8435 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8436 .thenReturn(false); 8437 8438 setAppInForegroundForToasts(mUid, false); 8439 8440 // enqueue toast -> toast should still enqueue 8441 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 8442 assertEquals(1, mService.mToastQueue.size()); 8443 assertThat(wasEnqueued).isTrue(); 8444 verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); 8445 } 8446 8447 @Test testTextToastsCallStatusBar()8448 public void testTextToastsCallStatusBar() throws Exception { 8449 allowTestPackageToToast(); 8450 8451 // enqueue toast -> no toasts enqueued 8452 boolean wasEnqueued = enqueueTextToast(TEST_PACKAGE, "Text"); 8453 assertThat(wasEnqueued).isTrue(); 8454 8455 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 8456 } 8457 8458 @Test testTextToastsCallStatusBar_nonUiContext_defaultDisplay()8459 public void testTextToastsCallStatusBar_nonUiContext_defaultDisplay() 8460 throws Exception { 8461 allowTestPackageToToast(); 8462 8463 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); 8464 8465 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 8466 } 8467 8468 @Test testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()8469 public void testTextToastsCallStatusBar_nonUiContext_secondaryDisplay() 8470 throws Exception { 8471 allowTestPackageToToast(); 8472 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 8473 8474 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); 8475 8476 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 8477 } 8478 8479 @Test testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()8480 public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay() 8481 throws Exception { 8482 mockIsVisibleBackgroundUsersSupported(true); 8483 mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); 8484 allowTestPackageToToast(); 8485 8486 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, DEFAULT_DISPLAY); 8487 8488 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 8489 8490 } 8491 8492 @Test testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()8493 public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay() 8494 throws Exception { 8495 mockIsVisibleBackgroundUsersSupported(true); 8496 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 8497 mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used 8498 allowTestPackageToToast(); 8499 8500 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, SECONDARY_DISPLAY_ID); 8501 8502 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 8503 } 8504 8505 @Test testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()8506 public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay() 8507 throws Exception { 8508 mockIsVisibleBackgroundUsersSupported(true); 8509 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 8510 mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); 8511 allowTestPackageToToast(); 8512 8513 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); 8514 8515 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 8516 } 8517 8518 @Test testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()8519 public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay() 8520 throws Exception { 8521 mockIsVisibleBackgroundUsersSupported(true); 8522 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 8523 mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used 8524 allowTestPackageToToast(); 8525 8526 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); 8527 8528 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 8529 } 8530 8531 @Test testTextToastsCallStatusBar_userNotVisibleOnDisplay()8532 public void testTextToastsCallStatusBar_userNotVisibleOnDisplay() throws Exception { 8533 final String testPackage = "testPackageName"; 8534 assertEquals(0, mService.mToastQueue.size()); 8535 mService.isSystemUid = false; 8536 mService.isSystemAppId = false; 8537 setToastRateIsWithinQuota(true); 8538 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8539 mockIsUserVisible(DEFAULT_DISPLAY, false); 8540 8541 // package is not suspended 8542 when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) 8543 .thenReturn(false); 8544 8545 // enqueue toast -> no toasts enqueued 8546 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 8547 verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 8548 anyInt()); 8549 assertEquals(0, mService.mToastQueue.size()); 8550 assertThat(wasEnqueued).isFalse(); 8551 } 8552 8553 @Test testDisallowToastsFromSuspendedPackages()8554 public void testDisallowToastsFromSuspendedPackages() throws Exception { 8555 final String testPackage = "testPackageName"; 8556 assertEquals(0, mService.mToastQueue.size()); 8557 mService.isSystemUid = false; 8558 mService.isSystemAppId = false; 8559 setToastRateIsWithinQuota(true); 8560 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8561 8562 // package is suspended 8563 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8564 .thenReturn(true); 8565 8566 // notifications from this package are NOT blocked by the user 8567 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 8568 8569 // enqueue toast -> no toasts enqueued 8570 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 8571 verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 8572 anyInt()); 8573 assertEquals(0, mService.mToastQueue.size()); 8574 assertThat(wasEnqueued).isFalse(); 8575 } 8576 8577 @Test testDisallowToastsFromBlockedApps()8578 public void testDisallowToastsFromBlockedApps() throws Exception { 8579 final String testPackage = "testPackageName"; 8580 assertEquals(0, mService.mToastQueue.size()); 8581 mService.isSystemUid = false; 8582 mService.isSystemAppId = false; 8583 setToastRateIsWithinQuota(true); 8584 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8585 8586 // package is not suspended 8587 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8588 .thenReturn(false); 8589 8590 // notifications from this package are blocked by the user 8591 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 8592 8593 setAppInForegroundForToasts(mUid, false); 8594 8595 // enqueue toast -> no toasts enqueued 8596 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 8597 assertEquals(0, mService.mToastQueue.size()); 8598 assertThat(wasEnqueued).isFalse(); 8599 } 8600 8601 @Test testAlwaysAllowSystemToasts()8602 public void testAlwaysAllowSystemToasts() throws Exception { 8603 final String testPackage = "testPackageName"; 8604 assertEquals(0, mService.mToastQueue.size()); 8605 mService.isSystemUid = true; 8606 setToastRateIsWithinQuota(true); 8607 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8608 8609 // package is suspended 8610 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8611 .thenReturn(true); 8612 8613 // notifications from this package ARE blocked by the user 8614 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 8615 8616 setAppInForegroundForToasts(mUid, false); 8617 8618 // enqueue toast -> system toast can still be enqueued 8619 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 8620 assertEquals(1, mService.mToastQueue.size()); 8621 assertThat(wasEnqueued).isTrue(); 8622 } 8623 8624 @Test testLimitNumberOfQueuedToastsFromPackage()8625 public void testLimitNumberOfQueuedToastsFromPackage() throws Exception { 8626 final String testPackage = "testPackageName"; 8627 assertEquals(0, mService.mToastQueue.size()); 8628 mService.isSystemUid = false; 8629 mService.isSystemAppId = false; 8630 setToastRateIsWithinQuota(true); 8631 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8632 8633 // package is not suspended 8634 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8635 .thenReturn(false); 8636 8637 INotificationManager nmService = (INotificationManager) mService.mService; 8638 8639 // Trying to quickly enqueue more toast than allowed. 8640 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) { 8641 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 8642 if (i < NotificationManagerService.MAX_PACKAGE_TOASTS) { 8643 assertThat(wasEnqueued).isTrue(); 8644 } else { 8645 assertThat(wasEnqueued).isFalse(); 8646 } 8647 } 8648 // Only allowed number enqueued, rest ignored. 8649 assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size()); 8650 } 8651 8652 @Test testPrioritizeSystemToasts()8653 public void testPrioritizeSystemToasts() throws Exception { 8654 // Insert non-system toasts 8655 final String testPackage = "testPackageName"; 8656 assertEquals(0, mService.mToastQueue.size()); 8657 mService.isSystemUid = false; 8658 mService.isSystemAppId = false; 8659 setToastRateIsWithinQuota(true); 8660 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 8661 8662 // package is not suspended 8663 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 8664 .thenReturn(false); 8665 8666 INotificationManager nmService = (INotificationManager) mService.mService; 8667 8668 // Enqueue maximum number of toasts for test package 8669 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) { 8670 enqueueTextToast(testPackage, "Text"); 8671 } 8672 8673 // Enqueue system toast 8674 final String testPackageSystem = "testPackageNameSystem"; 8675 mService.isSystemUid = true; 8676 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem, false); 8677 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem, mUserId)) 8678 .thenReturn(false); 8679 8680 enqueueToast(testPackageSystem, new TestableToastCallback()); 8681 8682 // System toast is inserted at the front of the queue, behind current showing toast 8683 assertEquals(testPackageSystem, mService.mToastQueue.get(1).pkg); 8684 } 8685 8686 @Test testPrioritizeSystemToasts_enqueueAfterExistingSystemToast()8687 public void testPrioritizeSystemToasts_enqueueAfterExistingSystemToast() throws Exception { 8688 // Insert system toasts 8689 final String testPackageSystem1 = "testPackageNameSystem1"; 8690 assertEquals(0, mService.mToastQueue.size()); 8691 mService.isSystemUid = true; 8692 setToastRateIsWithinQuota(true); 8693 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem1, false); 8694 8695 // package is not suspended 8696 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem1, mUserId)) 8697 .thenReturn(false); 8698 8699 INotificationManager nmService = (INotificationManager) mService.mService; 8700 8701 // Enqueue maximum number of toasts for test package 8702 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) { 8703 enqueueTextToast(testPackageSystem1, "Text"); 8704 } 8705 8706 // Enqueue another system toast 8707 final String testPackageSystem2 = "testPackageNameSystem2"; 8708 mService.isSystemUid = true; 8709 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem2, false); 8710 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem2, mUserId)) 8711 .thenReturn(false); 8712 8713 enqueueToast(testPackageSystem2, new TestableToastCallback()); 8714 8715 // System toast is inserted at the back of the queue, after the other system toasts 8716 assertEquals(testPackageSystem2, 8717 mService.mToastQueue.get(mService.mToastQueue.size() - 1).pkg); 8718 } 8719 setAppInForegroundForToasts(int uid, boolean inForeground)8720 private void setAppInForegroundForToasts(int uid, boolean inForeground) { 8721 int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE; 8722 when(mActivityManager.getUidImportance(mUid)).thenReturn(importance); 8723 when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground); 8724 } 8725 setToastRateIsWithinQuota(boolean isWithinQuota)8726 private void setToastRateIsWithinQuota(boolean isWithinQuota) { 8727 when(mToastRateLimiter.isWithinQuota( 8728 anyInt(), 8729 anyString(), 8730 eq(NotificationManagerService.TOAST_QUOTA_TAG))) 8731 .thenReturn(isWithinQuota); 8732 } 8733 setIfPackageHasPermissionToAvoidToastRateLimiting( String pkg, boolean hasPermission)8734 private void setIfPackageHasPermissionToAvoidToastRateLimiting( 8735 String pkg, boolean hasPermission) throws Exception { 8736 when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS, 8737 pkg, mUserId)) 8738 .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED); 8739 } 8740 8741 @Test testOnPanelRevealedAndHidden()8742 public void testOnPanelRevealedAndHidden() { 8743 int items = 5; 8744 mService.mNotificationDelegate.onPanelRevealed(false, items); 8745 verify(mAssistants, times(1)).onPanelRevealed(eq(items)); 8746 8747 mService.mNotificationDelegate.onPanelHidden(); 8748 verify(mAssistants, times(1)).onPanelHidden(); 8749 8750 assertEquals(2, mNotificationRecordLogger.numCalls()); 8751 assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN, 8752 mNotificationRecordLogger.event(0)); 8753 assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE, 8754 mNotificationRecordLogger.event(1)); 8755 } 8756 8757 @Test 8758 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testOnNotificationSmartReplySent()8759 public void testOnNotificationSmartReplySent() { 8760 final int replyIndex = 2; 8761 final String reply = "Hello"; 8762 final boolean modifiedBeforeSending = true; 8763 final boolean generatedByAssistant = true; 8764 8765 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8766 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 8767 mService.addNotification(r); 8768 8769 mService.mNotificationDelegate.onNotificationSmartReplySent( 8770 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN, 8771 modifiedBeforeSending); 8772 verify(mAssistants).notifyAssistantSuggestedReplySent( 8773 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(reply), eq(generatedByAssistant)); 8774 assertEquals(1, mNotificationRecordLogger.numCalls()); 8775 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED, 8776 mNotificationRecordLogger.event(0)); 8777 // Check that r.recordSmartReplied was called. 8778 assertThat(r.getSbn().getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) 8779 .isGreaterThan(0); 8780 assertThat(r.getStats().hasSmartReplied()).isTrue(); 8781 } 8782 8783 @Test 8784 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate()8785 public void testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate() throws Exception { 8786 final int replyIndex = 2; 8787 final String reply = "Hello"; 8788 final boolean modifiedBeforeSending = true; 8789 final boolean generatedByAssistant = true; 8790 8791 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8792 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 8793 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 8794 mService.addNotification(r); 8795 8796 mService.mNotificationDelegate.onNotificationSmartReplySent( 8797 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN, 8798 modifiedBeforeSending); 8799 waitForIdle(); 8800 8801 // Checks that a post update is sent. 8802 verify(mWorkerHandler, times(1)) 8803 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 8804 ArgumentCaptor<NotificationRecord> captor = 8805 ArgumentCaptor.forClass(NotificationRecord.class); 8806 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 8807 anyBoolean()); 8808 assertThat(captor.getValue().getNotification().flags 8809 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 8810 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 8811 assertThat(captor.getValue().getNotification().flags 8812 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 8813 assertThat(captor.getValue().shouldPostSilently()).isTrue(); 8814 } 8815 8816 @Test testOnNotificationActionClick()8817 public void testOnNotificationActionClick() { 8818 final int actionIndex = 2; 8819 final Notification.Action action = 8820 new Notification.Action.Builder(null, "text", mActivityIntent).build(); 8821 final boolean generatedByAssistant = false; 8822 8823 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8824 mService.addNotification(r); 8825 8826 NotificationVisibility notificationVisibility = 8827 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 8828 mService.mNotificationDelegate.onNotificationActionClick( 8829 10, 10, r.getKey(), actionIndex, action, notificationVisibility, 8830 generatedByAssistant); 8831 verify(mAssistants).notifyAssistantActionClicked( 8832 eq(r), eq(action), eq(generatedByAssistant)); 8833 8834 assertEquals(1, mNotificationRecordLogger.numCalls()); 8835 assertEquals( 8836 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED_2, 8837 mNotificationRecordLogger.event(0)); 8838 } 8839 8840 @Test 8841 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testActionClickLifetimeExtendedCancel()8842 public void testActionClickLifetimeExtendedCancel() throws Exception { 8843 final Notification.Action action = 8844 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 8845 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 8846 8847 // Creates a notification marked as being lifetime extended. 8848 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8849 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 8850 mService.addNotification(r); 8851 8852 StatusBarNotification[] notifs = 8853 mBinderService.getActiveNotifications(mPkg); 8854 assertThat(notifs.length).isEqualTo(1); 8855 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 8856 8857 // Call on action click. 8858 NotificationVisibility notificationVisibility = 8859 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 8860 mService.mNotificationDelegate.onNotificationActionClick( 8861 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 8862 /*generatedByAssistant=*/false); 8863 8864 // Lifetime extended flag persists. 8865 assertThat(r.getSbn().getNotification().flags 8866 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 8867 8868 mTestableLooper.moveTimeForward(210); 8869 waitForIdle(); 8870 verify(mWorkerHandler, times(1)) 8871 .scheduleCancelNotification( 8872 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 8873 8874 // Check that the cancelation occurred and the notification is gone. 8875 notifs = mBinderService.getActiveNotifications(mPkg); 8876 assertThat(notifs.length).isEqualTo(0); 8877 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 8878 } 8879 8880 @Test 8881 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testActionClickLifetimeExtendedCancel_PreventByNoDismiss()8882 public void testActionClickLifetimeExtendedCancel_PreventByNoDismiss() throws Exception { 8883 final Notification.Action action = 8884 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 8885 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 8886 8887 // Creates a notification marked as being lifetime extended. 8888 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8889 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 8890 // Make the notification non-dismissable 8891 r.getSbn().getNotification().flags |= FLAG_NO_DISMISS; 8892 mService.addNotification(r); 8893 8894 StatusBarNotification[] notifs = 8895 mBinderService.getActiveNotifications(mPkg); 8896 assertThat(notifs.length).isEqualTo(1); 8897 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 8898 8899 // Call on action click. 8900 NotificationVisibility notificationVisibility = 8901 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 8902 mService.mNotificationDelegate.onNotificationActionClick( 8903 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 8904 /*generatedByAssistant=*/false); 8905 8906 // Lifetime extended flag persists. 8907 assertThat(r.getSbn().getNotification().flags 8908 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 8909 8910 mTestableLooper.moveTimeForward(210); 8911 waitForIdle(); 8912 verify(mWorkerHandler, times(1)) 8913 .scheduleCancelNotification( 8914 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 8915 8916 // The cancellation is dropped and the notification is still present, with the update. 8917 notifs = mBinderService.getActiveNotifications(mPkg); 8918 assertThat(notifs.length).isEqualTo(1); 8919 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 8920 } 8921 8922 @Test 8923 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testUpdateOnActionClickDropsLifetimeExtendedCancel()8924 public void testUpdateOnActionClickDropsLifetimeExtendedCancel() throws Exception { 8925 final Notification.Action action = 8926 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 8927 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 8928 8929 // Creates a notification marked as being lifetime extended. 8930 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8931 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 8932 mService.addNotification(r); 8933 8934 StatusBarNotification[] notifs = 8935 mBinderService.getActiveNotifications(mPkg); 8936 assertThat(notifs.length).isEqualTo(1); 8937 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 8938 8939 // Call on action click. 8940 NotificationVisibility notificationVisibility = 8941 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 8942 mService.mNotificationDelegate.onNotificationActionClick( 8943 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 8944 /*generatedByAssistant=*/false); 8945 8946 // The "app" sends an update of the notification in response. 8947 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 8948 r.getSbn().getId(), r.getSbn().getNotification(), r.getSbn().getUserId()); 8949 8950 mTestableLooper.moveTimeForward(210); 8951 waitForIdle(); 8952 verify(mWorkerHandler, times(1)) 8953 .scheduleCancelNotification( 8954 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 8955 8956 // The cancellation is dropped and the notification is still present, with the update. 8957 notifs = mBinderService.getActiveNotifications(mPkg); 8958 assertThat(notifs.length).isEqualTo(1); 8959 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 8960 } 8961 8962 @Test testOnAssistantNotificationActionClick()8963 public void testOnAssistantNotificationActionClick() { 8964 final int actionIndex = 1; 8965 final Notification.Action action = 8966 new Notification.Action.Builder(null, "text", mActivityIntent).build(); 8967 final boolean generatedByAssistant = true; 8968 8969 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8970 mService.addNotification(r); 8971 8972 NotificationVisibility notificationVisibility = 8973 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 8974 mService.mNotificationDelegate.onNotificationActionClick( 8975 10, 10, r.getKey(), actionIndex, action, notificationVisibility, 8976 generatedByAssistant); 8977 verify(mAssistants).notifyAssistantActionClicked( 8978 eq(r), eq(action), eq(generatedByAssistant)); 8979 8980 assertEquals(1, mNotificationRecordLogger.numCalls()); 8981 assertEquals( 8982 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ASSIST_ACTION_CLICKED_1, 8983 mNotificationRecordLogger.event(0)); 8984 } 8985 8986 8987 @Test testLogSmartSuggestionsVisible_triggerOnExpandAndVisible()8988 public void testLogSmartSuggestionsVisible_triggerOnExpandAndVisible() { 8989 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 8990 mService.addNotification(r); 8991 8992 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 8993 NOTIFICATION_LOCATION_UNKNOWN); 8994 NotificationVisibility[] notificationVisibility = new NotificationVisibility[] { 8995 NotificationVisibility.obtain(r.getKey(), 0, 0, true) 8996 }; 8997 mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility, 8998 new NotificationVisibility[0]); 8999 9000 assertEquals(1, mService.countLogSmartSuggestionsVisible); 9001 } 9002 9003 @Test testLogSmartSuggestionsVisible_noTriggerOnExpand()9004 public void testLogSmartSuggestionsVisible_noTriggerOnExpand() { 9005 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9006 mService.addNotification(r); 9007 9008 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 9009 NOTIFICATION_LOCATION_UNKNOWN); 9010 9011 assertEquals(0, mService.countLogSmartSuggestionsVisible); 9012 } 9013 9014 @Test testLogSmartSuggestionsVisible_noTriggerOnVisible()9015 public void testLogSmartSuggestionsVisible_noTriggerOnVisible() { 9016 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9017 mService.addNotification(r); 9018 9019 NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{ 9020 NotificationVisibility.obtain(r.getKey(), 0, 0, true) 9021 }; 9022 mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility, 9023 new NotificationVisibility[0]); 9024 9025 assertEquals(0, mService.countLogSmartSuggestionsVisible); 9026 } 9027 9028 @Test testReportSeen_delegated()9029 public void testReportSeen_delegated() { 9030 Notification.Builder nb = 9031 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 9032 .setContentTitle("foo") 9033 .setSmallIcon(android.R.drawable.sym_def_app_icon); 9034 9035 StatusBarNotification sbn = new StatusBarNotification(mPkg, "opPkg", 0, "tag", mUid, 0, 9036 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 9037 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9038 9039 mService.reportSeen(r); 9040 verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt()); 9041 9042 } 9043 9044 @Test testReportSeen_notDelegated()9045 public void testReportSeen_notDelegated() { 9046 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9047 9048 mService.reportSeen(r); 9049 verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt()); 9050 } 9051 9052 @Test testNotificationStats_notificationError()9053 public void testNotificationStats_notificationError() { 9054 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9055 mService.addNotification(r); 9056 9057 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, r.getSbn().getId(), 9058 r.getSbn().getTag(), mUid, 0, 9059 new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(), 9060 UserHandle.getUserHandleForUid(mUid), null, 0); 9061 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9062 mService.addEnqueuedNotification(update); 9063 assertNull(update.getSbn().getNotification().getSmallIcon()); 9064 9065 NotificationManagerService.PostNotificationRunnable runnable = 9066 mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(), 9067 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 9068 runnable.run(); 9069 waitForIdle(); 9070 9071 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 9072 verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture()); 9073 assertNotNull(captor.getValue()); 9074 } 9075 9076 @Test testCanNotifyAsUser_crossUser()9077 public void testCanNotifyAsUser_crossUser() throws Exception { 9078 // same user no problem 9079 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId()); 9080 9081 // cross user, no permission, problem 9082 try { 9083 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1); 9084 fail("Should not be callable cross user without cross user permission"); 9085 } catch (SecurityException e) { 9086 // good 9087 } 9088 9089 // cross user, with permission, no problem 9090 enableInteractAcrossUsers(); 9091 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1); 9092 } 9093 9094 @Test testGetNotificationChannels_crossUser()9095 public void testGetNotificationChannels_crossUser() throws Exception { 9096 // same user no problem 9097 mBinderService.getNotificationChannels("src", "target", mContext.getUserId()); 9098 9099 // cross user, no permission, problem 9100 try { 9101 mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1); 9102 fail("Should not be callable cross user without cross user permission"); 9103 } catch (SecurityException e) { 9104 // good 9105 } 9106 9107 // cross user, with permission, no problem 9108 enableInteractAcrossUsers(); 9109 mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1); 9110 } 9111 9112 @Test setDefaultAssistantForUser_fromConfigXml()9113 public void setDefaultAssistantForUser_fromConfigXml() { 9114 ComponentName xmlConfig = new ComponentName("config", "xml"); 9115 ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(xmlConfig)); 9116 when(mResources 9117 .getString( 9118 com.android.internal.R.string.config_defaultAssistantAccessComponent)) 9119 .thenReturn(xmlConfig.flattenToString()); 9120 when(mContext.getResources()).thenReturn(mResources); 9121 when(mAssistants.queryPackageForServices(eq(null), anyInt(), anyInt())) 9122 .thenReturn(components); 9123 when(mAssistants.getDefaultComponents()) 9124 .thenReturn(components); 9125 mService.setNotificationAssistantAccessGrantedCallback( 9126 mNotificationAssistantAccessGrantedCallback); 9127 9128 9129 mService.setDefaultAssistantForUser(0); 9130 9131 verify(mNotificationAssistantAccessGrantedCallback) 9132 .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false)); 9133 } 9134 9135 @Test clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne()9136 public void clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne() throws RemoteException { 9137 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 9138 generateResetComponentValues(); 9139 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners); 9140 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 9141 ComponentName deviceConfig1 = new ComponentName("device", "config1"); 9142 ComponentName deviceConfig2 = new ComponentName("device", "config2"); 9143 changes.put(true, new ArrayList(Arrays.asList(deviceConfig1, deviceConfig2))); 9144 changes.put(false, new ArrayList()); 9145 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes); 9146 mService.getBinderService().clearData("device", 0, false); 9147 verify(mAssistants, times(1)) 9148 .setPackageOrComponentEnabled( 9149 eq("device/config2"), 9150 eq(0), eq(true), eq(false)); 9151 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 9152 eq("device"), eq(0), eq(false), eq(true)); 9153 } 9154 9155 @Test testNASSettingUpgrade_userSetNull()9156 public void testNASSettingUpgrade_userSetNull() throws RemoteException { 9157 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 9158 TestableNotificationManagerService service = spy(mService); 9159 int userId = 11; 9160 setUsers(new int[]{userId}); 9161 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 9162 setNASMigrationDone(false, userId); 9163 when(mAssistants.getDefaultFromConfig()) 9164 .thenReturn(newDefaultComponent); 9165 when(mAssistants.getAllowedComponents(anyInt())) 9166 .thenReturn(new ArrayList<>()); 9167 when(mAssistants.hasUserSet(userId)).thenReturn(true); 9168 9169 service.migrateDefaultNAS(); 9170 assertTrue(service.isNASMigrationDone(userId)); 9171 verify(mAssistants, times(1)).clearDefaults(); 9172 } 9173 9174 @Test testNASSettingUpgrade_userSet()9175 public void testNASSettingUpgrade_userSet() throws RemoteException { 9176 ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component1"); 9177 TestableNotificationManagerService service = spy(mService); 9178 int userId = 11; 9179 setUsers(new int[]{userId}); 9180 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 9181 setNASMigrationDone(false, userId); 9182 when(mAssistants.getDefaultFromConfig()) 9183 .thenReturn(defaultComponent); 9184 when(mAssistants.getAllowedComponents(anyInt())) 9185 .thenReturn(new ArrayList(Arrays.asList(defaultComponent))); 9186 when(mAssistants.hasUserSet(userId)).thenReturn(true); 9187 9188 service.migrateDefaultNAS(); 9189 verify(mAssistants, times(1)).setUserSet(userId, false); 9190 //resetDefaultAssistantsIfNecessary should invoke from readPolicyXml() and migration 9191 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 9192 } 9193 9194 @Test testNASSettingUpgrade_multiUser()9195 public void testNASSettingUpgrade_multiUser() throws RemoteException { 9196 ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 9197 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2"); 9198 TestableNotificationManagerService service = spy(mService); 9199 int userId1 = 11; 9200 int userId2 = 12; 9201 setUsers(new int[]{userId1, userId2}); 9202 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1}); 9203 when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2}); 9204 9205 setNASMigrationDone(false, userId1); 9206 setNASMigrationDone(false, userId2); 9207 when(mAssistants.getDefaultComponents()) 9208 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent))); 9209 when(mAssistants.getDefaultFromConfig()) 9210 .thenReturn(newDefaultComponent); 9211 //User1: set different NAS 9212 when(mAssistants.getAllowedComponents(userId1)) 9213 .thenReturn(Arrays.asList(oldDefaultComponent)); 9214 //User2: set to none 9215 when(mAssistants.getAllowedComponents(userId2)) 9216 .thenReturn(new ArrayList<>()); 9217 9218 when(mAssistants.hasUserSet(userId1)).thenReturn(true); 9219 when(mAssistants.hasUserSet(userId2)).thenReturn(true); 9220 9221 service.migrateDefaultNAS(); 9222 // user1's setting get reset 9223 verify(mAssistants, times(1)).setUserSet(userId1, false); 9224 verify(mAssistants, times(0)).setUserSet(eq(userId2), anyBoolean()); 9225 assertTrue(service.isNASMigrationDone(userId2)); 9226 9227 } 9228 9229 @Test testNASSettingUpgrade_multiProfile()9230 public void testNASSettingUpgrade_multiProfile() throws RemoteException { 9231 ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 9232 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2"); 9233 TestableNotificationManagerService service = spy(mService); 9234 int userId1 = 11; 9235 int userId2 = 12; //work profile 9236 setUsers(new int[]{userId1, userId2}); 9237 when(mUm.isManagedProfile(userId2)).thenReturn(true); 9238 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2}); 9239 9240 setNASMigrationDone(false, userId1); 9241 setNASMigrationDone(false, userId2); 9242 when(mAssistants.getDefaultComponents()) 9243 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent))); 9244 when(mAssistants.getDefaultFromConfig()) 9245 .thenReturn(newDefaultComponent); 9246 //Both profiles: set different NAS 9247 when(mAssistants.getAllowedComponents(userId1)) 9248 .thenReturn(Arrays.asList(oldDefaultComponent)); 9249 when(mAssistants.getAllowedComponents(userId2)) 9250 .thenReturn(Arrays.asList(oldDefaultComponent)); 9251 9252 when(mAssistants.hasUserSet(userId1)).thenReturn(true); 9253 when(mAssistants.hasUserSet(userId2)).thenReturn(true); 9254 9255 service.migrateDefaultNAS(); 9256 assertFalse(service.isNASMigrationDone(userId1)); 9257 assertFalse(service.isNASMigrationDone(userId2)); 9258 } 9259 9260 9261 9262 @Test testNASSettingUpgrade_clearDataAfterMigrationIsDone()9263 public void testNASSettingUpgrade_clearDataAfterMigrationIsDone() throws RemoteException { 9264 ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component"); 9265 TestableNotificationManagerService service = spy(mService); 9266 int userId = 12; 9267 setUsers(new int[]{userId}); 9268 when(mAssistants.getDefaultComponents()) 9269 .thenReturn(new ArraySet<>(Arrays.asList(defaultComponent))); 9270 when(mAssistants.hasUserSet(userId)).thenReturn(true); 9271 setNASMigrationDone(true, userId); 9272 9273 //Test User clear data 9274 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 9275 generateResetComponentValues(); 9276 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners); 9277 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 9278 changes.put(true, new ArrayList(Arrays.asList(defaultComponent))); 9279 changes.put(false, new ArrayList()); 9280 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes); 9281 9282 //Clear data 9283 service.getBinderService().clearData("package", userId, false); 9284 //Test migrate flow again 9285 service.migrateDefaultNAS(); 9286 9287 //Migration should not happen again 9288 verify(mAssistants, times(0)).setUserSet(userId, false); 9289 verify(mAssistants, times(0)).clearDefaults(); 9290 //resetDefaultAssistantsIfNecessary should only invoke once from readPolicyXml() 9291 verify(mAssistants, times(1)).resetDefaultAssistantsIfNecessary(); 9292 9293 } 9294 setNASMigrationDone(boolean done, int userId)9295 private void setNASMigrationDone(boolean done, int userId) { 9296 Settings.Secure.putIntForUser(mContext.getContentResolver(), 9297 Settings.Secure.NAS_SETTINGS_UPDATED, done ? 1 : 0, userId); 9298 } 9299 setUsers(int[] userIds)9300 private void setUsers(int[] userIds) { 9301 List<UserInfo> users = new ArrayList<>(); 9302 for (int id: userIds) { 9303 users.add(new UserInfo(id, String.valueOf(id), 0)); 9304 } 9305 for (UserInfo user : users) { 9306 when(mUm.getUserInfo(eq(user.id))).thenReturn(user); 9307 } 9308 when(mUm.getUsers()).thenReturn(users); 9309 } 9310 9311 @Test clearDefaultListenersPackageShouldEnableIt()9312 public void clearDefaultListenersPackageShouldEnableIt() throws RemoteException { 9313 ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants = 9314 generateResetComponentValues(); 9315 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changedAssistants); 9316 ComponentName deviceConfig = new ComponentName("device", "config"); 9317 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 9318 changes.put(true, new ArrayList(Arrays.asList(deviceConfig))); 9319 changes.put(false, new ArrayList()); 9320 when(mListeners.resetComponents(anyString(), anyInt())) 9321 .thenReturn(changes); 9322 mService.getBinderService().clearData("device", 0, false); 9323 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 9324 eq("device"), eq(0), eq(false), eq(true)); 9325 } 9326 9327 @Test clearDefaultDnDPackageShouldEnableIt()9328 public void clearDefaultDnDPackageShouldEnableIt() throws RemoteException { 9329 ArrayMap<Boolean, ArrayList<ComponentName>> changed = generateResetComponentValues(); 9330 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changed); 9331 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changed); 9332 mService.getBinderService().clearData("pkgName", 0, false); 9333 verify(mConditionProviders, times(1)).resetPackage( 9334 eq("pkgName"), eq(0)); 9335 } 9336 9337 @Test testFlagBubble()9338 public void testFlagBubble() throws RemoteException { 9339 setUpPrefsForBubbles(mPkg, mUid, 9340 true /* global */, 9341 BUBBLE_PREFERENCE_ALL /* app */, 9342 true /* channel */); 9343 9344 NotificationRecord nr = 9345 generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble"); 9346 9347 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9348 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9349 waitForIdle(); 9350 9351 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9352 assertEquals(1, notifs.length); 9353 assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0); 9354 assertTrue(mService.getNotificationRecord( 9355 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 9356 } 9357 9358 @Test testFlagBubble_noFlag_appNotAllowed()9359 public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException { 9360 setUpPrefsForBubbles(mPkg, mUid, 9361 true /* global */, 9362 BUBBLE_PREFERENCE_NONE /* app */, 9363 true /* channel */); 9364 9365 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 9366 "testFlagBubble_noFlag_appNotAllowed"); 9367 9368 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9369 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9370 waitForIdle(); 9371 9372 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9373 assertEquals(1, notifs.length); 9374 assertEquals((notifs[0].getNotification().flags & FLAG_BUBBLE), 0); 9375 assertFalse(mService.getNotificationRecord( 9376 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 9377 } 9378 9379 @Test testFlagBubbleNotifs_noFlag_whenAppForeground()9380 public void testFlagBubbleNotifs_noFlag_whenAppForeground() throws RemoteException { 9381 setUpPrefsForBubbles(mPkg, mUid, 9382 true /* global */, 9383 BUBBLE_PREFERENCE_ALL /* app */, 9384 true /* channel */); 9385 9386 // Notif with bubble metadata but not our other misc requirements 9387 Notification.Builder nb = new Notification.Builder(mContext, 9388 mTestNotificationChannel.getId()) 9389 .setContentTitle("foo") 9390 .setSmallIcon(android.R.drawable.sym_def_app_icon) 9391 .setBubbleMetadata(getBubbleMetadata()); 9392 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 0, 9393 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 9394 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9395 9396 // Say we're foreground 9397 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 9398 IMPORTANCE_FOREGROUND); 9399 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9400 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9401 waitForIdle(); 9402 9403 // if notif isn't configured properly it doesn't get to bubble just because app is 9404 // foreground. 9405 assertFalse(mService.getNotificationRecord( 9406 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 9407 } 9408 9409 @Test testFlagBubbleNotifs_flag_messaging()9410 public void testFlagBubbleNotifs_flag_messaging() throws RemoteException { 9411 setUpPrefsForBubbles(mPkg, mUid, 9412 true /* global */, 9413 BUBBLE_PREFERENCE_ALL /* app */, 9414 true /* channel */); 9415 9416 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 9417 "testFlagBubbleNotifs_flag_messaging"); 9418 9419 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9420 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9421 waitForIdle(); 9422 9423 // yes allowed, yes messaging, yes bubble 9424 assertTrue(mService.getNotificationRecord( 9425 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 9426 } 9427 9428 @Test testFlagBubbleNotifs_noFlag_noShortcut()9429 public void testFlagBubbleNotifs_noFlag_noShortcut() throws RemoteException { 9430 setUpPrefsForBubbles(mPkg, mUid, 9431 true /* global */, 9432 BUBBLE_PREFERENCE_ALL /* app */, 9433 true /* channel */); 9434 9435 Notification.Builder nb = getMessageStyleNotifBuilder(true, null, false, true); 9436 nb.setShortcutId(null); 9437 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 9438 null, mUid, 0, 9439 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 9440 9441 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 9442 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 9443 waitForIdle(); 9444 9445 // no shortcut no bubble 9446 assertFalse(mService.getNotificationRecord( 9447 sbn.getKey()).getNotification().isBubbleNotification()); 9448 } 9449 9450 @Test testFlagBubbleNotifs_noFlag_messaging_appNotAllowed()9451 public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException { 9452 setUpPrefsForBubbles(mPkg, mUid, 9453 true /* global */, 9454 BUBBLE_PREFERENCE_NONE /* app */, 9455 true /* channel */); 9456 9457 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 9458 "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed"); 9459 9460 // Post the notification 9461 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9462 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9463 waitForIdle(); 9464 9465 // not allowed, no bubble 9466 assertFalse(mService.getNotificationRecord( 9467 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 9468 } 9469 9470 @Test testFlagBubbleNotifs_noFlag_notBubble()9471 public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException { 9472 setUpPrefsForBubbles(mPkg, mUid, 9473 true /* global */, 9474 BUBBLE_PREFERENCE_ALL /* app */, 9475 true /* channel */); 9476 9477 // Messaging notif WITHOUT bubble metadata 9478 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addBubbleMetadata */, 9479 null /* groupKey */, false /* isSummary */, true); 9480 9481 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 9482 "testFlagBubbleNotifs_noFlag_notBubble", mUid, 0, 9483 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 9484 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9485 9486 // Post the notification 9487 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9488 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9489 waitForIdle(); 9490 9491 // no bubble metadata, no bubble 9492 assertFalse(mService.getNotificationRecord( 9493 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 9494 } 9495 9496 @Test testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed()9497 public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException { 9498 setUpPrefsForBubbles(mPkg, mUid, 9499 true /* global */, 9500 BUBBLE_PREFERENCE_ALL /* app */, 9501 false /* channel */); 9502 9503 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 9504 "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed"); 9505 nr.getChannel().lockFields(USER_LOCKED_ALLOW_BUBBLE); 9506 9507 // Post the notification 9508 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9509 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9510 waitForIdle(); 9511 9512 // channel not allowed, no bubble 9513 assertFalse(mService.getNotificationRecord( 9514 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 9515 } 9516 9517 @Test testCancelNotificationsFromApp_cancelsBubbles()9518 public void testCancelNotificationsFromApp_cancelsBubbles() throws Exception { 9519 final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel); 9520 nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE; 9521 9522 // Post the notification 9523 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 9524 "testAppCancelNotifications_cancelsBubbles", 9525 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(), 9526 nrBubble.getSbn().getUserId()); 9527 waitForIdle(); 9528 9529 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9530 assertEquals(1, notifs.length); 9531 assertEquals(1, mService.getNotificationRecordCount()); 9532 9533 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 9534 "testAppCancelNotifications_cancelsBubbles", nrBubble.getSbn().getId(), 9535 nrBubble.getSbn().getUserId()); 9536 waitForIdle(); 9537 9538 StatusBarNotification[] notifs2 = mBinderService.getActiveNotifications(mPkg); 9539 assertEquals(0, notifs2.length); 9540 assertEquals(0, mService.getNotificationRecordCount()); 9541 } 9542 9543 @Test testCancelAllNotificationsFromApp_cancelsBubble()9544 public void testCancelAllNotificationsFromApp_cancelsBubble() throws Exception { 9545 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 9546 nr.getSbn().getNotification().flags |= FLAG_BUBBLE; 9547 mService.addNotification(nr); 9548 9549 mBinderService.cancelAllNotifications(mPkg, nr.getSbn().getUserId()); 9550 waitForIdle(); 9551 9552 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9553 assertEquals(0, notifs.length); 9554 assertEquals(0, mService.getNotificationRecordCount()); 9555 } 9556 9557 @Test testCancelAllNotificationsFromListener_ignoresBubbles()9558 public void testCancelAllNotificationsFromListener_ignoresBubbles() throws Exception { 9559 final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel); 9560 final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel); 9561 nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE; 9562 9563 mService.addNotification(nrNormal); 9564 mService.addNotification(nrBubble); 9565 9566 mService.getBinderService().cancelNotificationsFromListener(null, null); 9567 waitForIdle(); 9568 9569 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9570 assertEquals(1, notifs.length); 9571 assertEquals(1, mService.getNotificationRecordCount()); 9572 } 9573 9574 @Test testCancelNotificationsFromListener_cancelsNonBubble()9575 public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception { 9576 // Add non-bubble notif 9577 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 9578 mService.addNotification(nr); 9579 9580 // Cancel via listener 9581 String[] keys = {nr.getSbn().getKey()}; 9582 mService.getBinderService().cancelNotificationsFromListener(null, keys); 9583 waitForIdle(); 9584 9585 // Notif not active anymore 9586 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9587 assertEquals(0, notifs.length); 9588 assertEquals(0, mService.getNotificationRecordCount()); 9589 // Cancel event is logged 9590 assertEquals(1, mNotificationRecordLogger.numCalls()); 9591 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 9592 .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0)); 9593 } 9594 9595 @Test testCancelNotificationsFromListener_suppressesBubble()9596 public void testCancelNotificationsFromListener_suppressesBubble() throws Exception { 9597 // Add bubble notif 9598 setUpPrefsForBubbles(mPkg, mUid, 9599 true /* global */, 9600 BUBBLE_PREFERENCE_ALL /* app */, 9601 true /* channel */); 9602 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 9603 9604 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 9605 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 9606 waitForIdle(); 9607 9608 // Cancel via listener 9609 String[] keys = {nr.getSbn().getKey()}; 9610 mService.getBinderService().cancelNotificationsFromListener(null, keys); 9611 waitForIdle(); 9612 9613 // Bubble notif active and suppressed 9614 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9615 assertEquals(1, notifs.length); 9616 assertEquals(1, mService.getNotificationRecordCount()); 9617 assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed()); 9618 } 9619 9620 @Test testCancelAllNotificationsFromStatusBar_ignoresBubble()9621 public void testCancelAllNotificationsFromStatusBar_ignoresBubble() throws Exception { 9622 // GIVEN a notification bubble 9623 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 9624 nr.getSbn().getNotification().flags |= FLAG_BUBBLE; 9625 mService.addNotification(nr); 9626 9627 // WHEN the status bar clears all notifications 9628 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 9629 nr.getSbn().getUserId()); 9630 waitForIdle(); 9631 9632 // THEN the bubble notification does not get removed 9633 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 9634 assertEquals(1, notifs.length); 9635 assertEquals(1, mService.getNotificationRecordCount()); 9636 } 9637 9638 9639 @Test testGetAllowedAssistantAdjustments()9640 public void testGetAllowedAssistantAdjustments() throws Exception { 9641 List<String> adjustments = mBinderService.getAllowedAssistantAdjustments(null); 9642 assertNotNull(adjustments); 9643 } 9644 9645 @Test testAdjustRestrictedKey()9646 public void testAdjustRestrictedKey() throws Exception { 9647 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9648 mService.addNotification(r); 9649 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 9650 9651 when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true); 9652 when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false); 9653 9654 Bundle signals = new Bundle(); 9655 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); 9656 signals.putInt(KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE); 9657 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 9658 "", r.getUser().getIdentifier()); 9659 9660 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 9661 r.applyAdjustments(); 9662 9663 assertEquals(IMPORTANCE_LOW, r.getAssistantImportance()); 9664 assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment()); 9665 } 9666 9667 @Test testAutomaticZenRuleValidation_policyFilterAgreement()9668 public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception { 9669 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 9670 .thenReturn(true); 9671 mService.setZenHelper(mock(ZenModeHelper.class)); 9672 ComponentName owner = new ComponentName(mContext, this.getClass()); 9673 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 9674 boolean isEnabled = true; 9675 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 9676 zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); 9677 9678 try { 9679 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 9680 fail("Zen policy only applies to priority only mode"); 9681 } catch (IllegalArgumentException e) { 9682 // yay 9683 } 9684 9685 rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 9686 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 9687 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 9688 9689 rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 9690 null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); 9691 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 9692 } 9693 9694 @Test testAddAutomaticZenRule_systemCallTakesPackageFromOwner()9695 public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception { 9696 mService.isSystemUid = true; 9697 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 9698 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 9699 .thenReturn(true); 9700 mService.setZenHelper(mockZenModeHelper); 9701 ComponentName owner = new ComponentName("android", "ProviderName"); 9702 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 9703 boolean isEnabled = true; 9704 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 9705 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 9706 mBinderService.addAutomaticZenRule(rule, "com.android.settings", false); 9707 9708 // verify that zen mode helper gets passed in a package name of "android" 9709 verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), 9710 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), anyInt()); 9711 } 9712 9713 @Test testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner()9714 public void testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner() throws Exception { 9715 // The multi-user case: where the calling uid doesn't match the system uid, but the calling 9716 // *appid* is the system. 9717 mService.isSystemUid = false; 9718 mService.isSystemAppId = true; 9719 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 9720 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 9721 .thenReturn(true); 9722 mService.setZenHelper(mockZenModeHelper); 9723 ComponentName owner = new ComponentName("android", "ProviderName"); 9724 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 9725 boolean isEnabled = true; 9726 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 9727 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 9728 mBinderService.addAutomaticZenRule(rule, "com.android.settings", false); 9729 9730 // verify that zen mode helper gets passed in a package name of "android" 9731 verify(mockZenModeHelper).addAutomaticZenRule(eq("android"), eq(rule), 9732 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), anyInt()); 9733 } 9734 9735 @Test testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg()9736 public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception { 9737 mService.isSystemUid = false; 9738 mService.isSystemAppId = false; 9739 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 9740 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 9741 .thenReturn(true); 9742 mService.setZenHelper(mockZenModeHelper); 9743 ComponentName owner = new ComponentName("android", "ProviderName"); 9744 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 9745 boolean isEnabled = true; 9746 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 9747 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 9748 mBinderService.addAutomaticZenRule(rule, "another.package", false); 9749 9750 // verify that zen mode helper gets passed in the package name from the arg, not the owner 9751 verify(mockZenModeHelper).addAutomaticZenRule( 9752 eq("another.package"), eq(rule), eq(ZenModeConfig.UPDATE_ORIGIN_APP), 9753 anyString(), anyInt()); // doesn't count as a system/systemui call 9754 } 9755 9756 @Test 9757 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners()9758 public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception { 9759 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9760 mService.setCallerIsNormalPackage(); 9761 9762 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 9763 .setType(AutomaticZenRule.TYPE_MANAGED) 9764 .setOwner(new ComponentName(mPkg, "cls")) 9765 .build(); 9766 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); 9767 9768 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 9769 9770 verify(zenModeHelper).addAutomaticZenRule(eq(mPkg), eq(rule), anyInt(), any(), anyInt()); 9771 } 9772 9773 @Test 9774 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeManagedCanBeUsedBySystem()9775 public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception { 9776 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED); 9777 } 9778 9779 @Test 9780 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps()9781 public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception { 9782 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 9783 AutomaticZenRule.TYPE_MANAGED); 9784 } 9785 9786 @Test 9787 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing()9788 public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception { 9789 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9790 mService.setCallerIsNormalPackage(); 9791 reset(mPackageManagerInternal); 9792 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 9793 when(mResources 9794 .getString(com.android.internal.R.string.config_systemWellbeing)) 9795 .thenReturn(mPkg); 9796 when(mContext.getResources()).thenReturn(mResources); 9797 9798 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 9799 .setType(AutomaticZenRule.TYPE_BEDTIME) 9800 .setOwner(new ComponentName(mPkg, "cls")) 9801 .build(); 9802 9803 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 9804 9805 verify(zenModeHelper).addAutomaticZenRule(eq(mPkg), eq(rule), anyInt(), any(), anyInt()); 9806 } 9807 9808 @Test 9809 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem()9810 public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception { 9811 reset(mPackageManagerInternal); 9812 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 9813 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_BEDTIME); 9814 } 9815 9816 @Test 9817 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps()9818 public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception { 9819 reset(mPackageManagerInternal); 9820 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 9821 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 9822 AutomaticZenRule.TYPE_BEDTIME); 9823 } 9824 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( @utomaticZenRule.Type int ruleType)9825 private void addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( 9826 @AutomaticZenRule.Type int ruleType) throws Exception { 9827 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9828 mService.isSystemUid = true; 9829 9830 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 9831 .setType(ruleType) 9832 .setOwner(new ComponentName(mPkg, "cls")) 9833 .build(); 9834 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); 9835 9836 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 9837 9838 verify(zenModeHelper).addAutomaticZenRule(eq(mPkg), eq(rule), anyInt(), any(), anyInt()); 9839 } 9840 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( @utomaticZenRule.Type int ruleType)9841 private void addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 9842 @AutomaticZenRule.Type int ruleType) { 9843 mService.setCallerIsNormalPackage(); 9844 mService.setZenHelper(mock(ZenModeHelper.class)); 9845 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 9846 .thenReturn(true); 9847 9848 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 9849 .setType(ruleType) 9850 .setOwner(new ComponentName(mPkg, "cls")) 9851 .build(); 9852 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false); 9853 9854 assertThrows(IllegalArgumentException.class, 9855 () -> mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false)); 9856 } 9857 9858 @Test 9859 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromUser_mappedToOriginUser()9860 public void addAutomaticZenRule_fromUser_mappedToOriginUser() throws Exception { 9861 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9862 mService.isSystemUid = true; 9863 9864 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true); 9865 9866 verify(zenModeHelper).addAutomaticZenRule(eq("pkg"), eq(SOME_ZEN_RULE), 9867 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyString(), anyInt()); 9868 } 9869 9870 @Test 9871 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem()9872 public void addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem() throws Exception { 9873 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9874 mService.isSystemUid = true; 9875 9876 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false); 9877 9878 verify(zenModeHelper).addAutomaticZenRule(eq("pkg"), eq(SOME_ZEN_RULE), 9879 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), anyInt()); 9880 } 9881 9882 @Test 9883 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromApp_mappedToOriginApp()9884 public void addAutomaticZenRule_fromApp_mappedToOriginApp() throws Exception { 9885 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9886 mService.setCallerIsNormalPackage(); 9887 9888 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false); 9889 9890 verify(zenModeHelper).addAutomaticZenRule(eq("pkg"), eq(SOME_ZEN_RULE), 9891 eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyString(), anyInt()); 9892 } 9893 9894 @Test 9895 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromAppFromUser_blocked()9896 public void addAutomaticZenRule_fromAppFromUser_blocked() throws Exception { 9897 setUpMockZenTest(); 9898 mService.setCallerIsNormalPackage(); 9899 9900 assertThrows(SecurityException.class, () -> 9901 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true)); 9902 } 9903 9904 @Test 9905 @EnableFlags(android.app.Flags.FLAG_MODES_API) updateAutomaticZenRule_fromUserFromSystem_allowed()9906 public void updateAutomaticZenRule_fromUserFromSystem_allowed() throws Exception { 9907 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9908 mService.isSystemUid = true; 9909 9910 mBinderService.updateAutomaticZenRule("id", SOME_ZEN_RULE, /* fromUser= */ true); 9911 9912 verify(zenModeHelper).updateAutomaticZenRule(eq("id"), eq(SOME_ZEN_RULE), 9913 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyString(), anyInt()); 9914 } 9915 9916 @Test 9917 @EnableFlags(android.app.Flags.FLAG_MODES_API) updateAutomaticZenRule_fromUserFromApp_blocked()9918 public void updateAutomaticZenRule_fromUserFromApp_blocked() throws Exception { 9919 setUpMockZenTest(); 9920 mService.setCallerIsNormalPackage(); 9921 9922 assertThrows(SecurityException.class, () -> 9923 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true)); 9924 } 9925 9926 @Test 9927 @EnableFlags(android.app.Flags.FLAG_MODES_API) removeAutomaticZenRule_fromUserFromSystem_allowed()9928 public void removeAutomaticZenRule_fromUserFromSystem_allowed() throws Exception { 9929 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9930 mService.isSystemUid = true; 9931 9932 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true); 9933 9934 verify(zenModeHelper).removeAutomaticZenRule(eq("id"), 9935 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyString(), anyInt()); 9936 } 9937 9938 @Test 9939 @EnableFlags(android.app.Flags.FLAG_MODES_API) removeAutomaticZenRule_fromUserFromApp_blocked()9940 public void removeAutomaticZenRule_fromUserFromApp_blocked() throws Exception { 9941 setUpMockZenTest(); 9942 mService.setCallerIsNormalPackage(); 9943 9944 assertThrows(SecurityException.class, () -> 9945 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true)); 9946 } 9947 9948 @Test 9949 @EnableFlags(android.app.Flags.FLAG_MODES_API) setAutomaticZenRuleState_conditionFromUser_mappedToOriginUser()9950 public void setAutomaticZenRuleState_conditionFromUser_mappedToOriginUser() throws Exception { 9951 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9952 mService.setCallerIsNormalPackage(); 9953 9954 Condition withSourceUser = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 9955 SOURCE_USER_ACTION); 9956 mBinderService.setAutomaticZenRuleState("id", withSourceUser); 9957 9958 verify(zenModeHelper).setAutomaticZenRuleState(eq("id"), eq(withSourceUser), 9959 eq(ZenModeConfig.UPDATE_ORIGIN_USER), anyInt()); 9960 } 9961 9962 @Test 9963 @EnableFlags(android.app.Flags.FLAG_MODES_API) setAutomaticZenRuleState_fromAppWithConditionNotFromUser_mappedToOriginApp()9964 public void setAutomaticZenRuleState_fromAppWithConditionNotFromUser_mappedToOriginApp() 9965 throws Exception { 9966 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9967 mService.setCallerIsNormalPackage(); 9968 9969 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 9970 SOURCE_CONTEXT); 9971 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 9972 9973 verify(zenModeHelper).setAutomaticZenRuleState(eq("id"), eq(withSourceContext), 9974 eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyInt()); 9975 } 9976 9977 @Test 9978 @EnableFlags(android.app.Flags.FLAG_MODES_API) setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_mappedToOriginSystem()9979 public void setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_mappedToOriginSystem() 9980 throws Exception { 9981 ZenModeHelper zenModeHelper = setUpMockZenTest(); 9982 mService.isSystemUid = true; 9983 9984 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 9985 SOURCE_CONTEXT); 9986 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 9987 9988 verify(zenModeHelper).setAutomaticZenRuleState(eq("id"), eq(withSourceContext), 9989 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyInt()); 9990 } 9991 9992 /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */ setUpMockZenTest()9993 private ZenModeHelper setUpMockZenTest() { 9994 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 9995 mService.setZenHelper(zenModeHelper); 9996 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 9997 .thenReturn(true); 9998 return zenModeHelper; 9999 } 10000 10001 @Test onZenModeChanged_sendsBroadcasts()10002 public void onZenModeChanged_sendsBroadcasts() throws Exception { 10003 when(mAmi.getCurrentUserId()).thenReturn(100); 10004 when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102}); 10005 when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() { 10006 @Override 10007 public List<String> answer(InvocationOnMock invocation) { 10008 int userId = invocation.getArgument(0); 10009 switch (userId) { 10010 case 100: 10011 return Lists.newArrayList("a", "b", "c"); 10012 case 101: 10013 return Lists.newArrayList(); 10014 case 102: 10015 return Lists.newArrayList("b"); 10016 default: 10017 throw new IllegalArgumentException( 10018 "Why would you ask for packages of userId " + userId + "?"); 10019 } 10020 } 10021 }); 10022 10023 mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null, 10024 "testing!", false); 10025 waitForIdle(); 10026 10027 InOrder inOrder = inOrder(mContext); 10028 // Verify broadcasts for registered receivers 10029 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 10030 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 10031 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null)); 10032 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 10033 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 10034 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null)); 10035 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 10036 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 10037 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null)); 10038 10039 // Verify broadcast for packages that manage DND. 10040 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 10041 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags( 10042 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 10043 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 10044 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( 10045 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 10046 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 10047 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags( 10048 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 10049 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 10050 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( 10051 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102))); 10052 } 10053 eqIntent(Intent wanted)10054 private static Intent eqIntent(Intent wanted) { 10055 return ArgumentMatchers.argThat( 10056 new ArgumentMatcher<Intent>() { 10057 @Override 10058 public boolean matches(Intent argument) { 10059 return wanted.filterEquals(argument) 10060 && wanted.getFlags() == argument.getFlags(); 10061 } 10062 10063 @Override 10064 public String toString() { 10065 return wanted.toString(); 10066 } 10067 }); 10068 } 10069 10070 @Test 10071 public void testAreNotificationsEnabledForPackage() throws Exception { 10072 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 10073 mUid); 10074 10075 verify(mPermissionHelper).hasPermission(mUid); 10076 } 10077 10078 @Test 10079 public void testAreNotificationsEnabledForPackage_crossUser() throws Exception { 10080 try { 10081 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 10082 mUid + UserHandle.PER_USER_RANGE); 10083 fail("Cannot call cross user without permission"); 10084 } catch (SecurityException e) { 10085 // pass 10086 } 10087 verify(mPermissionHelper, never()).hasPermission(anyInt()); 10088 10089 // cross user, with permission, no problem 10090 enableInteractAcrossUsers(); 10091 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 10092 mUid + UserHandle.PER_USER_RANGE); 10093 10094 verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE); 10095 } 10096 10097 @Test 10098 public void testAreNotificationsEnabledForPackage_viaInternalService() { 10099 mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid); 10100 verify(mPermissionHelper).hasPermission(mUid); 10101 } 10102 10103 @Test 10104 public void testGetPackageImportance() throws Exception { 10105 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 10106 assertThat(mBinderService.getPackageImportance(mContext.getPackageName())) 10107 .isEqualTo(IMPORTANCE_DEFAULT); 10108 10109 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 10110 assertThat(mBinderService.getPackageImportance(mContext.getPackageName())) 10111 .isEqualTo(IMPORTANCE_NONE); 10112 } 10113 10114 @Test 10115 public void testAreBubblesAllowedForPackage_crossUser() throws Exception { 10116 try { 10117 mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), 10118 mUid + UserHandle.PER_USER_RANGE); 10119 fail("Cannot call cross user without permission"); 10120 } catch (SecurityException e) { 10121 // pass 10122 } 10123 10124 // cross user, with permission, no problem 10125 enableInteractAcrossUsers(); 10126 mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), 10127 mUid + UserHandle.PER_USER_RANGE); 10128 } 10129 10130 private void enableInteractAcrossUsers() { 10131 TestablePermissions perms = mContext.getTestablePermissions(); 10132 perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); 10133 } 10134 10135 @Test 10136 public void testNotificationBubbleChanged_false() throws Exception { 10137 setUpPrefsForBubbles(mPkg, mUid, 10138 true /* global */, 10139 BUBBLE_PREFERENCE_ALL /* app */, 10140 true /* channel */); 10141 10142 // Notif with bubble metadata 10143 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10144 "testNotificationBubbleChanged_false"); 10145 10146 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10147 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10148 waitForIdle(); 10149 10150 // Reset as this is called when the notif is first sent 10151 reset(mListeners); 10152 10153 // First we were a bubble 10154 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 10155 assertEquals(1, notifsBefore.length); 10156 assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0); 10157 10158 // Notify we're not a bubble 10159 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 10160 waitForIdle(); 10161 10162 // Make sure we are not a bubble 10163 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 10164 assertEquals(1, notifsAfter.length); 10165 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 10166 } 10167 10168 @Test 10169 public void testNotificationBubbleChanged_true() throws Exception { 10170 setUpPrefsForBubbles(mPkg, mUid, 10171 true /* global */, 10172 BUBBLE_PREFERENCE_ALL /* app */, 10173 true /* channel */); 10174 10175 // Notif that is not a bubble 10176 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 10177 1, null, false); 10178 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10179 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10180 waitForIdle(); 10181 10182 // Would be a normal notification because wouldn't have met requirements to bubble 10183 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 10184 assertEquals(1, notifsBefore.length); 10185 assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0); 10186 10187 // Update the notification to be message style / meet bubble requirements 10188 NotificationRecord nr2 = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10189 nr.getSbn().getTag()); 10190 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr2.getSbn().getTag(), 10191 nr2.getSbn().getId(), nr2.getSbn().getNotification(), nr2.getSbn().getUserId()); 10192 waitForIdle(); 10193 10194 // Reset as this is called when the notif is first sent 10195 reset(mListeners); 10196 10197 // Notify we are now a bubble 10198 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 10199 waitForIdle(); 10200 10201 // Make sure we are a bubble 10202 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 10203 assertEquals(1, notifsAfter.length); 10204 assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0); 10205 } 10206 10207 @Test 10208 public void testNotificationBubbleChanged_true_notAllowed() throws Exception { 10209 setUpPrefsForBubbles(mPkg, mUid, 10210 true /* global */, 10211 BUBBLE_PREFERENCE_ALL /* app */, 10212 true /* channel */); 10213 10214 // Notif that is not a bubble 10215 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10216 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10217 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10218 waitForIdle(); 10219 10220 // Reset as this is called when the notif is first sent 10221 reset(mListeners); 10222 10223 // Would be a normal notification because wouldn't have met requirements to bubble 10224 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 10225 assertEquals(1, notifsBefore.length); 10226 assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0); 10227 10228 // Notify we are now a bubble 10229 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 10230 waitForIdle(); 10231 10232 // We still wouldn't be a bubble because the notification didn't meet requirements 10233 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 10234 assertEquals(1, notifsAfter.length); 10235 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 10236 } 10237 10238 @Test 10239 public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception { 10240 setUpPrefsForBubbles(mPkg, mUid, 10241 true /* global */, 10242 BUBBLE_PREFERENCE_ALL /* app */, 10243 true /* channel */); 10244 10245 // Notif with bubble metadata 10246 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10247 "testNotificationBubbleIsFlagRemoved_resetOnUpdate"); 10248 10249 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10250 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10251 waitForIdle(); 10252 // Flag shouldn't be modified 10253 NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 10254 assertFalse(recordToCheck.isFlagBubbleRemoved()); 10255 10256 // Notify we're not a bubble 10257 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 10258 waitForIdle(); 10259 // Flag should be modified 10260 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 10261 assertTrue(recordToCheck.isFlagBubbleRemoved()); 10262 10263 10264 // Update the notif 10265 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10266 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10267 waitForIdle(); 10268 // And the flag is reset 10269 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 10270 assertFalse(recordToCheck.isFlagBubbleRemoved()); 10271 } 10272 10273 @Test 10274 public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception { 10275 setUpPrefsForBubbles(mPkg, mUid, 10276 true /* global */, 10277 BUBBLE_PREFERENCE_ALL /* app */, 10278 true /* channel */); 10279 10280 // Notif with bubble metadata 10281 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10282 "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue"); 10283 10284 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10285 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10286 waitForIdle(); 10287 // Flag shouldn't be modified 10288 NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 10289 assertFalse(recordToCheck.isFlagBubbleRemoved()); 10290 10291 // Notify we're not a bubble 10292 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 10293 waitForIdle(); 10294 // Flag should be modified 10295 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 10296 assertTrue(recordToCheck.isFlagBubbleRemoved()); 10297 10298 // Notify we are a bubble 10299 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 10300 waitForIdle(); 10301 // And the flag is reset 10302 assertFalse(recordToCheck.isFlagBubbleRemoved()); 10303 } 10304 10305 @Test 10306 public void testOnBubbleMetadataFlagChanged() throws Exception { 10307 setUpPrefsForBubbles(mPkg, mUid, 10308 true /* global */, 10309 BUBBLE_PREFERENCE_ALL /* app */, 10310 true /* channel */); 10311 10312 // Post a bubble notification 10313 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 10314 // Set this so that the bubble can be suppressed 10315 nr.getNotification().getBubbleMetadata().setFlags( 10316 Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE); 10317 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10318 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10319 waitForIdle(); 10320 10321 // Check the flags 10322 Notification n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 10323 assertFalse(n.getBubbleMetadata().isNotificationSuppressed()); 10324 assertFalse(n.getBubbleMetadata().getAutoExpandBubble()); 10325 assertFalse(n.getBubbleMetadata().isBubbleSuppressed()); 10326 assertTrue(n.getBubbleMetadata().isBubbleSuppressable()); 10327 10328 // Reset as this is called when the notif is first sent 10329 reset(mListeners); 10330 10331 // Test: change the flags 10332 int flags = Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE; 10333 flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; 10334 flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 10335 flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; 10336 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), flags); 10337 waitForIdle(); 10338 10339 // Check 10340 n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 10341 assertEquals(flags, n.getBubbleMetadata().getFlags()); 10342 10343 // Reset to check again 10344 reset(mListeners); 10345 10346 // Test: clear flags 10347 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 0); 10348 waitForIdle(); 10349 10350 // Check 10351 n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 10352 assertEquals(0, n.getBubbleMetadata().getFlags()); 10353 } 10354 10355 @Test 10356 public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped() 10357 throws RemoteException { 10358 10359 setUpPrefsForBubbles(mPkg, mUid, 10360 true /* global */, 10361 BUBBLE_PREFERENCE_ALL /* app */, 10362 true /* channel */); 10363 10364 // Post a bubble notification 10365 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 10366 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10367 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10368 waitForIdle(); 10369 10370 // Test: suppress notification via bubble metadata update 10371 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 10372 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 10373 waitForIdle(); 10374 10375 // Check audio is stopped 10376 verify(mAttentionHelper).clearEffectsLocked(nr.getKey()); 10377 } 10378 10379 @Test 10380 public void testGrantInlineReplyUriPermission_recordExists() throws Exception { 10381 int userId = UserManager.isHeadlessSystemUserMode() 10382 ? UserHandle.getUserId(UID_HEADLESS) 10383 : USER_SYSTEM; 10384 10385 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 10386 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 10387 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10388 waitForIdle(); 10389 10390 // A notification exists for the given record 10391 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 10392 assertEquals(1, notifsBefore.length); 10393 10394 reset(mPackageManager); 10395 10396 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 10397 10398 mService.mNotificationDelegate.grantInlineReplyUriPermission( 10399 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 10400 nr.getSbn().getUid()); 10401 10402 // Grant permission called for the UID of SystemUI under the target user ID 10403 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 10404 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 10405 anyInt(), eq(nr.getSbn().getUserId())); 10406 } 10407 10408 @Test 10409 public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception { 10410 int userId = UserManager.isHeadlessSystemUserMode() 10411 ? UserHandle.getUserId(UID_HEADLESS) 10412 : USER_SYSTEM; 10413 10414 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 10415 waitForIdle(); 10416 10417 // No notifications exist for the given record 10418 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 10419 assertEquals(0, notifsBefore.length); 10420 10421 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 10422 10423 mService.mNotificationDelegate.grantInlineReplyUriPermission( 10424 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 10425 nr.getSbn().getUid()); 10426 10427 // Grant permission still called if no NotificationRecord exists for the given key 10428 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 10429 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 10430 anyInt(), eq(nr.getSbn().getUserId())); 10431 } 10432 10433 @Test 10434 public void testGrantInlineReplyUriPermission_userAll() throws Exception { 10435 // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM 10436 NotificationRecord nr = 10437 generateNotificationRecord(mTestNotificationChannel, UserHandle.USER_ALL); 10438 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 10439 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10440 waitForIdle(); 10441 10442 // A notification exists for the given record 10443 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 10444 assertEquals(1, notifsBefore.length); 10445 10446 reset(mPackageManager); 10447 10448 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 10449 10450 mService.mNotificationDelegate.grantInlineReplyUriPermission( 10451 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 10452 nr.getSbn().getUid()); 10453 10454 // Target user for the grant is USER_ALL instead of USER_SYSTEM 10455 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 10456 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 10457 anyInt(), UserManager.isHeadlessSystemUserMode() 10458 ? eq(UserHandle.getUserId(UID_HEADLESS)) 10459 : eq(USER_SYSTEM)); 10460 } 10461 10462 @Test 10463 public void testGrantInlineReplyUriPermission_acrossUsers() throws Exception { 10464 // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM 10465 int otherUserId = 11; 10466 NotificationRecord nr = 10467 generateNotificationRecord(mTestNotificationChannel, otherUserId); 10468 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 10469 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10470 waitForIdle(); 10471 10472 // A notification exists for the given record 10473 List<StatusBarNotification> notifsBefore = 10474 mBinderService.getAppActiveNotifications(mPkg, nr.getSbn().getUserId()).getList(); 10475 assertEquals(1, notifsBefore.size()); 10476 10477 reset(mPackageManager); 10478 10479 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 10480 10481 int uid = 0; // sysui on primary user 10482 int otherUserUid = (otherUserId * 100000) + 1; // sysui as a different user 10483 String sysuiPackage = "sysui"; 10484 final String[] sysuiPackages = new String[] { sysuiPackage }; 10485 when(mPackageManager.getPackagesForUid(uid)).thenReturn(sysuiPackages); 10486 10487 // Make sure to mock call for USER_SYSTEM and not USER_ALL, since it's been replaced by the 10488 // time this is called 10489 when(mPackageManager.getPackageUid(sysuiPackage, 0, otherUserId)) 10490 .thenReturn(otherUserUid); 10491 10492 mService.mNotificationDelegate.grantInlineReplyUriPermission( 10493 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), uid); 10494 10495 // Target user for the grant is USER_ALL instead of USER_SYSTEM 10496 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 10497 eq(otherUserUid), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), anyInt(), 10498 eq(otherUserId)); 10499 } 10500 10501 @Test 10502 public void testClearInlineReplyUriPermission_uriRecordExists() throws Exception { 10503 int userId = UserManager.isHeadlessSystemUserMode() 10504 ? UserHandle.getUserId(UID_HEADLESS) 10505 : USER_SYSTEM; 10506 10507 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 10508 reset(mPackageManager); 10509 10510 Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 10511 Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2); 10512 10513 // create an inline record with two uris in it 10514 mService.mNotificationDelegate.grantInlineReplyUriPermission( 10515 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 10516 nr.getSbn().getUid()); 10517 mService.mNotificationDelegate.grantInlineReplyUriPermission( 10518 nr.getKey(), uri2, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 10519 nr.getSbn().getUid()); 10520 10521 InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey()); 10522 assertNotNull(record); // record exists 10523 assertEquals(record.getUris().size(), 2); // record has two uris in it 10524 10525 mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), 10526 nr.getSbn().getUid()); 10527 10528 // permissionOwner destroyed 10529 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner( 10530 eq(record.getPermissionOwner()), eq(null), eq(~0), eq(nr.getUserId())); 10531 } 10532 10533 10534 @Test 10535 public void testClearInlineReplyUriPermission_noUriRecordExists() throws Exception { 10536 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0); 10537 reset(mPackageManager); 10538 10539 mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), 10540 nr.getSbn().getUid()); 10541 10542 // no permissionOwner destroyed 10543 verify(mUgmInternal, times(0)).revokeUriPermissionFromOwner( 10544 any(), eq(null), eq(~0), eq(nr.getUserId())); 10545 } 10546 10547 @Test 10548 public void testClearInlineReplyUriPermission_userAll() throws Exception { 10549 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 10550 UserHandle.USER_ALL); 10551 reset(mPackageManager); 10552 10553 Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 10554 10555 // create an inline record a uri in it 10556 mService.mNotificationDelegate.grantInlineReplyUriPermission( 10557 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 10558 nr.getSbn().getUid()); 10559 10560 InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey()); 10561 assertNotNull(record); // record exists 10562 10563 mService.mNotificationDelegate.clearInlineReplyUriPermissions( 10564 nr.getKey(), nr.getSbn().getUid()); 10565 10566 // permissionOwner destroyed for USER_SYSTEM, not USER_ALL 10567 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner( 10568 eq(record.getPermissionOwner()), eq(null), eq(~0), 10569 UserManager.isHeadlessSystemUserMode() 10570 ? eq(UserHandle.getUserId(UID_HEADLESS)) 10571 : eq(USER_SYSTEM)); 10572 } 10573 10574 @Test 10575 public void testNotificationBubbles_disabled_lowRamDevice() throws Exception { 10576 setUpPrefsForBubbles(mPkg, mUid, 10577 true /* global */, 10578 BUBBLE_PREFERENCE_ALL /* app */, 10579 true /* channel */); 10580 10581 // And we are low ram 10582 when(mActivityManager.isLowRamDevice()).thenReturn(true); 10583 10584 // Notification that would typically bubble 10585 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10586 "testNotificationBubbles_disabled_lowRamDevice"); 10587 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10588 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10589 waitForIdle(); 10590 10591 // But we wouldn't be a bubble because the device is low ram & all bubbles are disabled. 10592 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 10593 assertEquals(1, notifsAfter.length); 10594 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 10595 } 10596 10597 @Test 10598 @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS) 10599 public void testRemoveLargeRemoteViews() throws Exception { 10600 int removeSize = mContext.getResources().getInteger( 10601 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); 10602 10603 RemoteViews rv = mock(RemoteViews.class); 10604 when(rv.estimateMemoryUsage()).thenReturn(removeSize); 10605 when(rv.clone()).thenReturn(rv); 10606 RemoteViews rv1 = mock(RemoteViews.class); 10607 when(rv1.estimateMemoryUsage()).thenReturn(removeSize); 10608 when(rv1.clone()).thenReturn(rv1); 10609 RemoteViews rv2 = mock(RemoteViews.class); 10610 when(rv2.estimateMemoryUsage()).thenReturn(removeSize); 10611 when(rv2.clone()).thenReturn(rv2); 10612 RemoteViews rv3 = mock(RemoteViews.class); 10613 when(rv3.estimateMemoryUsage()).thenReturn(removeSize); 10614 when(rv3.clone()).thenReturn(rv3); 10615 RemoteViews rv4 = mock(RemoteViews.class); 10616 when(rv4.estimateMemoryUsage()).thenReturn(removeSize); 10617 when(rv4.clone()).thenReturn(rv4); 10618 // note: different! 10619 RemoteViews rv5 = mock(RemoteViews.class); 10620 when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1); 10621 when(rv5.clone()).thenReturn(rv5); 10622 10623 Notification np = new Notification.Builder(mContext, "test") 10624 .setSmallIcon(android.R.drawable.sym_def_app_icon) 10625 .setContentText("test") 10626 .setCustomContentView(rv) 10627 .setCustomBigContentView(rv1) 10628 .setCustomHeadsUpContentView(rv2) 10629 .build(); 10630 Notification n = new Notification.Builder(mContext, "test") 10631 .setSmallIcon(android.R.drawable.sym_def_app_icon) 10632 .setContentText("test") 10633 .setCustomContentView(rv3) 10634 .setCustomBigContentView(rv4) 10635 .setCustomHeadsUpContentView(rv5) 10636 .setPublicVersion(np) 10637 .build(); 10638 10639 assertNotNull(np.contentView); 10640 assertNotNull(np.bigContentView); 10641 assertNotNull(np.headsUpContentView); 10642 10643 assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); 10644 assertNotNull(n.publicVersion.contentView); 10645 assertNotNull(n.publicVersion.bigContentView); 10646 assertNotNull(n.publicVersion.headsUpContentView); 10647 10648 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 10649 10650 assertNull(n.contentView); 10651 assertNull(n.bigContentView); 10652 assertNotNull(n.headsUpContentView); 10653 assertNull(n.publicVersion.contentView); 10654 assertNull(n.publicVersion.bigContentView); 10655 assertNull(n.publicVersion.headsUpContentView); 10656 10657 verify(mUsageStats, times(5)).registerImageRemoved(mPkg); 10658 } 10659 10660 @Test 10661 @EnableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS) 10662 public void testRemoveRemoteViews() throws Exception { 10663 Notification np = new Notification.Builder(mContext, "test") 10664 .setSmallIcon(android.R.drawable.sym_def_app_icon) 10665 .setContentText("test") 10666 .setCustomContentView(mock(RemoteViews.class)) 10667 .setCustomBigContentView(mock(RemoteViews.class)) 10668 .setCustomHeadsUpContentView(mock(RemoteViews.class)) 10669 .build(); 10670 Notification n = new Notification.Builder(mContext, "test") 10671 .setSmallIcon(android.R.drawable.sym_def_app_icon) 10672 .setContentText("test") 10673 .setCustomContentView(mock(RemoteViews.class)) 10674 .setCustomBigContentView(mock(RemoteViews.class)) 10675 .setCustomHeadsUpContentView(mock(RemoteViews.class)) 10676 .setPublicVersion(np) 10677 .build(); 10678 10679 assertNotNull(n.contentView); 10680 assertNotNull(n.bigContentView); 10681 assertNotNull(n.headsUpContentView); 10682 10683 assertTrue(np.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); 10684 assertNotNull(np.contentView); 10685 assertNotNull(np.bigContentView); 10686 assertNotNull(np.headsUpContentView); 10687 10688 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 10689 10690 assertNull(n.contentView); 10691 assertNull(n.bigContentView); 10692 assertNull(n.headsUpContentView); 10693 assertNull(n.publicVersion.contentView); 10694 assertNull(n.publicVersion.bigContentView); 10695 assertNull(n.publicVersion.headsUpContentView); 10696 10697 verify(mUsageStats, times(1)).registerImageRemoved(mPkg); 10698 } 10699 10700 @Test 10701 public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground() 10702 throws Exception { 10703 setUpPrefsForBubbles(mPkg, mUid, 10704 true /* global */, 10705 BUBBLE_PREFERENCE_ALL /* app */, 10706 true /* channel */); 10707 10708 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10709 "testNotificationBubbles_flagAutoExpandForeground_fails_notForeground"); 10710 // Modify metadata flags 10711 nr.getSbn().getNotification().getBubbleMetadata().setFlags( 10712 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE 10713 | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 10714 10715 // Ensure we're not foreground 10716 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 10717 IMPORTANCE_VISIBLE); 10718 10719 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10720 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10721 waitForIdle(); 10722 10723 // yes allowed, yes messaging, yes bubble 10724 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 10725 assertTrue(notif.isBubbleNotification()); 10726 10727 // The flag should have failed since we're not foreground 10728 assertFalse(notif.getBubbleMetadata().getAutoExpandBubble()); 10729 } 10730 10731 @Test 10732 public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground() 10733 throws RemoteException { 10734 setUpPrefsForBubbles(mPkg, mUid, 10735 true /* global */, 10736 BUBBLE_PREFERENCE_ALL /* app */, 10737 true /* channel */); 10738 10739 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10740 "testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground"); 10741 // Modify metadata flags 10742 nr.getSbn().getNotification().getBubbleMetadata().setFlags( 10743 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE 10744 | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 10745 10746 // Ensure we are in the foreground 10747 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 10748 IMPORTANCE_FOREGROUND); 10749 10750 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10751 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10752 waitForIdle(); 10753 10754 // yes allowed, yes messaging, yes bubble 10755 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 10756 assertTrue(notif.isBubbleNotification()); 10757 10758 // Our flags should have passed since we are foreground 10759 assertTrue(notif.getBubbleMetadata().getAutoExpandBubble()); 10760 assertTrue(notif.getBubbleMetadata().isNotificationSuppressed()); 10761 } 10762 10763 @Test 10764 public void testNotificationBubbles_flagRemoved_whenShortcutRemoved() 10765 throws RemoteException { 10766 setUpPrefsForBubbles(mPkg, mUid, 10767 true /* global */, 10768 BUBBLE_PREFERENCE_ALL /* app */, 10769 true /* channel */); 10770 10771 ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback = 10772 ArgumentCaptor.forClass(LauncherApps.Callback.class); 10773 10774 // Messaging notification with shortcut info 10775 Notification.BubbleMetadata metadata = 10776 new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build(); 10777 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 10778 null /* groupKey */, false /* isSummary */, true); 10779 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 10780 nb.setBubbleMetadata(metadata); 10781 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 10782 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10783 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10784 10785 // Test: Send the bubble notification 10786 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10787 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10788 waitForIdle(); 10789 10790 // Verify: 10791 10792 // Make sure we register the callback for shortcut changes 10793 verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any()); 10794 10795 // yes allowed, yes messaging w/shortcut, yes bubble 10796 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 10797 assertTrue(notif.isBubbleNotification()); 10798 10799 // Make sure the shortcut is cached. 10800 verify(mShortcutServiceInternal).cacheShortcuts( 10801 anyInt(), any(), eq(mPkg), eq(singletonList(VALID_CONVO_SHORTCUT_ID)), 10802 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); 10803 10804 // Test: Remove the shortcut 10805 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 10806 launcherAppsCallback.getValue().onShortcutsChanged(mPkg, emptyList(), 10807 UserHandle.getUserHandleForUid(mUid)); 10808 waitForIdle(); 10809 10810 // Verify: 10811 10812 // Make sure callback is unregistered 10813 verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); 10814 10815 // We're no longer a bubble 10816 NotificationRecord notif2 = mService.getNotificationRecord( 10817 nr.getSbn().getKey()); 10818 assertNull(notif2.getShortcutInfo()); 10819 assertFalse(notif2.getNotification().isBubbleNotification()); 10820 } 10821 10822 @Test 10823 public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved() 10824 throws RemoteException { 10825 final String shortcutId = "someshortcutId"; 10826 setUpPrefsForBubbles(mPkg, mUid, 10827 true /* global */, 10828 BUBBLE_PREFERENCE_ALL /* app */, 10829 true /* channel */); 10830 10831 ArgumentCaptor<LauncherApps.Callback> launcherAppsCallback = 10832 ArgumentCaptor.forClass(LauncherApps.Callback.class); 10833 10834 // Messaging notification with shortcut info 10835 Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder( 10836 shortcutId).build(); 10837 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 10838 null /* groupKey */, false /* isSummary */, true); 10839 nb.setShortcutId(shortcutId); 10840 nb.setBubbleMetadata(metadata); 10841 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 10842 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10843 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10844 10845 // Pretend the shortcut exists 10846 List<ShortcutInfo> shortcutInfos = new ArrayList<>(); 10847 ShortcutInfo info = mock(ShortcutInfo.class); 10848 when(info.getPackage()).thenReturn(mPkg); 10849 when(info.getId()).thenReturn(shortcutId); 10850 when(info.getUserId()).thenReturn(USER_SYSTEM); 10851 when(info.isLongLived()).thenReturn(true); 10852 when(info.isEnabled()).thenReturn(true); 10853 shortcutInfos.add(info); 10854 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); 10855 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 10856 anyString(), anyInt(), any())).thenReturn(true); 10857 10858 // Test: Send the bubble notification 10859 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10860 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10861 waitForIdle(); 10862 10863 // Verify: 10864 10865 // Make sure we register the callback for shortcut changes 10866 verify(mLauncherApps, times(1)).registerCallback(launcherAppsCallback.capture(), any()); 10867 10868 // yes allowed, yes messaging w/shortcut, yes bubble 10869 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 10870 assertTrue(notif.isBubbleNotification()); 10871 10872 // Make sure the shortcut is cached. 10873 verify(mShortcutServiceInternal).cacheShortcuts( 10874 anyInt(), any(), eq(mPkg), eq(singletonList(shortcutId)), 10875 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); 10876 10877 // Test: Remove the notification 10878 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10879 nr.getSbn().getId(), nr.getSbn().getUserId()); 10880 waitForIdle(); 10881 10882 // Verify: 10883 10884 // Make sure callback is unregistered 10885 verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); 10886 } 10887 10888 @Test 10889 public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed() 10890 throws Exception { 10891 setUpPrefsForBubbles(mPkg, mUid, 10892 true /* global */, 10893 BUBBLE_PREFERENCE_ALL /* app */, 10894 true /* channel */); 10895 10896 NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( 10897 true /* summaryAutoCancel */); 10898 10899 // Dismiss summary 10900 final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, 10901 true); 10902 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, 10903 nrSummary.getUserId(), nrSummary.getKey(), 10904 NotificationStats.DISMISSAL_SHADE, 10905 NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv); 10906 waitForIdle(); 10907 10908 // The bubble should still exist 10909 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 10910 assertEquals(1, notifsAfter.length); 10911 } 10912 10913 @Test 10914 public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked() 10915 throws Exception { 10916 setUpPrefsForBubbles(mPkg, mUid, 10917 true /* global */, 10918 BUBBLE_PREFERENCE_ALL /* app */, 10919 true /* channel */); 10920 10921 NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( 10922 true /* summaryAutoCancel */); 10923 10924 // Click summary 10925 final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, 10926 true); 10927 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 10928 nrSummary.getKey(), nv); 10929 waitForIdle(); 10930 10931 // The bubble should still exist 10932 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 10933 assertEquals(1, notifsAfter.length); 10934 10935 // Check we got the click log and associated dismissal logs 10936 assertEquals(6, mNotificationRecordLogger.numCalls()); 10937 // Skip the notification-creation logs 10938 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 10939 mNotificationRecordLogger.event(3)); 10940 assertEquals(NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK, 10941 mNotificationRecordLogger.event(4)); 10942 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 10943 .NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED, 10944 mNotificationRecordLogger.event(5)); 10945 } 10946 10947 @Test 10948 public void testNotificationBubbles_bubbleStays_whenClicked() 10949 throws Exception { 10950 setUpPrefsForBubbles(mPkg, mUid, 10951 true /* global */, 10952 BUBBLE_PREFERENCE_ALL /* app */, 10953 true /* channel */); 10954 10955 // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble 10956 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10957 nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL; 10958 mService.addNotification(nr); 10959 10960 // WHEN we click the notification 10961 final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true); 10962 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 10963 nr.getKey(), nv); 10964 waitForIdle(); 10965 10966 // THEN the bubble should still exist 10967 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 10968 assertEquals(1, notifsAfter.length); 10969 10970 // Check we got the click log 10971 assertEquals(1, mNotificationRecordLogger.numCalls()); 10972 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 10973 mNotificationRecordLogger.event(0)); 10974 } 10975 10976 /** 10977 * When something is bubble'd and the bubble is dismissed, but the notification is still 10978 * visible, clicking on the notification shouldn't auto-cancel it because clicking on 10979 * it will produce a bubble. 10980 */ 10981 @Test 10982 public void testNotificationBubbles_bubbleStays_whenClicked_afterBubbleDismissed() 10983 throws Exception { 10984 setUpPrefsForBubbles(mPkg, mUid, 10985 true /* global */, 10986 BUBBLE_PREFERENCE_ALL /* app */, 10987 true /* channel */); 10988 10989 // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble 10990 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10991 nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL; 10992 nr.setAllowBubble(true); 10993 mService.addNotification(nr); 10994 10995 // And the bubble is dismissed 10996 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), 10997 false /* isBubble */, 0 /* bubbleFlags */); 10998 waitForIdle(); 10999 assertTrue(nr.isFlagBubbleRemoved()); 11000 11001 // WHEN we click the notification 11002 final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true); 11003 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 11004 nr.getKey(), nv); 11005 waitForIdle(); 11006 11007 // THEN the bubble should still exist 11008 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11009 assertEquals(1, notifsAfter.length); 11010 11011 // Check we got the click log 11012 assertEquals(1, mNotificationRecordLogger.numCalls()); 11013 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 11014 mNotificationRecordLogger.event(0)); 11015 } 11016 11017 @Test 11018 public void testLoadDefaultApprovedServices_emptyResources() { 11019 TestableResources tr = mContext.getOrCreateTestableResources(); 11020 tr.addOverride(com.android.internal.R.string.config_defaultListenerAccessPackages, ""); 11021 tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, ""); 11022 tr.addOverride(com.android.internal.R.string.config_defaultAssistantAccessComponent, ""); 11023 11024 mService.loadDefaultApprovedServices(USER_SYSTEM); 11025 11026 verify(mListeners, never()).addDefaultComponentOrPackage(anyString()); 11027 verify(mConditionProviders, never()).addDefaultComponentOrPackage(anyString()); 11028 verify(mAssistants, never()).addDefaultComponentOrPackage(anyString()); 11029 } 11030 11031 @Test 11032 public void testLoadDefaultApprovedServices_dnd() { 11033 TestableResources tr = mContext.getOrCreateTestableResources(); 11034 tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "test"); 11035 when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt())) 11036 .thenReturn(new ArraySet<>()); 11037 11038 mService.loadDefaultApprovedServices(USER_SYSTEM); 11039 11040 verify(mConditionProviders, times(1)).loadDefaultsFromConfig(); 11041 } 11042 11043 // TODO: add tests for the rest of the non-empty cases 11044 11045 @Test 11046 public void testOnUnlockUser() { 11047 UserInfo ui = new UserInfo(); 11048 ui.id = 10; 11049 mService.onUserUnlocked(new TargetUser(ui)); 11050 waitForIdle(); 11051 11052 verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id); 11053 } 11054 11055 @Test 11056 public void testOnStopUser() { 11057 UserInfo ui = new UserInfo(); 11058 ui.id = 10; 11059 mService.onUserStopping(new TargetUser(ui)); 11060 waitForIdle(); 11061 11062 verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id); 11063 } 11064 11065 @Test 11066 public void testHandleOnPackageChanged() { 11067 String[] pkgs = new String[] {mPkg, PKG_N_MR1}; 11068 int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1}; 11069 11070 mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids); 11071 11072 verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString()); 11073 11074 mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids); 11075 11076 verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]); 11077 verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]); 11078 } 11079 11080 @Test 11081 public void testHandleOnPackageRemoved_ClearsHistory() throws Exception { 11082 // Enables Notification History setting 11083 setUpPrefsForHistory(mUserId, true /* =enabled */); 11084 11085 // Posts a notification to the mTestNotificationChannel. 11086 final NotificationRecord notif = generateNotificationRecord( 11087 mTestNotificationChannel, 1, null, false); 11088 mService.addNotification(notif); 11089 StatusBarNotification[] notifs = mBinderService.getActiveNotifications( 11090 notif.getSbn().getPackageName()); 11091 assertEquals(1, notifs.length); 11092 11093 // Cancels all notifications. 11094 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 11095 notif.getUserId(), REASON_CANCEL); 11096 waitForIdle(); 11097 notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 11098 assertEquals(0, notifs.length); 11099 11100 // Checks that notification history's recently canceled archive contains the notification. 11101 notifs = mBinderService.getHistoricalNotificationsWithAttribution(mPkg, 11102 mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); 11103 waitForIdle(); 11104 assertEquals(1, notifs.length); 11105 11106 // Remove sthe package that contained the channel 11107 simulatePackageRemovedBroadcast(mPkg, mUid); 11108 waitForIdle(); 11109 11110 // Checks that notification history no longer contains the notification. 11111 notifs = mBinderService.getHistoricalNotificationsWithAttribution( 11112 mPkg, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); 11113 waitForIdle(); 11114 assertEquals(0, notifs.length); 11115 } 11116 11117 @Test 11118 public void testNotificationHistory_addNoisyNotification() throws Exception { 11119 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 11120 null /* tvExtender */); 11121 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11122 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11123 waitForIdle(); 11124 11125 verify(mHistoryManager, times(1)).addNotification(any()); 11126 } 11127 11128 @Test 11129 public void createConversationNotificationChannel() throws Exception { 11130 int userId = UserManager.isHeadlessSystemUserMode() 11131 ? UserHandle.getUserId(UID_HEADLESS) 11132 : USER_SYSTEM; 11133 11134 NotificationChannel original = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 11135 original.setAllowBubbles(!original.canBubble()); 11136 original.setShowBadge(!original.canShowBadge()); 11137 11138 Parcel parcel = Parcel.obtain(); 11139 original.writeToParcel(parcel, 0); 11140 parcel.setDataPosition(0); 11141 NotificationChannel orig = NotificationChannel.CREATOR.createFromParcel(parcel); 11142 assertEquals(original, orig); 11143 assertFalse(TextUtils.isEmpty(orig.getName())); 11144 11145 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(Arrays.asList( 11146 orig))); 11147 11148 mBinderService.createConversationNotificationChannelForPackage( 11149 mPkg, mUid, orig, "friend"); 11150 11151 NotificationChannel friendChannel = mBinderService.getConversationNotificationChannel( 11152 mPkg, userId, mPkg, original.getId(), false, "friend"); 11153 11154 assertEquals(original.getName(), friendChannel.getName()); 11155 assertEquals(original.getId(), friendChannel.getParentChannelId()); 11156 assertEquals("friend", friendChannel.getConversationId()); 11157 assertEquals(null, original.getConversationId()); 11158 assertEquals(original.canShowBadge(), friendChannel.canShowBadge()); 11159 assertFalse(friendChannel.canBubble()); // can't be modified by app 11160 assertFalse(original.getId().equals(friendChannel.getId())); 11161 assertNotNull(friendChannel.getId()); 11162 } 11163 11164 @Test 11165 public void testCorrectCategory_systemOn_appCannotTurnOff() { 11166 int requested = 0; 11167 int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 11168 11169 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 11170 system); 11171 11172 assertEquals(PRIORITY_CATEGORY_CONVERSATIONS, actual); 11173 } 11174 11175 @Test 11176 public void testCorrectCategory_systemOff_appTurnOff_noChanges() { 11177 int requested = PRIORITY_CATEGORY_CALLS; 11178 int system = PRIORITY_CATEGORY_CALLS; 11179 11180 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 11181 system); 11182 11183 assertEquals(PRIORITY_CATEGORY_CALLS, actual); 11184 } 11185 11186 @Test 11187 public void testCorrectCategory_systemOn_appTurnOn_noChanges() { 11188 int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 11189 int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 11190 11191 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 11192 system); 11193 11194 assertEquals(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS, actual); 11195 } 11196 11197 @Test 11198 public void testCorrectCategory_systemOff_appCannotTurnOn() { 11199 int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 11200 int system = PRIORITY_CATEGORY_CALLS; 11201 11202 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 11203 system); 11204 11205 assertEquals(PRIORITY_CATEGORY_CALLS, actual); 11206 } 11207 11208 @Test 11209 public void testRestoreConversationChannel_deleted() throws Exception { 11210 // Create parent channel 11211 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 11212 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 11213 IMPORTANCE_DEFAULT); 11214 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 11215 NotificationChannel.CREATOR); 11216 assertEquals(originalChannel, parentChannel); 11217 mBinderService.createNotificationChannels(mPkg, 11218 new ParceledListSlice(Arrays.asList(parentChannel))); 11219 11220 //Create deleted conversation channel 11221 mBinderService.createConversationNotificationChannelForPackage( 11222 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 11223 final NotificationChannel conversationChannel = 11224 mBinderService.getConversationNotificationChannel( 11225 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 11226 conversationChannel.setDeleted(true); 11227 11228 //Create notification record 11229 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 11230 null /* groupKey */, false /* isSummary */, true); 11231 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 11232 nb.setChannelId(originalChannel.getId()); 11233 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 11234 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 11235 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 11236 assertThat(nr.getChannel()).isEqualTo(originalChannel); 11237 11238 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11239 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11240 waitForIdle(); 11241 11242 // Verify that the channel was changed to the conversation channel and restored 11243 assertThat(mService.getNotificationRecord(nr.getKey()).isConversation()).isTrue(); 11244 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 11245 conversationChannel); 11246 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().isDeleted()).isFalse(); 11247 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().getDeletedTimeMs()) 11248 .isEqualTo(-1); 11249 } 11250 11251 @Test 11252 public void testDoNotRestoreParentChannel_deleted() throws Exception { 11253 // Create parent channel and set as deleted 11254 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 11255 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 11256 IMPORTANCE_DEFAULT); 11257 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 11258 NotificationChannel.CREATOR); 11259 assertEquals(originalChannel, parentChannel); 11260 mBinderService.createNotificationChannels(mPkg, 11261 new ParceledListSlice(Arrays.asList(parentChannel))); 11262 parentChannel.setDeleted(true); 11263 11264 //Create notification record 11265 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 11266 null /* groupKey */, false /* isSummary */, true); 11267 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 11268 nb.setChannelId(originalChannel.getId()); 11269 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 11270 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 11271 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 11272 assertThat(nr.getChannel()).isEqualTo(originalChannel); 11273 11274 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 11275 11276 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11277 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11278 waitForIdle(); 11279 11280 // Verify that the channel was not restored and the notification was not posted 11281 assertThat(mService.mChannelToastsSent).contains(mUid); 11282 assertThat(mService.getNotificationRecord(nr.getKey())).isNull(); 11283 assertThat(parentChannel.isDeleted()).isTrue(); 11284 } 11285 11286 @Test 11287 public void testEnqueueToConversationChannel_notDeleted_doesNotRestore() throws Exception { 11288 TestableNotificationManagerService service = spy(mService); 11289 PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper); 11290 service.setPreferencesHelper(preferencesHelper); 11291 // Create parent channel 11292 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 11293 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 11294 IMPORTANCE_DEFAULT); 11295 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 11296 NotificationChannel.CREATOR); 11297 assertEquals(originalChannel, parentChannel); 11298 mBinderService.createNotificationChannels(mPkg, 11299 new ParceledListSlice(Arrays.asList(parentChannel))); 11300 11301 //Create conversation channel 11302 mBinderService.createConversationNotificationChannelForPackage( 11303 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 11304 final NotificationChannel conversationChannel = 11305 mBinderService.getConversationNotificationChannel( 11306 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 11307 11308 //Create notification record 11309 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 11310 null /* groupKey */, false /* isSummary */, true); 11311 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 11312 nb.setChannelId(originalChannel.getId()); 11313 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 11314 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 11315 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 11316 assertThat(nr.getChannel()).isEqualTo(originalChannel); 11317 11318 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11319 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11320 waitForIdle(); 11321 11322 // Verify that the channel was changed to the conversation channel and not restored 11323 assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isTrue(); 11324 assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 11325 conversationChannel); 11326 verify(service, never()).handleSavePolicyFile(); 11327 verify(preferencesHelper, never()).createNotificationChannel(anyString(), 11328 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()); 11329 } 11330 11331 @Test 11332 public void testEnqueueToParentChannel_notDeleted_doesNotRestore() throws Exception { 11333 TestableNotificationManagerService service = spy(mService); 11334 PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper); 11335 service.setPreferencesHelper(preferencesHelper); 11336 // Create parent channel 11337 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 11338 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 11339 IMPORTANCE_DEFAULT); 11340 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 11341 NotificationChannel.CREATOR); 11342 assertEquals(originalChannel, parentChannel); 11343 mBinderService.createNotificationChannels(mPkg, 11344 new ParceledListSlice(Arrays.asList(parentChannel))); 11345 11346 //Create deleted conversation channel 11347 mBinderService.createConversationNotificationChannelForPackage( 11348 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 11349 final NotificationChannel conversationChannel = 11350 mBinderService.getConversationNotificationChannel( 11351 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 11352 11353 //Create notification record without a shortcutId 11354 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 11355 null /* groupKey */, false /* isSummary */, true); 11356 nb.setShortcutId(null); 11357 nb.setChannelId(originalChannel.getId()); 11358 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 11359 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 11360 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 11361 assertThat(nr.getChannel()).isEqualTo(originalChannel); 11362 11363 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11364 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11365 waitForIdle(); 11366 11367 // Verify that the channel is the parent channel and no channel was restored 11368 //assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isFalse(); 11369 assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 11370 parentChannel); 11371 verify(service, never()).handleSavePolicyFile(); 11372 verify(preferencesHelper, never()).createNotificationChannel(anyString(), 11373 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()); 11374 } 11375 11376 @Test 11377 public void testGetConversationsForPackage_hasShortcut() throws Exception { 11378 mService.setPreferencesHelper(mPreferencesHelper); 11379 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 11380 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 11381 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 11382 channel1.setConversationId("parent1", "convo 1"); 11383 convo1.setNotificationChannel(channel1); 11384 convos.add(convo1); 11385 11386 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 11387 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 11388 channel2.setConversationId("parent1", "convo 2"); 11389 convo2.setNotificationChannel(channel2); 11390 convos.add(convo2); 11391 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 11392 11393 ShortcutInfo si = mock(ShortcutInfo.class); 11394 when(si.getPackage()).thenReturn(PKG_P); 11395 when(si.getId()).thenReturn("convo"); 11396 when(si.getUserId()).thenReturn(USER_SYSTEM); 11397 when(si.getLabel()).thenReturn("Hello"); 11398 when(si.isLongLived()).thenReturn(true); 11399 when(si.isEnabled()).thenReturn(true); 11400 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); 11401 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 11402 anyString(), anyInt(), any())).thenReturn(true); 11403 11404 List<ConversationChannelWrapper> conversations = 11405 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 11406 assertEquals(si, conversations.get(0).getShortcutInfo()); 11407 assertEquals(si, conversations.get(1).getShortcutInfo()); 11408 11409 // Returns null shortcuts when locked. 11410 when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(false); 11411 conversations = 11412 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 11413 assertThat(conversations.get(0).getShortcutInfo()).isNull(); 11414 assertThat(conversations.get(1).getShortcutInfo()).isNull(); 11415 } 11416 11417 @Test 11418 public void testGetConversationsForPackage_shortcut_notLongLived() throws Exception { 11419 mService.setPreferencesHelper(mPreferencesHelper); 11420 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 11421 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 11422 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 11423 channel1.setConversationId("parent1", "convo 1"); 11424 convo1.setNotificationChannel(channel1); 11425 convos.add(convo1); 11426 11427 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 11428 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 11429 channel2.setConversationId("parent1", "convo 2"); 11430 convo2.setNotificationChannel(channel2); 11431 convos.add(convo2); 11432 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 11433 11434 ShortcutInfo si = mock(ShortcutInfo.class); 11435 when(si.getPackage()).thenReturn(PKG_P); 11436 when(si.getId()).thenReturn("convo"); 11437 when(si.getUserId()).thenReturn(USER_SYSTEM); 11438 when(si.getLabel()).thenReturn("Hello"); 11439 when(si.isLongLived()).thenReturn(false); 11440 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); 11441 11442 List<ConversationChannelWrapper> conversations = 11443 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 11444 assertNull(conversations.get(0).getShortcutInfo()); 11445 assertNull(conversations.get(1).getShortcutInfo()); 11446 } 11447 11448 @Test 11449 public void testGetConversationsForPackage_doesNotHaveShortcut() throws Exception { 11450 mService.setPreferencesHelper(mPreferencesHelper); 11451 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 11452 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 11453 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 11454 channel1.setConversationId("parent1", "convo 1"); 11455 convo1.setNotificationChannel(channel1); 11456 convos.add(convo1); 11457 11458 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 11459 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 11460 channel2.setConversationId("parent1", "convo 2"); 11461 convo2.setNotificationChannel(channel2); 11462 convos.add(convo2); 11463 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 11464 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 11465 11466 List<ConversationChannelWrapper> conversations = 11467 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 11468 assertNull(conversations.get(0).getShortcutInfo()); 11469 assertNull(conversations.get(1).getShortcutInfo()); 11470 } 11471 11472 @Test 11473 public void testShortcutHelperNull_doesntCrashEnqueue() throws RemoteException { 11474 mService.setShortcutHelper(null); 11475 NotificationRecord nr = 11476 generateMessageBubbleNotifRecord(mTestNotificationChannel, 11477 "testShortcutHelperNull_doesntCrashEnqueue"); 11478 try { 11479 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11480 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11481 waitForIdle(); 11482 } catch (Exception e) { 11483 fail(e.getMessage()); 11484 } 11485 } 11486 11487 @Test 11488 public void testRecordMessages_invalidMsg() throws RemoteException { 11489 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 11490 null /* groupKey */, false /* isSummary */, true); 11491 nb.setShortcutId(null); 11492 StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1, 11493 "testRecordMessages_invalidMsg", mUid, 0, nb.build(), 11494 UserHandle.getUserHandleForUid(mUid), null, 0); 11495 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 11496 11497 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 11498 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 11499 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11500 waitForIdle(); 11501 11502 assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 11503 } 11504 11505 @Test 11506 public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException { 11507 Notification.Builder nb = new Notification.Builder(mContext, 11508 mTestNotificationChannel.getId()) 11509 .setContentTitle("foo") 11510 .setShortcutId(null) 11511 .setSmallIcon(android.R.drawable.sym_def_app_icon) 11512 .setCategory(Notification.CATEGORY_MESSAGE); 11513 StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1, 11514 "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(), 11515 UserHandle.getUserHandleForUid(mUid), null, 0); 11516 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 11517 11518 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 11519 mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(), 11520 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11521 waitForIdle(); 11522 11523 // PKG_O is allowed to be in conversation space b/c of override in 11524 // TestableNotificationManagerService 11525 assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid)); 11526 } 11527 11528 @Test 11529 public void testRecordMessages_validMsg() throws RemoteException { 11530 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 11531 null /* groupKey */, false /* isSummary */, true); 11532 nb.setShortcutId(null); 11533 StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1, 11534 "testRecordMessages_validMsg", mUid, 0, nb.build(), 11535 UserHandle.getUserHandleForUid(mUid), null, 0); 11536 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 11537 11538 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 11539 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11540 waitForIdle(); 11541 11542 assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 11543 11544 nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11545 "testRecordMessages_validMsg"); 11546 11547 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 11548 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11549 waitForIdle(); 11550 11551 assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 11552 } 11553 11554 @Test 11555 public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException { 11556 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11557 "testRecordMessages_invalidMsg_afterValidMsg_1"); 11558 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11559 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11560 waitForIdle(); 11561 assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation()); 11562 11563 mBinderService.cancelAllNotifications(mPkg, mUid); 11564 waitForIdle(); 11565 11566 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 11567 null /* groupKey */, false /* isSummary */, true); 11568 nb.setShortcutId(null); 11569 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 11570 "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(), 11571 UserHandle.getUserHandleForUid(mUid), null, 0); 11572 nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 11573 11574 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11575 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11576 waitForIdle(); 11577 11578 assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation()); 11579 } 11580 11581 @Test 11582 public void testCanPostFgsWhenOverLimit() throws RemoteException { 11583 when(mAmi.applyForegroundServiceNotification( 11584 any(), anyString(), anyInt(), anyString(), anyInt())) 11585 .thenReturn(SHOW_IMMEDIATELY); 11586 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 11587 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 11588 i, null, false).getSbn(); 11589 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 11590 "testCanPostFgsWhenOverLimit", 11591 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 11592 } 11593 11594 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 11595 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 11596 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 11597 "testCanPostFgsWhenOverLimit - fgs over limit!", 11598 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 11599 11600 waitForIdle(); 11601 11602 StatusBarNotification[] notifs = 11603 mBinderService.getActiveNotifications(sbn.getPackageName()); 11604 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 11605 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 11606 mService.getNotificationRecordCount()); 11607 } 11608 11609 @Test 11610 public void testCannotPostNonFgsWhenOverLimit() throws RemoteException { 11611 when(mAmi.applyForegroundServiceNotification( 11612 any(), anyString(), anyInt(), anyString(), anyInt())) 11613 .thenReturn(SHOW_IMMEDIATELY); 11614 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 11615 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 11616 i, null, false).getSbn(); 11617 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 11618 "testCanPostFgsWhenOverLimit", 11619 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 11620 waitForIdle(); 11621 } 11622 11623 final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 11624 100, null, false).getSbn(); 11625 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 11626 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 11627 "testCanPostFgsWhenOverLimit - fgs over limit!", 11628 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 11629 11630 final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel, 11631 101, null, false).getSbn(); 11632 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 11633 "testCanPostFgsWhenOverLimit - non fgs over limit!", 11634 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId()); 11635 11636 11637 when(mAmi.applyForegroundServiceNotification( 11638 any(), anyString(), anyInt(), anyString(), anyInt())) 11639 .thenReturn(NOT_FOREGROUND_SERVICE); 11640 final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel, 11641 101, null, false).getSbn(); 11642 sbn3.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 11643 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 11644 "testCanPostFgsWhenOverLimit - fake fgs over limit!", 11645 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId()); 11646 11647 waitForIdle(); 11648 11649 StatusBarNotification[] notifs = 11650 mBinderService.getActiveNotifications(sbn.getPackageName()); 11651 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 11652 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 11653 mService.getNotificationRecordCount()); 11654 } 11655 11656 @Test 11657 public void testIsVisibleToListener_notEnabled() { 11658 StatusBarNotification sbn = mock(StatusBarNotification.class); 11659 when(sbn.getUserId()).thenReturn(10); 11660 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 11661 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 11662 info.userid = 10; 11663 when(info.isSameUser(anyInt())).thenReturn(true); 11664 when(assistant.isSameUser(anyInt())).thenReturn(true); 11665 when(info.enabledAndUserMatches(info.userid)).thenReturn(false); 11666 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 11667 11668 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 11669 } 11670 11671 @Test 11672 public void testIsVisibleToListener_noAssistant() { 11673 StatusBarNotification sbn = mock(StatusBarNotification.class); 11674 when(sbn.getUserId()).thenReturn(10); 11675 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 11676 info.userid = 10; 11677 when(info.isSameUser(anyInt())).thenReturn(true); 11678 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 11679 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null); 11680 11681 assertTrue(mService.isVisibleToListener(sbn, 0, info)); 11682 } 11683 11684 @Test 11685 public void testIsVisibleToListener_assistant_differentUser() { 11686 StatusBarNotification sbn = mock(StatusBarNotification.class); 11687 when(sbn.getUserId()).thenReturn(10); 11688 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 11689 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 11690 info.userid = 0; 11691 when(info.isSameUser(anyInt())).thenReturn(true); 11692 when(assistant.isSameUser(anyInt())).thenReturn(true); 11693 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 11694 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 11695 11696 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 11697 } 11698 11699 @Test 11700 public void testIsVisibleToListener_assistant_sameUser() { 11701 StatusBarNotification sbn = mock(StatusBarNotification.class); 11702 when(sbn.getUserId()).thenReturn(10); 11703 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 11704 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 11705 info.userid = 10; 11706 when(info.isSameUser(anyInt())).thenReturn(true); 11707 when(assistant.isSameUser(anyInt())).thenReturn(true); 11708 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 11709 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 11710 11711 assertTrue(mService.isVisibleToListener(sbn, 0, info)); 11712 } 11713 11714 @Test 11715 public void testIsVisibleToListener_mismatchedType() { 11716 when(mNlf.isTypeAllowed(anyInt())).thenReturn(false); 11717 11718 StatusBarNotification sbn = mock(StatusBarNotification.class); 11719 when(sbn.getUserId()).thenReturn(10); 11720 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 11721 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 11722 info.userid = 10; 11723 when(info.isSameUser(anyInt())).thenReturn(true); 11724 when(assistant.isSameUser(anyInt())).thenReturn(true); 11725 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 11726 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 11727 11728 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 11729 } 11730 11731 @Test 11732 public void testIsVisibleToListener_disallowedPackage() { 11733 when(mNlf.isPackageAllowed(any())).thenReturn(false); 11734 11735 StatusBarNotification sbn = mock(StatusBarNotification.class); 11736 when(sbn.getUserId()).thenReturn(10); 11737 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 11738 ManagedServices.ManagedServiceInfo assistant = 11739 mock(ManagedServices.ManagedServiceInfo.class); 11740 info.userid = 10; 11741 when(info.isSameUser(anyInt())).thenReturn(true); 11742 when(assistant.isSameUser(anyInt())).thenReturn(true); 11743 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 11744 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 11745 11746 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 11747 } 11748 11749 @Test 11750 public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedFirst() { 11751 final NotificationRecord parent = spy(generateNotificationRecord( 11752 mTestNotificationChannel, 1, "group", true)); 11753 final NotificationRecord child = spy(generateNotificationRecord( 11754 mTestNotificationChannel, 2, "group", false)); 11755 mService.addNotification(parent); 11756 mService.addNotification(child); 11757 11758 InOrder inOrder = inOrder(parent, child); 11759 11760 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 11761 parent.getUserId()); 11762 waitForIdle(); 11763 inOrder.verify(parent).recordDismissalSentiment(anyInt()); 11764 inOrder.verify(child).recordDismissalSentiment(anyInt()); 11765 } 11766 11767 @Test 11768 public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedSecond() { 11769 final NotificationRecord parent = spy(generateNotificationRecord( 11770 mTestNotificationChannel, 1, "group", true)); 11771 final NotificationRecord child = spy(generateNotificationRecord( 11772 mTestNotificationChannel, 2, "group", false)); 11773 mService.addNotification(child); 11774 mService.addNotification(parent); 11775 11776 InOrder inOrder = inOrder(parent, child); 11777 11778 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 11779 parent.getUserId()); 11780 waitForIdle(); 11781 inOrder.verify(parent).recordDismissalSentiment(anyInt()); 11782 inOrder.verify(child).recordDismissalSentiment(anyInt()); 11783 } 11784 11785 @Test 11786 public void testImmutableBubbleIntent() throws Exception { 11787 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 11788 NotificationRecord r = generateMessageBubbleNotifRecord(true, 11789 mTestNotificationChannel, 7, "testImmutableBubbleIntent", null, false, false); 11790 try { 11791 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 11792 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 11793 11794 waitForIdle(); 11795 fail("Allowed a bubble with an immutable intent to be posted"); 11796 } catch (IllegalArgumentException e) { 11797 // good 11798 } 11799 } 11800 11801 @Test 11802 public void testMutableBubbleIntent() throws Exception { 11803 NotificationRecord r = generateMessageBubbleNotifRecord(true, 11804 mTestNotificationChannel, 7, "testMutableBubbleIntent", null, false, true); 11805 11806 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 11807 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 11808 11809 waitForIdle(); 11810 StatusBarNotification[] notifs = 11811 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 11812 assertEquals(1, notifs.length); 11813 } 11814 11815 @Test 11816 public void testImmutableDirectReplyActionIntent() throws Exception { 11817 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 11818 NotificationRecord r = generateMessageBubbleNotifRecord(false, 11819 mTestNotificationChannel, 7, "testImmutableDirectReplyActionIntent", null, false, 11820 false); 11821 try { 11822 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 11823 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 11824 11825 waitForIdle(); 11826 fail("Allowed a direct reply with an immutable intent to be posted"); 11827 } catch (IllegalArgumentException e) { 11828 // good 11829 } 11830 } 11831 11832 @Test 11833 public void testMutableDirectReplyActionIntent() throws Exception { 11834 NotificationRecord r = generateMessageBubbleNotifRecord(false, 11835 mTestNotificationChannel, 7, "testMutableDirectReplyActionIntent", null, false, 11836 true); 11837 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 11838 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 11839 11840 waitForIdle(); 11841 StatusBarNotification[] notifs = 11842 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 11843 assertEquals(1, notifs.length); 11844 } 11845 11846 @Test 11847 public void testImmutableDirectReplyContextualActionIntent() throws Exception { 11848 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 11849 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 11850 11851 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 11852 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 11853 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 11854 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 11855 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 11856 mActivityIntentImmutable).addRemoteInput(remoteInput) 11857 .build(); 11858 extraAction.add(replyAction); 11859 Bundle signals = new Bundle(); 11860 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 11861 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 11862 r.getUser()); 11863 r.addAdjustment(adjustment); 11864 r.applyAdjustments(); 11865 11866 try { 11867 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 11868 r.getSbn().getTag(), r, false, false); 11869 fail("Allowed a contextual direct reply with an immutable intent to be posted"); 11870 } catch (IllegalArgumentException e) { 11871 // good 11872 } 11873 } 11874 11875 @Test 11876 public void testMutableDirectReplyContextualActionIntent() throws Exception { 11877 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 11878 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 11879 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 11880 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 11881 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 11882 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 11883 mActivityIntent).addRemoteInput(remoteInput) 11884 .build(); 11885 extraAction.add(replyAction); 11886 Bundle signals = new Bundle(); 11887 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 11888 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 11889 r.getUser()); 11890 r.addAdjustment(adjustment); 11891 r.applyAdjustments(); 11892 11893 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 11894 r.getSbn().getTag(), r, false, false); 11895 } 11896 11897 @Test 11898 public void testImmutableActionIntent() throws Exception { 11899 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 11900 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 11901 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 11902 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 11903 11904 waitForIdle(); 11905 StatusBarNotification[] notifs = 11906 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 11907 assertEquals(1, notifs.length); 11908 } 11909 11910 @Test 11911 public void testImmutableContextualActionIntent() throws Exception { 11912 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 11913 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 11914 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 11915 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 11916 extraAction.add(new Notification.Action(0, "hello", mActivityIntentImmutable)); 11917 Bundle signals = new Bundle(); 11918 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 11919 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 11920 r.getUser()); 11921 r.addAdjustment(adjustment); 11922 r.applyAdjustments(); 11923 11924 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 11925 r.getSbn().getTag(), r, false, false); 11926 } 11927 11928 @Test 11929 public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception { 11930 int uid = 9000; 11931 int[] userIds = new int[] {mUserId, 1000}; 11932 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 11933 List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); 11934 for (int userId : userIds) { 11935 for (String pkg : disallowedApps) { 11936 when(mPackageManager.getPackageUid(pkg, 0, userId)).thenReturn(uid++); 11937 } 11938 } 11939 11940 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 11941 new NotificationListenerFilter()); 11942 11943 mBinderService.migrateNotificationFilter(null, 11944 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 11945 disallowedApps); 11946 11947 ArgumentCaptor<NotificationListenerFilter> captor = 11948 ArgumentCaptor.forClass(NotificationListenerFilter.class); 11949 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 11950 11951 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 11952 captor.getValue().getTypes()); 11953 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9000))); 11954 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9002))); 11955 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9003))); 11956 11957 // hypothetical other user untouched 11958 assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 10000))); 11959 } 11960 11961 @Test 11962 public void testMigrateNotificationFilter_invalidPackage() throws Exception { 11963 int[] userIds = new int[] {mUserId, 1000}; 11964 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 11965 List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); 11966 for (int userId : userIds) { 11967 when(mPackageManager.getPackageUid("apples", 0, userId)).thenThrow( 11968 new RemoteException("")); 11969 when(mPackageManager.getPackageUid("bananas", 0, userId)).thenReturn(9000); 11970 when(mPackageManager.getPackageUid("cherries", 0, userId)).thenReturn(9001); 11971 } 11972 11973 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 11974 new NotificationListenerFilter()); 11975 11976 mBinderService.migrateNotificationFilter(null, 11977 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 11978 disallowedApps); 11979 11980 ArgumentCaptor<NotificationListenerFilter> captor = 11981 ArgumentCaptor.forClass(NotificationListenerFilter.class); 11982 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 11983 11984 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 11985 captor.getValue().getTypes()); 11986 // valid values stay 11987 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("bananas", 9000))); 11988 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9001))); 11989 // don't store invalid values 11990 for (VersionedPackage vp : captor.getValue().getDisallowedPackages()) { 11991 assertNotEquals("apples", vp.getPackageName()); 11992 } 11993 } 11994 11995 @Test 11996 public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception { 11997 int[] userIds = new int[] {mUserId}; 11998 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 11999 List<String> disallowedApps = ImmutableList.of("apples"); 12000 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 12001 .thenReturn(1001); 12002 12003 when(mListeners.getNotificationListenerFilter(any())).thenReturn(null); 12004 12005 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 12006 disallowedApps); 12007 12008 ArgumentCaptor<NotificationListenerFilter> captor = 12009 ArgumentCaptor.forClass(NotificationListenerFilter.class); 12010 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 12011 12012 assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes()); 12013 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 12014 } 12015 12016 @Test 12017 public void testMigrateNotificationFilter_existingTypeFilter() throws Exception { 12018 int[] userIds = new int[] {mUserId}; 12019 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 12020 List<String> disallowedApps = ImmutableList.of("apples"); 12021 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 12022 .thenReturn(1001); 12023 12024 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 12025 new NotificationListenerFilter(FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>())); 12026 12027 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 12028 disallowedApps); 12029 12030 ArgumentCaptor<NotificationListenerFilter> captor = 12031 ArgumentCaptor.forClass(NotificationListenerFilter.class); 12032 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 12033 12034 // type isn't saved but pkg list is 12035 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, captor.getValue().getTypes()); 12036 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 12037 } 12038 12039 @Test 12040 public void testMigrateNotificationFilter_existingPkgFilter() throws Exception { 12041 int[] userIds = new int[] {mUserId}; 12042 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 12043 List<String> disallowedApps = ImmutableList.of("apples"); 12044 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 12045 .thenReturn(1001); 12046 12047 NotificationListenerFilter preexisting = new NotificationListenerFilter(); 12048 preexisting.addPackage(new VersionedPackage("test", 1002)); 12049 when(mListeners.getNotificationListenerFilter(any())).thenReturn(preexisting); 12050 12051 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 12052 disallowedApps); 12053 12054 ArgumentCaptor<NotificationListenerFilter> captor = 12055 ArgumentCaptor.forClass(NotificationListenerFilter.class); 12056 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 12057 12058 // type is saved but pkg list isn't 12059 assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes()); 12060 assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 12061 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002))); 12062 } 12063 12064 @Test 12065 public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException { 12066 mService.setPreferencesHelper(mPreferencesHelper); 12067 12068 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 12069 12070 assertThat(mBinderService.getNotificationChannelsBypassingDnd(mPkg, mUid).getList()) 12071 .isEmpty(); 12072 verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid); 12073 } 12074 12075 @Test 12076 public void testGetPackagesBypassingDnd_empty() throws RemoteException { 12077 mService.setPreferencesHelper(mPreferencesHelper); 12078 List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); 12079 assertThat(result).isEmpty(); 12080 } 12081 12082 @Test 12083 public void testGetPackagesBypassingDnd_excludeConversationChannels() throws RemoteException { 12084 mService.setPreferencesHelper(mPreferencesHelper); 12085 12086 // Set packages 12087 PackageInfo pkg0 = new PackageInfo(); 12088 pkg0.packageName = "pkg0"; 12089 pkg0.applicationInfo = new ApplicationInfo(); 12090 pkg0.applicationInfo.uid = mUid; 12091 PackageInfo pkg1 = new PackageInfo(); 12092 pkg1.packageName = "pkg1"; 12093 pkg1.applicationInfo = new ApplicationInfo(); 12094 pkg1.applicationInfo.uid = mUid; 12095 PackageInfo pkg2 = new PackageInfo(); 12096 pkg2.packageName = "pkg2"; 12097 pkg2.applicationInfo = new ApplicationInfo(); 12098 pkg2.applicationInfo.uid = mUid; 12099 12100 when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) 12101 .thenReturn(List.of(pkg0, pkg1, pkg2)); 12102 12103 // Conversation channels 12104 NotificationChannel nc0 = new NotificationChannel("id0", "id0", 12105 NotificationManager.IMPORTANCE_HIGH); 12106 nc0.setConversationId("parentChannel", "conversationId"); 12107 12108 // Demoted conversation channel 12109 NotificationChannel nc1 = new NotificationChannel("id1", "id1", 12110 NotificationManager.IMPORTANCE_HIGH); 12111 nc1.setConversationId("parentChannel", "conversationId"); 12112 nc1.setDemoted(true); 12113 12114 // Non-conversation channels 12115 NotificationChannel nc2 = new NotificationChannel("id2", "id2", 12116 NotificationManager.IMPORTANCE_HIGH); 12117 NotificationChannel nc3 = new NotificationChannel("id3", "id3", 12118 NotificationManager.IMPORTANCE_HIGH); 12119 12120 ParceledListSlice<NotificationChannel> pls0 = 12121 new ParceledListSlice(ImmutableList.of(nc0)); 12122 ParceledListSlice<NotificationChannel> pls1 = 12123 new ParceledListSlice(ImmutableList.of(nc1)); 12124 ParceledListSlice<NotificationChannel> pls2 = 12125 new ParceledListSlice(ImmutableList.of(nc2, nc3)); 12126 12127 when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) 12128 .thenReturn(pls0); 12129 when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) 12130 .thenReturn(pls1); 12131 when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) 12132 .thenReturn(pls2); 12133 12134 List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, false); 12135 12136 assertThat(result).containsExactly("pkg1", "pkg2"); 12137 } 12138 12139 @Test 12140 public void testGetPackagesBypassingDnd_includeConversationChannels() throws RemoteException { 12141 mService.setPreferencesHelper(mPreferencesHelper); 12142 12143 // Set packages 12144 PackageInfo pkg0 = new PackageInfo(); 12145 pkg0.packageName = "pkg0"; 12146 pkg0.applicationInfo = new ApplicationInfo(); 12147 pkg0.applicationInfo.uid = mUid; 12148 PackageInfo pkg1 = new PackageInfo(); 12149 pkg1.packageName = "pkg1"; 12150 pkg1.applicationInfo = new ApplicationInfo(); 12151 pkg1.applicationInfo.uid = mUid; 12152 PackageInfo pkg2 = new PackageInfo(); 12153 pkg2.packageName = "pkg2"; 12154 pkg2.applicationInfo = new ApplicationInfo(); 12155 pkg2.applicationInfo.uid = mUid; 12156 12157 when(mPackageManagerClient.getInstalledPackagesAsUser(0, mUserId)) 12158 .thenReturn(List.of(pkg0, pkg1, pkg2)); 12159 12160 // Conversation channels 12161 NotificationChannel nc0 = new NotificationChannel("id0", "id0", 12162 NotificationManager.IMPORTANCE_HIGH); 12163 nc0.setConversationId("parentChannel", "conversationId"); 12164 12165 // Demoted conversation channel 12166 NotificationChannel nc1 = new NotificationChannel("id1", "id1", 12167 NotificationManager.IMPORTANCE_HIGH); 12168 nc1.setConversationId("parentChannel", "conversationId"); 12169 nc1.setDemoted(true); 12170 12171 // Non-conversation channels 12172 NotificationChannel nc2 = new NotificationChannel("id2", "id2", 12173 NotificationManager.IMPORTANCE_HIGH); 12174 NotificationChannel nc3 = new NotificationChannel("id3", "id3", 12175 NotificationManager.IMPORTANCE_HIGH); 12176 12177 ParceledListSlice<NotificationChannel> pls0 = 12178 new ParceledListSlice(ImmutableList.of(nc0)); 12179 ParceledListSlice<NotificationChannel> pls1 = 12180 new ParceledListSlice(ImmutableList.of(nc1)); 12181 ParceledListSlice<NotificationChannel> pls2 = 12182 new ParceledListSlice(ImmutableList.of(nc2, nc3)); 12183 12184 when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg0", mUid)) 12185 .thenReturn(pls0); 12186 when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg1", mUid)) 12187 .thenReturn(pls1); 12188 when(mPreferencesHelper.getNotificationChannelsBypassingDnd("pkg2", mUid)) 12189 .thenReturn(pls2); 12190 12191 List<String> result = mBinderService.getPackagesBypassingDnd(mUserId, true); 12192 12193 assertThat(result).containsExactly("pkg0", "pkg1", "pkg2"); 12194 } 12195 12196 @Test 12197 public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception { 12198 // set the testable NMS to not system uid/appid 12199 mService.isSystemUid = false; 12200 mService.isSystemAppId = false; 12201 12202 // make sure a caller without listener access or read_contacts permission can't call 12203 // matchesCallFilter. 12204 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 12205 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 12206 eq("android.permission.READ_CONTACTS"), anyString()); 12207 12208 try { 12209 // shouldn't matter what we're passing in, if we get past this line fail immediately 12210 ((INotificationManager) mService.mService).matchesCallFilter(null); 12211 fail("call to matchesCallFilter with no permissions should fail"); 12212 } catch (SecurityException e) { 12213 // pass 12214 } 12215 } 12216 12217 @Test 12218 public void testMatchesCallFilter_hasSystemPermission() throws Exception { 12219 // set the testable NMS to system uid 12220 mService.isSystemUid = true; 12221 12222 // make sure caller doesn't have listener access or read_contacts permission 12223 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 12224 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 12225 eq("android.permission.READ_CONTACTS"), anyString()); 12226 12227 try { 12228 ((INotificationManager) mService.mService).matchesCallFilter(null); 12229 // pass, but check that we actually checked for system permissions 12230 assertTrue(mService.countSystemChecks > 0); 12231 } catch (SecurityException e) { 12232 fail("call to matchesCallFilter with just system permissions should work"); 12233 } 12234 } 12235 12236 @Test 12237 public void testMatchesCallFilter_hasListenerPermission() throws Exception { 12238 mService.isSystemUid = false; 12239 mService.isSystemAppId = false; 12240 12241 // make sure a caller with only listener access and not read_contacts permission can call 12242 // matchesCallFilter. 12243 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(true); 12244 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 12245 eq("android.permission.READ_CONTACTS"), anyString()); 12246 12247 try { 12248 ((INotificationManager) mService.mService).matchesCallFilter(null); 12249 // pass, this is not a functionality test 12250 } catch (SecurityException e) { 12251 fail("call to matchesCallFilter with listener permissions should work"); 12252 } 12253 } 12254 12255 @Test 12256 public void testMatchesCallFilter_hasContactsPermission() throws Exception { 12257 mService.isSystemUid = false; 12258 mService.isSystemAppId = false; 12259 12260 // make sure a caller with only read_contacts permission and not listener access can call 12261 // matchesCallFilter. 12262 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 12263 doNothing().when(mContext).enforceCallingPermission( 12264 eq("android.permission.READ_CONTACTS"), anyString()); 12265 12266 try { 12267 ((INotificationManager) mService.mService).matchesCallFilter(null); 12268 // pass, this is not a functionality test 12269 } catch (SecurityException e) { 12270 fail("call to matchesCallFilter with listener permissions should work"); 12271 } 12272 } 12273 12274 @Test 12275 public void testMediaNotificationsBypassBlock() throws Exception { 12276 when(mAmi.getPendingIntentFlags(any(IIntentSender.class))) 12277 .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT); 12278 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 12279 12280 Notification.Builder nb = new Notification.Builder( 12281 mContext, mTestNotificationChannel.getId()) 12282 .setContentTitle("foo") 12283 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12284 .addAction(new Notification.Action.Builder(null, "test", null).build()); 12285 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12286 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12287 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12288 12289 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 12290 12291 // normal blocked notifications - blocked 12292 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12293 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 12294 12295 // just using the style - blocked 12296 nb.setStyle(new Notification.MediaStyle()); 12297 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12298 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12299 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12300 12301 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12302 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 12303 12304 // using the style, but incorrect type in session - blocked 12305 nb.setStyle(new Notification.MediaStyle()); 12306 Bundle extras = new Bundle(); 12307 extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent()); 12308 nb.addExtras(extras); 12309 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12310 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12311 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12312 12313 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12314 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 12315 12316 // style + media session - bypasses block 12317 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); 12318 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12319 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12320 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12321 12322 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12323 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 12324 } 12325 12326 @Test 12327 public void testMediaNotificationsBypassBlock_atPost() throws Exception { 12328 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12329 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 12330 12331 Notification.Builder nb = new Notification.Builder( 12332 mContext, mTestNotificationChannel.getId()) 12333 .setContentTitle("foo") 12334 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12335 .addAction(new Notification.Action.Builder(null, "test", null).build()); 12336 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12337 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12338 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12339 12340 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 12341 12342 mService.addEnqueuedNotification(r); 12343 NotificationManagerService.PostNotificationRunnable runnable = 12344 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 12345 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 12346 runnable.run(); 12347 waitForIdle(); 12348 12349 verify(mUsageStats).registerBlocked(any()); 12350 verify(mUsageStats, never()).registerPostedByApp(any()); 12351 12352 // just using the style - blocked 12353 mService.clearNotifications(); 12354 reset(mUsageStats); 12355 nb.setStyle(new Notification.MediaStyle()); 12356 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12357 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12358 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12359 12360 mService.addEnqueuedNotification(r); 12361 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 12362 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 12363 runnable.run(); 12364 waitForIdle(); 12365 12366 verify(mUsageStats).registerBlocked(any()); 12367 verify(mUsageStats, never()).registerPostedByApp(any()); 12368 12369 // style + media session - bypasses block 12370 mService.clearNotifications(); 12371 reset(mUsageStats); 12372 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); 12373 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12374 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12375 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12376 12377 mService.addEnqueuedNotification(r); 12378 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 12379 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 12380 runnable.run(); 12381 waitForIdle(); 12382 12383 verify(mUsageStats, never()).registerBlocked(any()); 12384 verify(mUsageStats).registerPostedByApp(any()); 12385 } 12386 12387 @Test 12388 public void testCallNotificationsBypassBlock() throws Exception { 12389 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 12390 12391 Notification.Builder nb = new Notification.Builder( 12392 mContext, mTestNotificationChannel.getId()) 12393 .setContentTitle("foo") 12394 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12395 .addAction(new Notification.Action.Builder(null, "test", null).build()); 12396 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12397 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12398 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12399 12400 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 12401 12402 // normal blocked notifications - blocked 12403 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12404 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 12405 12406 // just using the style - blocked 12407 Person person = new Person.Builder() 12408 .setName("caller") 12409 .build(); 12410 nb.setStyle(Notification.CallStyle.forOngoingCall( 12411 person, mActivityIntent)); 12412 nb.setFullScreenIntent(mActivityIntent, true); 12413 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12414 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12415 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12416 12417 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12418 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 12419 12420 // style + managed call - bypasses block 12421 when(mTelecomManager.isInManagedCall()).thenReturn(true); 12422 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12423 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 12424 12425 // style + self managed call - bypasses block 12426 when(mTelecomManager.isInSelfManagedCall( 12427 r.getSbn().getPackageName(), UserHandle.ALL)).thenReturn(true); 12428 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12429 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 12430 12431 // set telecom manager to null - blocked 12432 mService.setTelecomManager(null); 12433 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12434 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 12435 .isFalse(); 12436 12437 // set telecom feature to false - blocked 12438 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false); 12439 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12440 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 12441 .isFalse(); 12442 12443 // telecom manager is not ready - blocked 12444 mService.setTelecomManager(mTelecomManager); 12445 when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready")); 12446 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 12447 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 12448 .isFalse(); 12449 } 12450 12451 @Test 12452 public void testCallNotificationsBypassBlock_atPost() throws Exception { 12453 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12454 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 12455 12456 Notification.Builder nb = 12457 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 12458 .setContentTitle("foo") 12459 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12460 .addAction(new Notification.Action.Builder(null, "test", null).build()); 12461 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 12462 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12463 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12464 12465 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 12466 12467 // normal blocked notifications - blocked 12468 mService.addEnqueuedNotification(r); 12469 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 12470 mPostNotificationTrackerFactory.newTracker(null)).run(); 12471 waitForIdle(); 12472 12473 verify(mUsageStats).registerBlocked(any()); 12474 verify(mUsageStats, never()).registerPostedByApp(any()); 12475 12476 // just using the style - blocked 12477 mService.clearNotifications(); 12478 reset(mUsageStats); 12479 Person person = new Person.Builder().setName("caller").build(); 12480 nb.setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)); 12481 nb.setFullScreenIntent(mActivityIntent, true); 12482 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, nb.build(), 12483 UserHandle.getUserHandleForUid(mUid), null, 0); 12484 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12485 12486 mService.addEnqueuedNotification(r); 12487 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 12488 mPostNotificationTrackerFactory.newTracker(null)).run(); 12489 waitForIdle(); 12490 12491 verify(mUsageStats).registerBlocked(any()); 12492 verify(mUsageStats, never()).registerPostedByApp(any()); 12493 12494 // style + managed call - bypasses block 12495 mService.clearNotifications(); 12496 reset(mUsageStats); 12497 when(mTelecomManager.isInManagedCall()).thenReturn(true); 12498 12499 mService.addEnqueuedNotification(r); 12500 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 12501 mPostNotificationTrackerFactory.newTracker(null)).run(); 12502 waitForIdle(); 12503 12504 verify(mUsageStats, never()).registerBlocked(any()); 12505 verify(mUsageStats).registerPostedByApp(any()); 12506 12507 // style + self managed call - bypasses block 12508 mService.clearNotifications(); 12509 reset(mUsageStats); 12510 when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), UserHandle.ALL)) 12511 .thenReturn(true); 12512 12513 mService.addEnqueuedNotification(r); 12514 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 12515 mPostNotificationTrackerFactory.newTracker(null)).run(); 12516 waitForIdle(); 12517 12518 verify(mUsageStats, never()).registerBlocked(any()); 12519 verify(mUsageStats).registerPostedByApp(any()); 12520 12521 // set telecom manager to null - notifications should be blocked 12522 // but post notifications runnable should not crash 12523 mService.clearNotifications(); 12524 reset(mUsageStats); 12525 mService.setTelecomManager(null); 12526 12527 mService.addEnqueuedNotification(r); 12528 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 12529 mPostNotificationTrackerFactory.newTracker(null)).run(); 12530 waitForIdle(); 12531 12532 verify(mUsageStats).registerBlocked(any()); 12533 verify(mUsageStats, never()).registerPostedByApp(any()); 12534 12535 // set FEATURE_TELECOM to false - notifications should be blocked 12536 // but post notifications runnable should not crash 12537 mService.setTelecomManager(mTelecomManager); 12538 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false); 12539 reset(mUsageStats); 12540 mService.setTelecomManager(null); 12541 12542 mService.addEnqueuedNotification(r); 12543 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 12544 mPostNotificationTrackerFactory.newTracker(null)).run(); 12545 waitForIdle(); 12546 12547 verify(mUsageStats).registerBlocked(any()); 12548 verify(mUsageStats, never()).registerPostedByApp(any()); 12549 12550 // telecom is not ready - notifications should be blocked but no crashes 12551 mService.setTelecomManager(mTelecomManager); 12552 when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready")); 12553 reset(mUsageStats); 12554 12555 mService.addEnqueuedNotification(r); 12556 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 12557 mPostNotificationTrackerFactory.newTracker(null)).run(); 12558 waitForIdle(); 12559 12560 verify(mUsageStats).registerBlocked(any()); 12561 verify(mUsageStats, never()).registerPostedByApp(any()); 12562 } 12563 12564 @Test 12565 public void testGetAllUsersNotificationPermissions() { 12566 // In this case, there are multiple users each with notification permissions (and also, 12567 // for good measure, some without). 12568 // make sure the collection returned contains info for all of them 12569 final List<UserInfo> userInfos = new ArrayList<>(); 12570 userInfos.add(new UserInfo(0, "user0", 0)); 12571 userInfos.add(new UserInfo(1, "user1", 0)); 12572 userInfos.add(new UserInfo(2, "user2", 0)); 12573 when(mUm.getUsers()).thenReturn(userInfos); 12574 12575 // construct the permissions for each of them 12576 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(), 12577 permissions1 = new ArrayMap<>(); 12578 permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false)); 12579 permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true)); 12580 permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false)); 12581 permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true)); 12582 when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0); 12583 when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1); 12584 when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>()); 12585 12586 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions = 12587 mService.getAllUsersNotificationPermissions(); 12588 assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first); 12589 assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second); 12590 assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first); 12591 assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second); 12592 assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first); 12593 assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second); 12594 assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first); 12595 assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second); 12596 } 12597 12598 @Test 12599 public void testGetActiveNotification_filtersUsers() throws Exception { 12600 when(mUm.getProfileIds(mUserId, false)).thenReturn(new int[]{mUserId, 10}); 12601 12602 NotificationRecord nr0 = 12603 generateNotificationRecord(mTestNotificationChannel, mUserId); 12604 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 12605 nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId()); 12606 12607 NotificationRecord nr10 = 12608 generateNotificationRecord(mTestNotificationChannel, 10); 12609 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag10", 12610 nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId()); 12611 12612 NotificationRecord nr11 = 12613 generateNotificationRecord(mTestNotificationChannel, 11); 12614 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag11", 12615 nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId()); 12616 waitForIdle(); 12617 12618 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 12619 assertEquals(2, notifs.length); 12620 for (StatusBarNotification sbn : notifs) { 12621 if (sbn.getUserId() == 11) { 12622 fail("leaked data across users"); 12623 } 12624 } 12625 } 12626 12627 @Test 12628 public void testGetActiveNotificationsFromListener_redactNotification() throws Exception { 12629 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 12630 NotificationRecord r = 12631 generateNotificationRecord(mTestNotificationChannel, 0, 0); 12632 mService.addNotification(r); 12633 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 12634 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 12635 StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1); 12636 when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted); 12637 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12638 info.userid = 0; 12639 when(info.isSameUser(anyInt())).thenReturn(true); 12640 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 12641 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 12642 List<StatusBarNotification> notifications = mBinderService 12643 .getActiveNotificationsFromListener(mock(INotificationListener.class), null, -1) 12644 .getList(); 12645 12646 boolean foundRedactedSbn = false; 12647 for (StatusBarNotification sbn: notifications) { 12648 String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString(); 12649 if (REDACTED_TEXT.equals(text)) { 12650 foundRedactedSbn = true; 12651 break; 12652 } 12653 } 12654 assertTrue("expect to find a redacted notification", foundRedactedSbn); 12655 } 12656 12657 @Test 12658 public void testGetSnoozedNotificationsFromListener_redactNotification() throws Exception { 12659 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 12660 NotificationRecord r = 12661 generateNotificationRecord(mTestNotificationChannel, 0, 0); 12662 when(mSnoozeHelper.getSnoozed()).thenReturn(List.of(r)); 12663 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 12664 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 12665 StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1); 12666 when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted); 12667 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12668 info.userid = 0; 12669 when(info.isSameUser(anyInt())).thenReturn(true); 12670 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 12671 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 12672 List<StatusBarNotification> notifications = mBinderService 12673 .getSnoozedNotificationsFromListener(mock(INotificationListener.class), -1) 12674 .getList(); 12675 12676 boolean foundRedactedSbn = false; 12677 for (StatusBarNotification sbn: notifications) { 12678 String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString(); 12679 if (REDACTED_TEXT.equals(text)) { 12680 foundRedactedSbn = true; 12681 break; 12682 } 12683 } 12684 assertTrue("expect to find a redacted notification", foundRedactedSbn); 12685 } 12686 12687 @Test 12688 public void testUngroupingOngoingAutoSummary() throws Exception { 12689 NotificationRecord nr0 = 12690 generateNotificationRecord(mTestNotificationChannel, 0); 12691 NotificationRecord nr1 = 12692 generateNotificationRecord(mTestNotificationChannel, 0); 12693 nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT; 12694 12695 mService.addNotification(nr0); 12696 mService.addNotification(nr1); 12697 12698 // grouphelper is a mock here, so make the calls it would make 12699 12700 // add summary 12701 mService.addNotification( 12702 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 12703 nr1.getKey(), GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0, 12704 VISIBILITY_PRIVATE)); 12705 12706 // cancel both children 12707 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(), 12708 nr0.getSbn().getId(), nr0.getSbn().getUserId()); 12709 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(), 12710 nr1.getSbn().getId(), nr1.getSbn().getUserId()); 12711 waitForIdle(); 12712 12713 // group helper would send 'remove summary' event 12714 mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName()); 12715 waitForIdle(); 12716 12717 // make sure the summary was removed and not re-posted 12718 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 12719 } 12720 12721 @Test 12722 public void testUngroupingAutoSummary_differentUsers() throws Exception { 12723 NotificationRecord nr0 = 12724 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM); 12725 NotificationRecord nr1 = 12726 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM); 12727 12728 // add notifications + summary for USER_SYSTEM 12729 mService.addNotification(nr0); 12730 mService.addNotification(nr1); 12731 mService.addNotification( 12732 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 12733 nr1.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE)); 12734 12735 // add notifications + summary for USER_ALL 12736 NotificationRecord nr0_all = 12737 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL); 12738 NotificationRecord nr1_all = 12739 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL); 12740 12741 mService.addNotification(nr0_all); 12742 mService.addNotification(nr1_all); 12743 mService.addNotification( 12744 mService.createAutoGroupSummary(nr0_all.getUserId(), 12745 nr0_all.getSbn().getPackageName(), 12746 nr0_all.getKey(), GroupHelper.BASE_FLAGS, mock(Icon.class), 0, VISIBILITY_PRIVATE)); 12747 12748 // cancel both children for USER_ALL 12749 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(), 12750 nr0_all.getSbn().getId(), UserHandle.USER_ALL); 12751 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(), 12752 nr1_all.getSbn().getId(), UserHandle.USER_ALL); 12753 waitForIdle(); 12754 12755 // group helper would send 'remove summary' event 12756 mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL, 12757 nr0_all.getSbn().getPackageName()); 12758 waitForIdle(); 12759 12760 // make sure the right summary was removed 12761 assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(), 12762 UserHandle.USER_ALL, 0, null)).isEqualTo(0); 12763 12764 // the USER_SYSTEM notifications + summary were not removed 12765 assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(), 12766 USER_SYSTEM, 0, null)).isEqualTo(3); 12767 } 12768 12769 @Test 12770 public void testStrongAuthTracker_isInLockDownMode() { 12771 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 12772 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 12773 mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); 12774 assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); 12775 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId()); 12776 mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); 12777 assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); 12778 } 12779 12780 @Test 12781 public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() { 12782 // post 2 notifications from 2 packages 12783 NotificationRecord pkgA = new NotificationRecord(mContext, 12784 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 12785 mService.addNotification(pkgA); 12786 NotificationRecord pkgB = new NotificationRecord(mContext, 12787 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 12788 mService.addNotification(pkgB); 12789 12790 // when entering the lockdown mode, cancel the 2 notifications. 12791 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 12792 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 12793 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 12794 assertTrue(mStrongAuthTracker.isInLockDownMode(0)); 12795 12796 // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN. 12797 ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); 12798 verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any()); 12799 assertEquals(REASON_LOCKDOWN, captor.getValue().intValue()); 12800 12801 // exit lockdown mode. 12802 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); 12803 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 12804 assertFalse(mStrongAuthTracker.isInLockDownMode(0)); 12805 12806 // the notifyPostedLocked function is called twice. 12807 verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong()); 12808 } 12809 12810 @Test 12811 public void testMakeRankingUpdateLockedInLockDownMode() { 12812 // post 2 notifications from a same package 12813 NotificationRecord pkgA = new NotificationRecord(mContext, 12814 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 12815 mService.addNotification(pkgA); 12816 NotificationRecord pkgB = new NotificationRecord(mContext, 12817 generateSbn("a", 1000, 9, 1), mTestNotificationChannel); 12818 mService.addNotification(pkgB); 12819 12820 mService.setIsVisibleToListenerReturnValue(true); 12821 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null); 12822 assertEquals(2, nru.getRankingMap().getOrderedKeys().length); 12823 12824 // when only user 0 entering the lockdown mode, its notification will be suppressed. 12825 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 12826 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 12827 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 12828 assertTrue(mStrongAuthTracker.isInLockDownMode(0)); 12829 assertFalse(mStrongAuthTracker.isInLockDownMode(1)); 12830 12831 nru = mService.makeRankingUpdateLocked(null); 12832 assertEquals(1, nru.getRankingMap().getOrderedKeys().length); 12833 12834 // User 0 exits lockdown mode. Its notification will be resumed. 12835 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); 12836 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 12837 assertFalse(mStrongAuthTracker.isInLockDownMode(0)); 12838 assertFalse(mStrongAuthTracker.isInLockDownMode(1)); 12839 12840 nru = mService.makeRankingUpdateLocked(null); 12841 assertEquals(2, nru.getRankingMap().getOrderedKeys().length); 12842 } 12843 12844 @Test 12845 public void testMakeRankingUpdate_redactsIfRecordSensitiveAndServiceUntrusted() { 12846 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 12847 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 12848 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 12849 NotificationRecord pkgA = new NotificationRecord(mContext, 12850 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 12851 addSmartActionsAndReplies(pkgA); 12852 mService.addNotification(pkgA); 12853 NotificationRecord pkgB = new NotificationRecord(mContext, 12854 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 12855 addSmartActionsAndReplies(pkgB); 12856 mService.addNotification(pkgB); 12857 12858 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12859 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 12860 when(info.isSameUser(anyInt())).thenReturn(true); 12861 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 12862 NotificationListenerService.Ranking ranking = 12863 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 12864 assertEquals(0, ranking.getSmartActions().size()); 12865 assertEquals(0, ranking.getSmartReplies().size()); 12866 NotificationListenerService.Ranking ranking2 = 12867 nru.getRankingMap().getRawRankingObject(pkgB.getSbn().getKey()); 12868 assertEquals(0, ranking2.getSmartActions().size()); 12869 assertEquals(0, ranking2.getSmartReplies().size()); 12870 } 12871 12872 @Test 12873 public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() { 12874 mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 12875 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 12876 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 12877 NotificationRecord pkgA = new NotificationRecord(mContext, 12878 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 12879 addSmartActionsAndReplies(pkgA); 12880 12881 mService.addNotification(pkgA); 12882 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12883 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 12884 when(info.isSameUser(anyInt())).thenReturn(true); 12885 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 12886 NotificationListenerService.Ranking ranking = 12887 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 12888 assertEquals(1, ranking.getSmartActions().size()); 12889 assertEquals(1, ranking.getSmartReplies().size()); 12890 } 12891 12892 @Test 12893 public void testMakeRankingUpdate_doesntRedactIfNotSensitiveOrServiceTrusted() { 12894 mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 12895 NotificationRecord pkgA = new NotificationRecord(mContext, 12896 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 12897 addSmartActionsAndReplies(pkgA); 12898 12899 mService.addNotification(pkgA); 12900 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12901 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 12902 when(info.isSameUser(anyInt())).thenReturn(true); 12903 12904 // No sensitive content, no redaction 12905 when(mListeners.isUidTrusted(eq(1000))).thenReturn(false); 12906 when(mListeners.hasSensitiveContent(any())).thenReturn(false); 12907 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 12908 NotificationListenerService.Ranking ranking = 12909 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 12910 assertEquals(1, ranking.getSmartActions().size()); 12911 assertEquals(1, ranking.getSmartReplies().size()); 12912 12913 // trusted listener, no redaction 12914 when(mListeners.isUidTrusted(eq(1000))).thenReturn(true); 12915 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 12916 nru = mService.makeRankingUpdateLocked(info); 12917 ranking = nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 12918 assertEquals(1, ranking.getSmartActions().size()); 12919 assertEquals(1, ranking.getSmartReplies().size()); 12920 } 12921 12922 private void addSmartActionsAndReplies(NotificationRecord record) { 12923 Bundle b = new Bundle(); 12924 ArrayList<Notification.Action> actions = new ArrayList<>(); 12925 actions.add(new Notification.Action(0, "", null)); 12926 b.putParcelableArrayList(KEY_CONTEXTUAL_ACTIONS, actions); 12927 ArrayList<CharSequence> replies = new ArrayList<>(List.of("test")); 12928 b.putCharSequenceArrayList(KEY_TEXT_REPLIES, replies); 12929 Adjustment a = new Adjustment(record.getSbn().getPackageName(), record.getSbn().getKey(), 12930 b, "", record.getUserId()); 12931 record.addAdjustment(a); 12932 record.applyAdjustments(); 12933 } 12934 12935 @Test 12936 public void testMaybeShowReviewPermissionsNotification_flagOff() { 12937 mService.setShowReviewPermissionsNotification(false); 12938 reset(mMockNm); 12939 12940 // If state is SHOULD_SHOW, it would show, but not if the flag is off! 12941 Settings.Global.putInt(mContext.getContentResolver(), 12942 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 12943 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 12944 mService.maybeShowInitialReviewPermissionsNotification(); 12945 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 12946 } 12947 12948 @Test 12949 public void testMaybeShowReviewPermissionsNotification_unknown() { 12950 mService.setShowReviewPermissionsNotification(true); 12951 reset(mMockNm); 12952 12953 // Set up various possible states of the settings int and confirm whether or not the 12954 // notification is shown as expected 12955 12956 // Initial state: default/unknown setting, make sure nothing happens 12957 Settings.Global.putInt(mContext.getContentResolver(), 12958 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 12959 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN); 12960 mService.maybeShowInitialReviewPermissionsNotification(); 12961 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 12962 } 12963 12964 @Test 12965 public void testMaybeShowReviewPermissionsNotification_shouldShow() { 12966 mService.setShowReviewPermissionsNotification(true); 12967 reset(mMockNm); 12968 12969 // If state is SHOULD_SHOW, it ... should show 12970 Settings.Global.putInt(mContext.getContentResolver(), 12971 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 12972 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 12973 mService.maybeShowInitialReviewPermissionsNotification(); 12974 verify(mMockNm, times(1)).notify(eq(TAG), 12975 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 12976 any(Notification.class)); 12977 } 12978 12979 @Test 12980 public void testMaybeShowReviewPermissionsNotification_alreadyShown() { 12981 mService.setShowReviewPermissionsNotification(true); 12982 reset(mMockNm); 12983 12984 // If state is either USER_INTERACTED or DISMISSED, we should not show this on boot 12985 Settings.Global.putInt(mContext.getContentResolver(), 12986 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 12987 NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED); 12988 mService.maybeShowInitialReviewPermissionsNotification(); 12989 12990 Settings.Global.putInt(mContext.getContentResolver(), 12991 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 12992 NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED); 12993 mService.maybeShowInitialReviewPermissionsNotification(); 12994 12995 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 12996 } 12997 12998 @Test 12999 public void testMaybeShowReviewPermissionsNotification_reshown() { 13000 mService.setShowReviewPermissionsNotification(true); 13001 reset(mMockNm); 13002 13003 // If we have re-shown the notification and the user did not subsequently interacted with 13004 // it, then make sure we show when trying on boot 13005 Settings.Global.putInt(mContext.getContentResolver(), 13006 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 13007 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN); 13008 mService.maybeShowInitialReviewPermissionsNotification(); 13009 verify(mMockNm, times(1)).notify(eq(TAG), 13010 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 13011 any(Notification.class)); 13012 } 13013 13014 @Test 13015 public void testRescheduledReviewPermissionsNotification() { 13016 mService.setShowReviewPermissionsNotification(true); 13017 reset(mMockNm); 13018 13019 // when rescheduled, the notification goes through the NotificationManagerInternal service 13020 // this call doesn't need to know anything about previously scheduled state -- if called, 13021 // it should send the notification & write the appropriate int to Settings 13022 mInternalService.sendReviewPermissionsNotification(); 13023 13024 // Notification should be sent 13025 verify(mMockNm, times(1)).notify(eq(TAG), 13026 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 13027 any(Notification.class)); 13028 13029 // write STATE_RESHOWN to settings 13030 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN, 13031 Settings.Global.getInt(mContext.getContentResolver(), 13032 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 13033 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 13034 } 13035 13036 @Test 13037 public void testRescheduledReviewPermissionsNotification_flagOff() { 13038 mService.setShowReviewPermissionsNotification(false); 13039 reset(mMockNm); 13040 13041 // no notification should be sent if the flag is off 13042 mInternalService.sendReviewPermissionsNotification(); 13043 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 13044 } 13045 13046 private void verifyStickyHun(int permissionState, boolean appRequested, 13047 boolean isSticky) throws Exception { 13048 13049 when(mPermissionHelper.hasRequestedPermission(Manifest.permission.USE_FULL_SCREEN_INTENT, 13050 mPkg, mUserId)).thenReturn(appRequested); 13051 13052 when(mPermissionManager.checkPermissionForDataDelivery( 13053 eq(Manifest.permission.USE_FULL_SCREEN_INTENT), any(), any())) 13054 .thenReturn(permissionState); 13055 13056 Notification n = new Notification.Builder(mContext, "test") 13057 .setFullScreenIntent(mActivityIntent, true) 13058 .build(); 13059 13060 mService.fixNotification(n, mPkg, "tag", 9, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 13061 13062 final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED; 13063 13064 if (isSticky) { 13065 assertNotSame(0, stickyFlag); 13066 } else { 13067 assertSame(0, stickyFlag); 13068 } 13069 } 13070 13071 @Test 13072 public void testFixNotification_flagEnableStickyHun_fsiPermissionHardDenied_showStickyHun() 13073 throws Exception { 13074 13075 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_HARD_DENIED, true, 13076 /* isSticky= */ true); 13077 } 13078 13079 @Test 13080 public void testFixNotification_flagEnableStickyHun_fsiPermissionSoftDenied_showStickyHun() 13081 throws Exception { 13082 13083 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, true, 13084 /* isSticky= */ true); 13085 } 13086 13087 @Test 13088 public void testFixNotification_fsiPermissionSoftDenied_appNotRequest_noShowStickyHun() 13089 throws Exception { 13090 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, false, 13091 /* isSticky= */ false); 13092 } 13093 13094 13095 @Test 13096 public void testFixNotification_flagEnableStickyHun_fsiPermissionGranted_showFsi() 13097 throws Exception { 13098 13099 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_GRANTED, true, 13100 /* isSticky= */ false); 13101 } 13102 13103 @Test 13104 public void fixNotification_withFgsFlag_butIsNotFgs() throws Exception { 13105 final ApplicationInfo applicationInfo = new ApplicationInfo(); 13106 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 13107 .thenReturn(applicationInfo); 13108 13109 Notification n = new Notification.Builder(mContext, "test") 13110 .setFlag(FLAG_FOREGROUND_SERVICE, true) 13111 .setFlag(FLAG_CAN_COLORIZE, true) 13112 .build(); 13113 13114 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13115 13116 assertFalse(n.isForegroundService()); 13117 assertFalse(n.hasColorizedPermission()); 13118 } 13119 13120 @Test 13121 public void checkCallStyleNotification_withoutAnyValidUseCase_throws() throws Exception { 13122 Person person = new Person.Builder().setName("caller").build(); 13123 Notification n = new Notification.Builder(mContext, "test") 13124 .setStyle(Notification.CallStyle.forOngoingCall( 13125 person, mActivityIntent)) 13126 .build(); 13127 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13128 n, UserHandle.getUserHandleForUid(mUid), null, 0); 13129 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13130 13131 try { 13132 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13133 r.getSbn().getId(), r.getSbn().getTag(), r, false, false); 13134 assertFalse("CallStyle should not be allowed without a valid use case", true); 13135 } catch (IllegalArgumentException error) { 13136 assertThat(error.getMessage()).contains("CallStyle"); 13137 } 13138 } 13139 13140 @Test 13141 public void checkCallStyleNotification_allowedForFgs() throws Exception { 13142 Person person = new Person.Builder().setName("caller").build(); 13143 Notification n = new Notification.Builder(mContext, "test") 13144 .setFlag(FLAG_FOREGROUND_SERVICE, true) 13145 .setStyle(Notification.CallStyle.forOngoingCall( 13146 person, mActivityIntent)) 13147 .build(); 13148 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13149 n, UserHandle.getUserHandleForUid(mUid), null, 0); 13150 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13151 13152 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13153 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13154 } 13155 13156 private NotificationRecord createBigPictureRecord(boolean isBigPictureStyle, boolean hasImage, 13157 boolean isImageBitmap, boolean isExpired) { 13158 Notification.Builder builder = new Notification.Builder(mContext); 13159 Notification.BigPictureStyle style = new Notification.BigPictureStyle(); 13160 13161 if (isBigPictureStyle && hasImage) { 13162 if (isImageBitmap) { 13163 style = style.bigPicture(Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888)); 13164 } else { 13165 style = style.bigPicture(Icon.createWithResource(mContext, R.drawable.btn_plus)); 13166 } 13167 } 13168 if (isBigPictureStyle) { 13169 builder.setStyle(style); 13170 } 13171 13172 Notification notification = builder.setChannelId(TEST_CHANNEL_ID).build(); 13173 13174 long timePostedMs = System.currentTimeMillis(); 13175 if (isExpired) { 13176 timePostedMs -= BITMAP_DURATION.toMillis(); 13177 } 13178 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13179 notification, UserHandle.getUserHandleForUid(mUid), null, timePostedMs); 13180 13181 return new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13182 } 13183 13184 private void addRecordAndRemoveBitmaps(NotificationRecord record) { 13185 mService.addNotification(record); 13186 mInternalService.removeBitmaps(); 13187 waitForIdle(); 13188 } 13189 13190 @Test 13191 public void testRemoveBitmaps_notBigPicture_noRepost() { 13192 addRecordAndRemoveBitmaps( 13193 createBigPictureRecord( 13194 /* isBigPictureStyle= */ false, 13195 /* hasImage= */ false, 13196 /* isImageBitmap= */ false, 13197 /* isExpired= */ false)); 13198 verify(mWorkerHandler, never()) 13199 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 13200 } 13201 13202 @Test 13203 public void testRemoveBitmaps_bigPictureNoImage_noRepost() { 13204 addRecordAndRemoveBitmaps( 13205 createBigPictureRecord( 13206 /* isBigPictureStyle= */ true, 13207 /* hasImage= */ false, 13208 /* isImageBitmap= */ false, 13209 /* isExpired= */ false)); 13210 verify(mWorkerHandler, never()) 13211 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 13212 } 13213 13214 @Test 13215 public void testRemoveBitmaps_notExpired_noRepost() { 13216 addRecordAndRemoveBitmaps( 13217 createBigPictureRecord( 13218 /* isBigPictureStyle= */ true, 13219 /* hasImage= */ true, 13220 /* isImageBitmap= */ true, 13221 /* isExpired= */ false)); 13222 verify(mWorkerHandler, never()) 13223 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 13224 } 13225 13226 @Test 13227 public void testRemoveBitmaps_bitmapExpired_repost() { 13228 addRecordAndRemoveBitmaps( 13229 createBigPictureRecord( 13230 /* isBigPictureStyle= */ true, 13231 /* hasImage= */ true, 13232 /* isImageBitmap= */ true, 13233 /* isExpired= */ true)); 13234 verify(mWorkerHandler, times(1)) 13235 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 13236 } 13237 13238 @Test 13239 public void testRemoveBitmaps_bitmapExpired_bitmapGone() { 13240 NotificationRecord record = createBigPictureRecord( 13241 /* isBigPictureStyle= */ true, 13242 /* hasImage= */ true, 13243 /* isImageBitmap= */ true, 13244 /* isExpired= */ true); 13245 addRecordAndRemoveBitmaps(record); 13246 assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE)).isTrue(); 13247 final Parcelable picture = record.getNotification().extras.getParcelable(EXTRA_PICTURE); 13248 assertThat(picture).isNull(); 13249 } 13250 13251 @Test 13252 public void testRemoveBitmaps_bitmapExpired_silent() { 13253 NotificationRecord record = createBigPictureRecord( 13254 /* isBigPictureStyle= */ true, 13255 /* hasImage= */ true, 13256 /* isImageBitmap= */ true, 13257 /* isExpired= */ true); 13258 addRecordAndRemoveBitmaps(record); 13259 assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0); 13260 } 13261 13262 @Test 13263 public void testRemoveBitmaps_iconExpired_repost() { 13264 addRecordAndRemoveBitmaps( 13265 createBigPictureRecord( 13266 /* isBigPictureStyle= */ true, 13267 /* hasImage= */ true, 13268 /* isImageBitmap= */ false, 13269 /* isExpired= */ true)); 13270 verify(mWorkerHandler, times(1)) 13271 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 13272 } 13273 13274 @Test 13275 public void testRemoveBitmaps_iconExpired_iconGone() { 13276 NotificationRecord record = createBigPictureRecord( 13277 /* isBigPictureStyle= */ true, 13278 /* hasImage= */ true, 13279 /* isImageBitmap= */ false, 13280 /* isExpired= */ true); 13281 addRecordAndRemoveBitmaps(record); 13282 assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE_ICON)).isTrue(); 13283 final Parcelable pictureIcon = 13284 record.getNotification().extras.getParcelable(EXTRA_PICTURE_ICON); 13285 assertThat(pictureIcon).isNull(); 13286 } 13287 13288 @Test 13289 public void testRemoveBitmaps_iconExpired_silent() { 13290 NotificationRecord record = createBigPictureRecord( 13291 /* isBigPictureStyle= */ true, 13292 /* hasImage= */ true, 13293 /* isImageBitmap= */ false, 13294 /* isExpired= */ true); 13295 addRecordAndRemoveBitmaps(record); 13296 assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0); 13297 } 13298 13299 @Test 13300 public void checkCallStyleNotification_allowedForByForegroundService() throws Exception { 13301 Person person = new Person.Builder().setName("caller").build(); 13302 Notification n = new Notification.Builder(mContext, "test") 13303 // Without FLAG_FOREGROUND_SERVICE. 13304 //.setFlag(FLAG_FOREGROUND_SERVICE, true) 13305 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 13306 .build(); 13307 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13308 n, UserHandle.getUserHandleForUid(mUid), null, 0); 13309 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13310 13311 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13312 r.getSbn().getId(), r.getSbn().getTag(), r, false, 13313 true /* byForegroundService */)).isTrue(); 13314 } 13315 13316 @Test 13317 public void checkCallStyleNotification_allowedForUij() throws Exception { 13318 Person person = new Person.Builder().setName("caller").build(); 13319 Notification n = new Notification.Builder(mContext, "test") 13320 .setFlag(FLAG_USER_INITIATED_JOB, true) 13321 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 13322 .build(); 13323 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13324 n, UserHandle.getUserHandleForUid(mUid), null, 0); 13325 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13326 13327 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13328 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13329 } 13330 13331 @Test 13332 public void checkCallStyleNotification_allowedForFsiAllowed() throws Exception { 13333 Person person = new Person.Builder().setName("caller").build(); 13334 Notification n = new Notification.Builder(mContext, "test") 13335 .setFullScreenIntent(mActivityIntent, true) 13336 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 13337 .build(); 13338 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13339 n, UserHandle.getUserHandleForUid(mUid), null, 0); 13340 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13341 13342 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13343 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13344 } 13345 13346 @Test 13347 public void checkCallStyleNotification_allowedForFsiDenied() throws Exception { 13348 Person person = new Person.Builder().setName("caller").build(); 13349 Notification n = new Notification.Builder(mContext, "test") 13350 .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true) 13351 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 13352 .build(); 13353 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13354 n, UserHandle.getUserHandleForUid(mUid), null, 0); 13355 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13356 13357 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13358 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13359 } 13360 13361 @Test 13362 public void fixSystemNotification_withOnGoingFlag_shouldBeDismissible() 13363 throws Exception { 13364 final ApplicationInfo ai = new ApplicationInfo(); 13365 ai.packageName = "pkg"; 13366 ai.uid = mUid; 13367 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 13368 13369 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 13370 .thenReturn(ai); 13371 when(mAppOpsManager.checkOpNoThrow( 13372 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 13373 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 13374 // Given: a notification from an app on the system partition has the flag 13375 // FLAG_ONGOING_EVENT set 13376 Notification n = new Notification.Builder(mContext, "test") 13377 .setOngoing(true) 13378 .build(); 13379 13380 // When: fix the notification with NotificationManagerService 13381 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13382 13383 // Then: the notification's flag FLAG_NO_DISMISS should not be set 13384 assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13385 } 13386 13387 @Test 13388 public void fixMediaNotification_withOnGoingFlag_shouldBeNonDismissible() 13389 throws Exception { 13390 // Given: a media notification has the flag FLAG_ONGOING_EVENT set 13391 Notification n = new Notification.Builder(mContext, "test") 13392 .setOngoing(true) 13393 .setStyle(new Notification.MediaStyle() 13394 .setMediaSession(mock(MediaSession.Token.class))) 13395 .build(); 13396 13397 // When: fix the notification with NotificationManagerService 13398 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13399 13400 // Then: the notification's flag FLAG_NO_DISMISS should be set 13401 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13402 } 13403 13404 @Test 13405 public void fixSystemNotification_defaultSearchSelectior_withOnGoingFlag_nondismissible() 13406 throws Exception { 13407 final ApplicationInfo ai = new ApplicationInfo(); 13408 ai.packageName = SEARCH_SELECTOR_PKG; 13409 ai.uid = mUid; 13410 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 13411 13412 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 13413 .thenReturn(ai); 13414 when(mAppOpsManager.checkOpNoThrow( 13415 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 13416 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 13417 // Given: a notification from an app on the system partition has the flag 13418 // FLAG_ONGOING_EVENT set 13419 Notification n = new Notification.Builder(mContext, "test") 13420 .setOngoing(true) 13421 .build(); 13422 13423 // When: fix the notification with NotificationManagerService 13424 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13425 13426 // Then: the notification's flag FLAG_NO_DISMISS should be set 13427 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13428 } 13429 13430 @Test 13431 public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible() 13432 throws Exception { 13433 final ApplicationInfo ai = new ApplicationInfo(); 13434 ai.packageName = ADSERVICES_APK_PKG; 13435 ai.uid = mUid; 13436 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 13437 13438 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 13439 .thenReturn(ai); 13440 when(mAppOpsManager.checkOpNoThrow( 13441 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 13442 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 13443 // Given: a notification from an app on the system partition has the flag 13444 // FLAG_ONGOING_EVENT set 13445 Notification n = new Notification.Builder(mContext, "test") 13446 .setOngoing(true) 13447 .build(); 13448 13449 // When: fix the notification with NotificationManagerService 13450 mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, 13451 true); 13452 13453 // Then: the notification's flag FLAG_NO_DISMISS should be set 13454 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13455 } 13456 13457 @Test 13458 public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible() 13459 throws Exception { 13460 // Given: a call notification has the flag FLAG_ONGOING_EVENT set 13461 Person person = new Person.Builder() 13462 .setName("caller") 13463 .build(); 13464 Notification n = new Notification.Builder(mContext, "test") 13465 .setOngoing(true) 13466 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 13467 .build(); 13468 13469 // When: fix the notification with NotificationManagerService 13470 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13471 13472 // Then: the notification's flag FLAG_NO_DISMISS should be set 13473 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13474 } 13475 13476 13477 @Test 13478 public void fixNonExemptNotification_withOnGoingFlag_shouldBeDismissible() throws Exception { 13479 // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set 13480 Notification n = new Notification.Builder(mContext, "test") 13481 .setOngoing(true) 13482 .build(); 13483 13484 // When: fix the notification with NotificationManagerService 13485 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13486 13487 // Then: the notification's flag FLAG_NO_DISMISS should not be set 13488 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 13489 } 13490 13491 @Test 13492 public void fixNonExemptNotification_withNoDismissFlag_shouldBeDismissible() 13493 throws Exception { 13494 // Given: a non-exempt notification has the flag FLAG_NO_DISMISS set (even though this is 13495 // not allowed) 13496 Notification n = new Notification.Builder(mContext, "test") 13497 .build(); 13498 n.flags |= Notification.FLAG_NO_DISMISS; 13499 13500 // When: fix the notification with NotificationManagerService 13501 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13502 13503 // Then: the notification's flag FLAG_NO_DISMISS should be cleared 13504 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 13505 } 13506 13507 @Test 13508 public void fixMediaNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception { 13509 // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set 13510 Notification n = new Notification.Builder(mContext, "test") 13511 .setOngoing(false) 13512 .setStyle(new Notification.MediaStyle() 13513 .setMediaSession(mock(MediaSession.Token.class))) 13514 .build(); 13515 13516 // When: fix the notification with NotificationManagerService 13517 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13518 13519 // Then: the notification's flag FLAG_NO_DISMISS should not be set 13520 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 13521 } 13522 13523 @Test 13524 public void fixMediaNotification_withoutOnGoingFlag_withNoDismissFlag_shouldBeDismissible() 13525 throws Exception { 13526 // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set, 13527 // but has the flag FLAG_NO_DISMISS set 13528 Notification n = new Notification.Builder(mContext, "test") 13529 .setOngoing(false) 13530 .setStyle(new Notification.MediaStyle() 13531 .setMediaSession(mock(MediaSession.Token.class))) 13532 .build(); 13533 n.flags |= Notification.FLAG_NO_DISMISS; 13534 13535 // When: fix the notification with NotificationManagerService 13536 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13537 13538 // Then: the notification's flag FLAG_NO_DISMISS should be cleared 13539 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 13540 } 13541 13542 @Test 13543 public void fixNonExempt_Notification_withoutOnGoingFlag_shouldBeDismissible() 13544 throws Exception { 13545 // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set 13546 Notification n = new Notification.Builder(mContext, "test") 13547 .setOngoing(false) 13548 .build(); 13549 13550 // When: fix the notification with NotificationManagerService 13551 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13552 13553 // Then: the notification's flag FLAG_NO_DISMISS should not be set 13554 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 13555 } 13556 13557 @Test 13558 public void fixOrganizationAdminNotification_withOnGoingFlag_shouldBeNonDismissible() 13559 throws Exception { 13560 when(mDevicePolicyManager.isActiveDeviceOwner(mUid)).thenReturn(true); 13561 // Given: a notification has the flag FLAG_ONGOING_EVENT set 13562 Notification n = new Notification.Builder(mContext, "test") 13563 .setOngoing(true) 13564 .build(); 13565 13566 // When: fix the notification with NotificationManagerService 13567 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13568 13569 // Then: the notification's flag FLAG_NO_DISMISS should be set 13570 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13571 } 13572 13573 @Test 13574 public void fixExemptAppOpNotification_withFlag_shouldBeNonDismissible() 13575 throws Exception { 13576 final ApplicationInfo ai = new ApplicationInfo(); 13577 ai.packageName = mPkg; 13578 ai.uid = mUid; 13579 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 13580 13581 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 13582 .thenReturn(ai); 13583 when(mAppOpsManager.checkOpNoThrow( 13584 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 13585 mPkg)).thenReturn(AppOpsManager.MODE_ALLOWED); 13586 // Given: a notification has the flag FLAG_ONGOING_EVENT set 13587 Notification n = new Notification.Builder(mContext, "test") 13588 .setOngoing(true) 13589 .build(); 13590 13591 // When: fix the notification with NotificationManagerService 13592 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13593 13594 // Then: the notification's flag FLAG_NO_DISMISS should be set 13595 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13596 } 13597 13598 @Test 13599 public void fixExemptAppOpNotification_withoutAppOpsFlag_shouldBeDismissible() 13600 throws Exception { 13601 when(mAppOpsManager.checkOpNoThrow( 13602 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 13603 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED); 13604 // Given: a notification has the flag FLAG_ONGOING_EVENT set 13605 Notification n = new Notification.Builder(mContext, "test") 13606 .setOngoing(true) 13607 .build(); 13608 13609 // When: fix the notification with NotificationManagerService 13610 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 13611 13612 // Then: the notification's flag FLAG_NO_DISMISS should not be set 13613 assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); 13614 } 13615 13616 @Test 13617 public void testCancelAllNotifications_IgnoreUserInitiatedJob() throws Exception { 13618 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13619 .thenReturn(true); 13620 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 13621 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13622 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 13623 "testCancelAllNotifications_IgnoreUserInitiatedJob", 13624 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13625 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 13626 waitForIdle(); 13627 StatusBarNotification[] notifs = 13628 mBinderService.getActiveNotifications(sbn.getPackageName()); 13629 assertEquals(1, notifs.length); 13630 assertEquals(1, mService.getNotificationRecordCount()); 13631 } 13632 13633 @Test 13634 public void testCancelAllNotifications_UijFlag_NoUij_Allowed() throws Exception { 13635 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13636 .thenReturn(false); 13637 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 13638 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13639 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 13640 "testCancelAllNotifications_UijFlag_NoUij_Allowed", 13641 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13642 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 13643 waitForIdle(); 13644 StatusBarNotification[] notifs = 13645 mBinderService.getActiveNotifications(sbn.getPackageName()); 13646 assertEquals(0, notifs.length); 13647 } 13648 13649 @Test 13650 public void testCancelAllNotificationsOtherPackage_IgnoresUijNotification() throws Exception { 13651 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13652 .thenReturn(true); 13653 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 13654 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13655 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 13656 "testCancelAllNotifications_IgnoreOtherPackages", 13657 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13658 mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); 13659 waitForIdle(); 13660 StatusBarNotification[] notifs = 13661 mBinderService.getActiveNotifications(sbn.getPackageName()); 13662 assertEquals(1, notifs.length); 13663 assertEquals(1, mService.getNotificationRecordCount()); 13664 } 13665 13666 @Test 13667 public void testRemoveUserInitiatedJobFlag_ImmediatelyAfterEnqueue() throws Exception { 13668 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13669 .thenReturn(true); 13670 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 13671 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13672 .build(); 13673 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, 13674 n, UserHandle.getUserHandleForUid(mUid), null, 0); 13675 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13676 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null, 13677 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13678 mInternalService.removeUserInitiatedJobFlagFromNotification(mPkg, sbn.getId(), 13679 sbn.getUserId()); 13680 waitForIdle(); 13681 StatusBarNotification[] notifs = 13682 mBinderService.getActiveNotifications(sbn.getPackageName()); 13683 assertFalse(notifs[0].getNotification().isUserInitiatedJob()); 13684 } 13685 13686 @Test 13687 public void testCancelAfterSecondEnqueueDoesNotSpecifyUserInitiatedJobFlag() throws Exception { 13688 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 13689 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_USER_INITIATED_JOB; 13690 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 13691 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13692 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; 13693 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 13694 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13695 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 13696 sbn.getUserId()); 13697 waitForIdle(); 13698 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 13699 assertEquals(0, mService.getNotificationRecordCount()); 13700 } 13701 13702 @Test 13703 public void testCancelNotificationWithTag_fromApp_cannotCancelUijChild() throws Exception { 13704 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13705 .thenReturn(true); 13706 mService.isSystemUid = false; 13707 mService.isSystemAppId = false; 13708 final NotificationRecord parent = generateNotificationRecord( 13709 mTestNotificationChannel, 1, "group", true); 13710 final NotificationRecord child = generateNotificationRecord( 13711 mTestNotificationChannel, 2, "group", false); 13712 final NotificationRecord child2 = generateNotificationRecord( 13713 mTestNotificationChannel, 3, "group", false); 13714 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13715 mService.addNotification(parent); 13716 mService.addNotification(child); 13717 mService.addNotification(child2); 13718 mService.getBinderService().cancelNotificationWithTag( 13719 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 13720 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 13721 waitForIdle(); 13722 StatusBarNotification[] notifs = 13723 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13724 assertEquals(1, notifs.length); 13725 } 13726 13727 @Test 13728 public void testCancelNotificationWithTag_fromApp_cannotCancelUijParent() throws Exception { 13729 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13730 .thenReturn(true); 13731 mService.isSystemUid = false; 13732 mService.isSystemAppId = false; 13733 final NotificationRecord parent = generateNotificationRecord( 13734 mTestNotificationChannel, 1, "group", true); 13735 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13736 final NotificationRecord child = generateNotificationRecord( 13737 mTestNotificationChannel, 2, "group", false); 13738 final NotificationRecord child2 = generateNotificationRecord( 13739 mTestNotificationChannel, 3, "group", false); 13740 mService.addNotification(parent); 13741 mService.addNotification(child); 13742 mService.addNotification(child2); 13743 mService.getBinderService().cancelNotificationWithTag( 13744 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 13745 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 13746 waitForIdle(); 13747 StatusBarNotification[] notifs = 13748 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13749 assertEquals(3, notifs.length); 13750 } 13751 13752 @Test 13753 public void testCancelAllNotificationsFromApp_cannotCancelUijChild() throws Exception { 13754 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13755 .thenReturn(true); 13756 mService.isSystemUid = false; 13757 mService.isSystemAppId = false; 13758 final NotificationRecord parent = generateNotificationRecord( 13759 mTestNotificationChannel, 1, "group", true); 13760 final NotificationRecord child = generateNotificationRecord( 13761 mTestNotificationChannel, 2, "group", false); 13762 final NotificationRecord child2 = generateNotificationRecord( 13763 mTestNotificationChannel, 3, "group", false); 13764 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13765 final NotificationRecord newGroup = generateNotificationRecord( 13766 mTestNotificationChannel, 4, "group2", false); 13767 mService.addNotification(parent); 13768 mService.addNotification(child); 13769 mService.addNotification(child2); 13770 mService.addNotification(newGroup); 13771 mService.getBinderService().cancelAllNotifications( 13772 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 13773 waitForIdle(); 13774 StatusBarNotification[] notifs = 13775 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13776 assertEquals(1, notifs.length); 13777 } 13778 13779 @Test 13780 public void testCancelAllNotifications_fromApp_cannotCancelUijParent() throws Exception { 13781 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13782 .thenReturn(true); 13783 mService.isSystemUid = false; 13784 mService.isSystemAppId = false; 13785 final NotificationRecord parent = generateNotificationRecord( 13786 mTestNotificationChannel, 1, "group", true); 13787 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13788 final NotificationRecord child = generateNotificationRecord( 13789 mTestNotificationChannel, 2, "group", false); 13790 final NotificationRecord child2 = generateNotificationRecord( 13791 mTestNotificationChannel, 3, "group", false); 13792 final NotificationRecord newGroup = generateNotificationRecord( 13793 mTestNotificationChannel, 4, "group2", false); 13794 mService.addNotification(parent); 13795 mService.addNotification(child); 13796 mService.addNotification(child2); 13797 mService.addNotification(newGroup); 13798 mService.getBinderService().cancelAllNotifications( 13799 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 13800 waitForIdle(); 13801 StatusBarNotification[] notifs = 13802 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13803 assertEquals(1, notifs.length); 13804 } 13805 13806 @Test 13807 public void testCancelNotificationsFromListener_clearAll_GroupWithUijParent() throws Exception { 13808 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13809 .thenReturn(true); 13810 final NotificationRecord parent = generateNotificationRecord( 13811 mTestNotificationChannel, 1, "group", true); 13812 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13813 final NotificationRecord child = generateNotificationRecord( 13814 mTestNotificationChannel, 2, "group", false); 13815 final NotificationRecord child2 = generateNotificationRecord( 13816 mTestNotificationChannel, 3, "group", false); 13817 final NotificationRecord newGroup = generateNotificationRecord( 13818 mTestNotificationChannel, 4, "group2", false); 13819 mService.addNotification(parent); 13820 mService.addNotification(child); 13821 mService.addNotification(child2); 13822 mService.addNotification(newGroup); 13823 mService.getBinderService().cancelNotificationsFromListener(null, null); 13824 waitForIdle(); 13825 StatusBarNotification[] notifs = 13826 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13827 assertEquals(0, notifs.length); 13828 } 13829 13830 @Test 13831 public void testCancelNotificationsFromListener_clearAll_GroupWithUijChild() throws Exception { 13832 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13833 .thenReturn(true); 13834 final NotificationRecord parent = generateNotificationRecord( 13835 mTestNotificationChannel, 1, "group", true); 13836 final NotificationRecord child = generateNotificationRecord( 13837 mTestNotificationChannel, 2, "group", false); 13838 final NotificationRecord child2 = generateNotificationRecord( 13839 mTestNotificationChannel, 3, "group", false); 13840 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13841 final NotificationRecord newGroup = generateNotificationRecord( 13842 mTestNotificationChannel, 4, "group2", false); 13843 mService.addNotification(parent); 13844 mService.addNotification(child); 13845 mService.addNotification(child2); 13846 mService.addNotification(newGroup); 13847 mService.getBinderService().cancelNotificationsFromListener(null, null); 13848 waitForIdle(); 13849 StatusBarNotification[] notifs = 13850 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13851 assertEquals(0, notifs.length); 13852 } 13853 13854 @Test 13855 public void testCancelNotificationsFromListener_clearAll_Uij() throws Exception { 13856 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13857 .thenReturn(true); 13858 final NotificationRecord child2 = generateNotificationRecord( 13859 mTestNotificationChannel, 3, null, false); 13860 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13861 mService.addNotification(child2); 13862 mService.getBinderService().cancelNotificationsFromListener(null, null); 13863 waitForIdle(); 13864 StatusBarNotification[] notifs = 13865 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 13866 assertEquals(0, notifs.length); 13867 } 13868 13869 @Test 13870 public void testCancelNotificationsFromListener_byKey_GroupWithUijParent() throws Exception { 13871 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13872 .thenReturn(true); 13873 final NotificationRecord parent = generateNotificationRecord( 13874 mTestNotificationChannel, 1, "group", true); 13875 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13876 final NotificationRecord child = generateNotificationRecord( 13877 mTestNotificationChannel, 2, "group", false); 13878 final NotificationRecord child2 = generateNotificationRecord( 13879 mTestNotificationChannel, 3, "group", false); 13880 final NotificationRecord newGroup = generateNotificationRecord( 13881 mTestNotificationChannel, 4, "group2", false); 13882 mService.addNotification(parent); 13883 mService.addNotification(child); 13884 mService.addNotification(child2); 13885 mService.addNotification(newGroup); 13886 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 13887 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 13888 mService.getBinderService().cancelNotificationsFromListener(null, keys); 13889 waitForIdle(); 13890 StatusBarNotification[] notifs = 13891 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13892 assertEquals(0, notifs.length); 13893 } 13894 13895 @Test 13896 public void testCancelNotificationsFromListener_byKey_GroupWithUijChild() throws Exception { 13897 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13898 .thenReturn(true); 13899 final NotificationRecord parent = generateNotificationRecord( 13900 mTestNotificationChannel, 1, "group", true); 13901 final NotificationRecord child = generateNotificationRecord( 13902 mTestNotificationChannel, 2, "group", false); 13903 final NotificationRecord child2 = generateNotificationRecord( 13904 mTestNotificationChannel, 3, "group", false); 13905 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13906 final NotificationRecord newGroup = generateNotificationRecord( 13907 mTestNotificationChannel, 4, "group2", false); 13908 mService.addNotification(parent); 13909 mService.addNotification(child); 13910 mService.addNotification(child2); 13911 mService.addNotification(newGroup); 13912 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 13913 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 13914 mService.getBinderService().cancelNotificationsFromListener(null, keys); 13915 waitForIdle(); 13916 StatusBarNotification[] notifs = 13917 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13918 assertEquals(0, notifs.length); 13919 } 13920 13921 @Test 13922 public void testCancelNotificationsFromListener_byKey_Uij() throws Exception { 13923 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13924 .thenReturn(true); 13925 final NotificationRecord child = generateNotificationRecord( 13926 mTestNotificationChannel, 3, null, false); 13927 child.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13928 mService.addNotification(child); 13929 String[] keys = {child.getSbn().getKey()}; 13930 mService.getBinderService().cancelNotificationsFromListener(null, keys); 13931 waitForIdle(); 13932 StatusBarNotification[] notifs = 13933 mBinderService.getActiveNotifications(child.getSbn().getPackageName()); 13934 assertEquals(0, notifs.length); 13935 } 13936 13937 @Test 13938 public void testUserInitiatedCancelAllWithGroup_UserInitiatedFlag() throws Exception { 13939 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 13940 .thenReturn(true); 13941 final NotificationRecord parent = generateNotificationRecord( 13942 mTestNotificationChannel, 1, "group", true); 13943 final NotificationRecord child = generateNotificationRecord( 13944 mTestNotificationChannel, 2, "group", false); 13945 final NotificationRecord child2 = generateNotificationRecord( 13946 mTestNotificationChannel, 3, "group", false); 13947 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 13948 final NotificationRecord newGroup = generateNotificationRecord( 13949 mTestNotificationChannel, 4, "group2", false); 13950 mService.addNotification(parent); 13951 mService.addNotification(child); 13952 mService.addNotification(child2); 13953 mService.addNotification(newGroup); 13954 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId()); 13955 waitForIdle(); 13956 StatusBarNotification[] notifs = 13957 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 13958 assertEquals(0, notifs.length); 13959 } 13960 13961 @Test 13962 public void testDeleteChannelGroupChecksForUijs() throws Exception { 13963 when(mCompanionMgr.getAssociations(mPkg, UserHandle.getUserId(mUid))) 13964 .thenReturn(singletonList(mock(AssociationInfo.class))); 13965 CountDownLatch latch = new CountDownLatch(2); 13966 mService.createNotificationChannelGroup(mPkg, mUid, 13967 new NotificationChannelGroup("group", "group"), true, false); 13968 new Thread(() -> { 13969 NotificationChannel notificationChannel = new NotificationChannel("id", "id", 13970 NotificationManager.IMPORTANCE_HIGH); 13971 notificationChannel.setGroup("group"); 13972 ParceledListSlice<NotificationChannel> pls = 13973 new ParceledListSlice(ImmutableList.of(notificationChannel)); 13974 try { 13975 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 13976 } catch (RemoteException e) { 13977 throw new RuntimeException(e); 13978 } 13979 latch.countDown(); 13980 }).start(); 13981 new Thread(() -> { 13982 try { 13983 synchronized (this) { 13984 wait(5000); 13985 } 13986 mService.createNotificationChannelGroup(mPkg, mUid, 13987 new NotificationChannelGroup("new", "new group"), true, false); 13988 NotificationChannel notificationChannel = 13989 new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH); 13990 notificationChannel.setGroup("new"); 13991 ParceledListSlice<NotificationChannel> pls = 13992 new ParceledListSlice(ImmutableList.of(notificationChannel)); 13993 try { 13994 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 13995 mBinderService.deleteNotificationChannelGroup(mPkg, "group"); 13996 } catch (RemoteException e) { 13997 throw new RuntimeException(e); 13998 } 13999 } catch (Exception e) { 14000 e.printStackTrace(); 14001 } 14002 latch.countDown(); 14003 }).start(); 14004 14005 latch.await(); 14006 verify(mJsi).isNotificationChannelAssociatedWithAnyUserInitiatedJobs( 14007 anyString(), anyInt(), anyString()); 14008 } 14009 14010 @Test 14011 public void testRemoveUserInitiatedJobFlagFromNotification_enqueued() { 14012 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 14013 .thenReturn(true); 14014 Notification n = new Notification.Builder(mContext, "").build(); 14015 n.flags |= FLAG_USER_INITIATED_JOB; 14016 14017 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 14018 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14019 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14020 14021 mService.addEnqueuedNotification(r); 14022 14023 mInternalService.removeUserInitiatedJobFlagFromNotification( 14024 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 14025 14026 waitForIdle(); 14027 14028 verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); 14029 } 14030 14031 @Test 14032 public void testRemoveUserInitiatedJobFlagFromNotification_posted() { 14033 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 14034 .thenReturn(true); 14035 Notification n = new Notification.Builder(mContext, "").build(); 14036 n.flags |= FLAG_USER_INITIATED_JOB; 14037 14038 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 14039 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14040 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14041 14042 mService.addNotification(r); 14043 14044 mInternalService.removeUserInitiatedJobFlagFromNotification( 14045 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 14046 14047 waitForIdle(); 14048 14049 ArgumentCaptor<NotificationRecord> captor = 14050 ArgumentCaptor.forClass(NotificationRecord.class); 14051 verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); 14052 14053 assertEquals(0, captor.getValue().getNotification().flags); 14054 } 14055 14056 @Test 14057 public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_enqueued() { 14058 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 14059 Notification n = new Notification.Builder(mContext, "").build(); 14060 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 14061 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14062 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14063 mService.addEnqueuedNotification(r); 14064 } 14065 Notification n = new Notification.Builder(mContext, "").build(); 14066 n.flags |= FLAG_USER_INITIATED_JOB; 14067 14068 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 14069 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 14070 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14071 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14072 14073 mService.addEnqueuedNotification(r); 14074 14075 mInternalService.removeUserInitiatedJobFlagFromNotification( 14076 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 14077 14078 waitForIdle(); 14079 14080 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 14081 mService.getNotificationRecordCount()); 14082 } 14083 14084 @Test 14085 public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_posted() { 14086 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 14087 .thenReturn(true); 14088 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 14089 Notification n = new Notification.Builder(mContext, "").build(); 14090 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 14091 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14092 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14093 mService.addNotification(r); 14094 } 14095 Notification n = new Notification.Builder(mContext, "").build(); 14096 n.flags |= FLAG_USER_INITIATED_JOB; 14097 14098 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 14099 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 14100 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14101 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14102 14103 mService.addNotification(r); 14104 14105 mInternalService.removeUserInitiatedJobFlagFromNotification( 14106 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 14107 14108 waitForIdle(); 14109 14110 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 14111 mService.getNotificationRecordCount()); 14112 } 14113 14114 @Test 14115 public void testCanPostUijWhenOverLimit() throws RemoteException { 14116 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 14117 .thenReturn(true); 14118 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 14119 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 14120 i, null, false).getSbn(); 14121 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCanPostUijWhenOverLimit", 14122 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 14123 } 14124 14125 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 14126 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 14127 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 14128 "testCanPostUijWhenOverLimit - uij over limit!", 14129 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 14130 14131 waitForIdle(); 14132 14133 StatusBarNotification[] notifs = 14134 mBinderService.getActiveNotifications(sbn.getPackageName()); 14135 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 14136 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 14137 mService.getNotificationRecordCount()); 14138 } 14139 14140 @Test 14141 public void testCannotPostNonUijWhenOverLimit() throws RemoteException { 14142 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 14143 .thenReturn(true); 14144 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 14145 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 14146 i, null, false).getSbn(); 14147 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCannotPostNonUijWhenOverLimit", 14148 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 14149 waitForIdle(); 14150 } 14151 14152 final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 14153 100, null, false).getSbn(); 14154 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 14155 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 14156 "testCannotPostNonUijWhenOverLimit - uij over limit!", 14157 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 14158 14159 final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel, 14160 101, null, false).getSbn(); 14161 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 14162 "testCannotPostNonUijWhenOverLimit - non uij over limit!", 14163 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId()); 14164 14165 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 14166 .thenReturn(false); 14167 final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel, 14168 101, null, false).getSbn(); 14169 sbn3.getNotification().flags |= FLAG_USER_INITIATED_JOB; 14170 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 14171 "testCannotPostNonUijWhenOverLimit - fake uij over limit!", 14172 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId()); 14173 14174 waitForIdle(); 14175 14176 StatusBarNotification[] notifs = 14177 mBinderService.getActiveNotifications(sbn.getPackageName()); 14178 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 14179 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 14180 mService.getNotificationRecordCount()); 14181 } 14182 14183 @Test 14184 public void fixNotification_withUijFlag_butIsNotUij() throws Exception { 14185 final ApplicationInfo applicationInfo = new ApplicationInfo(); 14186 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14187 .thenReturn(applicationInfo); 14188 14189 Notification n = new Notification.Builder(mContext, "test") 14190 .setFlag(FLAG_USER_INITIATED_JOB, true) 14191 .build(); 14192 14193 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14194 assertFalse(n.isUserInitiatedJob()); 14195 } 14196 14197 @Test 14198 public void enqueue_updatesEnqueueRate() throws Exception { 14199 Notification n = generateNotificationRecord(null).getNotification(); 14200 14201 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 14202 // Don't waitForIdle() here. We want to verify the "intermediate" state. 14203 14204 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 14205 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 14206 verify(mUsageStats, never()).registerPostedByApp(any()); 14207 14208 waitForIdle(); 14209 } 14210 14211 @Test 14212 public void enqueue_withPost_updatesEnqueueRateAndPost() throws Exception { 14213 Notification n = generateNotificationRecord(null).getNotification(); 14214 14215 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 14216 waitForIdle(); 14217 14218 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 14219 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 14220 verify(mUsageStats).registerPostedByApp(any()); 14221 } 14222 14223 @Test 14224 public void enqueueNew_whenOverEnqueueRate_accepts() throws Exception { 14225 Notification n = generateNotificationRecord(null).getNotification(); 14226 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 14227 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f); 14228 14229 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 14230 waitForIdle(); 14231 14232 assertThat(mService.mNotificationsByKey).hasSize(1); 14233 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 14234 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 14235 verify(mUsageStats).registerPostedByApp(any()); 14236 } 14237 14238 @Test 14239 public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception { 14240 // Post the first version. 14241 Notification original = generateNotificationRecord(null).getNotification(); 14242 original.when = System.currentTimeMillis(); 14243 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); 14244 waitForIdle(); 14245 assertThat(mService.mNotificationList).hasSize(1); 14246 assertThat(mService.mNotificationList.get(0).getNotification().when) 14247 .isEqualTo(original.when); 14248 14249 reset(mUsageStats); 14250 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 14251 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE - 1f); 14252 14253 // Post the update. 14254 Notification update = generateNotificationRecord(null).getNotification(); 14255 update.when = System.currentTimeMillis() + 111; 14256 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); 14257 waitForIdle(); 14258 14259 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 14260 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 14261 verify(mUsageStats, never()).registerPostedByApp(any()); 14262 verify(mUsageStats).registerUpdatedByApp(any(), any()); 14263 assertThat(mService.mNotificationList).hasSize(1); 14264 assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when); 14265 } 14266 14267 @Test 14268 public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception { 14269 // Post the first version. 14270 Notification original = generateNotificationRecord(null).getNotification(); 14271 original.when = System.currentTimeMillis(); 14272 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); 14273 waitForIdle(); 14274 assertThat(mService.mNotificationList).hasSize(1); 14275 assertThat(mService.mNotificationList.get(0).getNotification().when) 14276 .isEqualTo(original.when); 14277 14278 reset(mUsageStats); 14279 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 14280 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f); 14281 14282 // Post the update. 14283 Notification update = generateNotificationRecord(null).getNotification(); 14284 update.when = System.currentTimeMillis() + 111; 14285 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); 14286 waitForIdle(); 14287 14288 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 14289 verify(mUsageStats, never()).registerEnqueuedByAppAndAccepted(any()); 14290 verify(mUsageStats, never()).registerPostedByApp(any()); 14291 verify(mUsageStats, never()).registerUpdatedByApp(any(), any()); 14292 assertThat(mService.mNotificationList).hasSize(1); 14293 assertThat(mService.mNotificationList.get(0).getNotification().when) 14294 .isEqualTo(original.when); // old 14295 } 14296 14297 @Test 14298 @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) 14299 public void enqueueNotification_acceptsCorrectToken() throws RemoteException { 14300 Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) 14301 .setContentIntent(createPendingIntent("content")) 14302 .build(); 14303 Notification received = parcelAndUnparcel(sent, Notification.CREATOR); 14304 assertThat(received.getAllowlistToken()).isEqualTo( 14305 NotificationManagerService.ALLOWLIST_TOKEN); 14306 14307 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 14308 parcelAndUnparcel(received, Notification.CREATOR), mUserId); 14309 waitForIdle(); 14310 14311 assertThat(mService.mNotificationList).hasSize(1); 14312 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 14313 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 14314 } 14315 14316 @Test 14317 @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) 14318 public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException { 14319 Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) 14320 .setContentIntent(createPendingIntent("content")) 14321 .build(); 14322 assertThat(receivedWithoutParceling.getAllowlistToken()).isNull(); 14323 14324 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 14325 parcelAndUnparcel(receivedWithoutParceling, Notification.CREATOR), mUserId); 14326 waitForIdle(); 14327 14328 assertThat(mService.mNotificationList).hasSize(1); 14329 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 14330 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 14331 } 14332 14333 @Test 14334 @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) 14335 public void enqueueNotification_rejectsOtherToken() throws RemoteException { 14336 Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) 14337 .setContentIntent(createPendingIntent("content")) 14338 .build(); 14339 sent.overrideAllowlistToken(new Binder()); 14340 Notification received = parcelAndUnparcel(sent, Notification.CREATOR); 14341 assertThat(received.getAllowlistToken()).isEqualTo(sent.getAllowlistToken()); 14342 14343 assertThrows(SecurityException.class, () -> 14344 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 14345 parcelAndUnparcel(received, Notification.CREATOR), mUserId)); 14346 waitForIdle(); 14347 14348 assertThat(mService.mNotificationList).isEmpty(); 14349 } 14350 14351 @Test 14352 @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) 14353 public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents() 14354 throws RemoteException { 14355 Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) 14356 .setContentIntent(createPendingIntent("content")) 14357 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) 14358 .setContentIntent(createPendingIntent("public")) 14359 .build()) 14360 .build(); 14361 sentFromApp.publicVersion.overrideAllowlistToken(new Binder()); 14362 14363 // Instead of using the normal parceling, assume the caller parcels it by hand, including a 14364 // null token in the outer notification (as would be expected, and as is verified by 14365 // enqueue) but trying to sneak in a different one in the inner notification, hoping it gets 14366 // propagated to the PendingIntents. 14367 Parcel parcelSentFromApp = Parcel.obtain(); 14368 writeNotificationToParcelCustom(parcelSentFromApp, sentFromApp, new ArraySet<>( 14369 Lists.newArrayList(sentFromApp.contentIntent, 14370 sentFromApp.publicVersion.contentIntent))); 14371 14372 // Use the unparceling as received in enqueueNotificationWithTag() 14373 parcelSentFromApp.setDataPosition(0); 14374 Notification receivedByNms = new Notification(parcelSentFromApp); 14375 14376 // Verify that all the pendingIntents have the correct token. 14377 assertThat(receivedByNms.contentIntent.getWhitelistToken()).isEqualTo( 14378 NotificationManagerService.ALLOWLIST_TOKEN); 14379 assertThat(receivedByNms.publicVersion.contentIntent.getWhitelistToken()).isEqualTo( 14380 NotificationManagerService.ALLOWLIST_TOKEN); 14381 } 14382 14383 /** 14384 * Replicates the behavior of {@link Notification#writeToParcel} but excluding the 14385 * "always use the same allowlist token as the root notification" parts. 14386 */ 14387 private static void writeNotificationToParcelCustom(Parcel parcel, Notification notif, 14388 ArraySet<PendingIntent> allPendingIntents) { 14389 int flags = 0; 14390 parcel.writeInt(1); // version? 14391 14392 parcel.writeStrongBinder(notif.getAllowlistToken()); 14393 parcel.writeLong(notif.when); 14394 parcel.writeLong(notif.creationTime); 14395 if (notif.getSmallIcon() != null) { 14396 parcel.writeInt(1); 14397 notif.getSmallIcon().writeToParcel(parcel, 0); 14398 } else { 14399 parcel.writeInt(0); 14400 } 14401 parcel.writeInt(notif.number); 14402 if (notif.contentIntent != null) { 14403 parcel.writeInt(1); 14404 notif.contentIntent.writeToParcel(parcel, 0); 14405 } else { 14406 parcel.writeInt(0); 14407 } 14408 if (notif.deleteIntent != null) { 14409 parcel.writeInt(1); 14410 notif.deleteIntent.writeToParcel(parcel, 0); 14411 } else { 14412 parcel.writeInt(0); 14413 } 14414 if (notif.tickerText != null) { 14415 parcel.writeInt(1); 14416 TextUtils.writeToParcel(notif.tickerText, parcel, flags); 14417 } else { 14418 parcel.writeInt(0); 14419 } 14420 if (notif.tickerView != null) { 14421 parcel.writeInt(1); 14422 notif.tickerView.writeToParcel(parcel, 0); 14423 } else { 14424 parcel.writeInt(0); 14425 } 14426 if (notif.contentView != null) { 14427 parcel.writeInt(1); 14428 notif.contentView.writeToParcel(parcel, 0); 14429 } else { 14430 parcel.writeInt(0); 14431 } 14432 if (notif.getLargeIcon() != null) { 14433 parcel.writeInt(1); 14434 notif.getLargeIcon().writeToParcel(parcel, 0); 14435 } else { 14436 parcel.writeInt(0); 14437 } 14438 14439 parcel.writeInt(notif.defaults); 14440 parcel.writeInt(notif.flags); 14441 14442 if (notif.sound != null) { 14443 parcel.writeInt(1); 14444 notif.sound.writeToParcel(parcel, 0); 14445 } else { 14446 parcel.writeInt(0); 14447 } 14448 parcel.writeInt(notif.audioStreamType); 14449 14450 if (notif.audioAttributes != null) { 14451 parcel.writeInt(1); 14452 notif.audioAttributes.writeToParcel(parcel, 0); 14453 } else { 14454 parcel.writeInt(0); 14455 } 14456 14457 parcel.writeLongArray(notif.vibrate); 14458 parcel.writeInt(notif.ledARGB); 14459 parcel.writeInt(notif.ledOnMS); 14460 parcel.writeInt(notif.ledOffMS); 14461 parcel.writeInt(notif.iconLevel); 14462 14463 if (notif.fullScreenIntent != null) { 14464 parcel.writeInt(1); 14465 notif.fullScreenIntent.writeToParcel(parcel, 0); 14466 } else { 14467 parcel.writeInt(0); 14468 } 14469 14470 parcel.writeInt(notif.priority); 14471 14472 parcel.writeString8(notif.category); 14473 14474 parcel.writeString8(notif.getGroup()); 14475 14476 parcel.writeString8(notif.getSortKey()); 14477 14478 parcel.writeBundle(notif.extras); // null ok 14479 14480 parcel.writeTypedArray(notif.actions, 0); // null ok 14481 14482 if (notif.bigContentView != null) { 14483 parcel.writeInt(1); 14484 notif.bigContentView.writeToParcel(parcel, 0); 14485 } else { 14486 parcel.writeInt(0); 14487 } 14488 14489 if (notif.headsUpContentView != null) { 14490 parcel.writeInt(1); 14491 notif.headsUpContentView.writeToParcel(parcel, 0); 14492 } else { 14493 parcel.writeInt(0); 14494 } 14495 14496 parcel.writeInt(notif.visibility); 14497 14498 if (notif.publicVersion != null) { 14499 parcel.writeInt(1); 14500 writeNotificationToParcelCustom(parcel, notif.publicVersion, new ArraySet<>()); 14501 } else { 14502 parcel.writeInt(0); 14503 } 14504 14505 parcel.writeInt(notif.color); 14506 14507 if (notif.getChannelId() != null) { 14508 parcel.writeInt(1); 14509 parcel.writeString8(notif.getChannelId()); 14510 } else { 14511 parcel.writeInt(0); 14512 } 14513 parcel.writeLong(notif.getTimeoutAfter()); 14514 14515 if (notif.getShortcutId() != null) { 14516 parcel.writeInt(1); 14517 parcel.writeString8(notif.getShortcutId()); 14518 } else { 14519 parcel.writeInt(0); 14520 } 14521 14522 if (notif.getLocusId() != null) { 14523 parcel.writeInt(1); 14524 notif.getLocusId().writeToParcel(parcel, 0); 14525 } else { 14526 parcel.writeInt(0); 14527 } 14528 14529 parcel.writeInt(notif.getBadgeIconType()); 14530 14531 if (notif.getSettingsText() != null) { 14532 parcel.writeInt(1); 14533 TextUtils.writeToParcel(notif.getSettingsText(), parcel, flags); 14534 } else { 14535 parcel.writeInt(0); 14536 } 14537 14538 parcel.writeInt(notif.getGroupAlertBehavior()); 14539 14540 if (notif.getBubbleMetadata() != null) { 14541 parcel.writeInt(1); 14542 notif.getBubbleMetadata().writeToParcel(parcel, 0); 14543 } else { 14544 parcel.writeInt(0); 14545 } 14546 14547 parcel.writeBoolean(notif.getAllowSystemGeneratedContextualActions()); 14548 14549 parcel.writeInt(Notification.FOREGROUND_SERVICE_DEFAULT); // no getter for mFgsDeferBehavior 14550 14551 // mUsesStandardHeader is not written because it should be recomputed in listeners 14552 14553 parcel.writeArraySet(allPendingIntents); 14554 } 14555 14556 @Test 14557 @SuppressWarnings("unchecked") 14558 @EnableFlags(android.app.Flags.FLAG_SECURE_ALLOWLIST_TOKEN) 14559 public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException { 14560 Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) 14561 .setContentIntent(createPendingIntent("content")) 14562 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) 14563 .setContentIntent(createPendingIntent("public")) 14564 .build()) 14565 .extend(new Notification.WearableExtender() 14566 .addPage(new Notification.Builder(mContext, TEST_CHANNEL_ID) 14567 .setContentIntent(createPendingIntent("wearPage")) 14568 .build())) 14569 .build(); 14570 // Binder transition: app -> NMS 14571 Notification receivedByNms = parcelAndUnparcel(sentFromApp, Notification.CREATOR); 14572 assertThat(receivedByNms.getAllowlistToken()).isEqualTo( 14573 NotificationManagerService.ALLOWLIST_TOKEN); 14574 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 14575 parcelAndUnparcel(receivedByNms, Notification.CREATOR), mUserId); 14576 waitForIdle(); 14577 assertThat(mService.mNotificationList).hasSize(1); 14578 Notification posted = mService.mNotificationList.get(0).getNotification(); 14579 assertThat(posted.getAllowlistToken()).isEqualTo( 14580 NotificationManagerService.ALLOWLIST_TOKEN); 14581 assertThat(posted.contentIntent.getWhitelistToken()).isEqualTo( 14582 NotificationManagerService.ALLOWLIST_TOKEN); 14583 14584 ParceledListSlice<StatusBarNotification> listSentFromNms = 14585 mBinderService.getAppActiveNotifications(mPkg, mUserId); 14586 // Binder transition: NMS -> app. App doesn't have the allowlist token so clear it 14587 // (having a different one would produce the same effect; the relevant thing is to not let 14588 // out ALLOWLIST_TOKEN). 14589 // Note: for other tests, this is restored by constructing TestableNMS in setup(). 14590 Notification.processAllowlistToken = null; 14591 ParceledListSlice<StatusBarNotification> listReceivedByApp = parcelAndUnparcel( 14592 listSentFromNms, ParceledListSlice.CREATOR); 14593 Notification gottenBackByApp = listReceivedByApp.getList().get(0).getNotification(); 14594 14595 assertThat(gottenBackByApp.getAllowlistToken()).isNull(); 14596 assertThat(gottenBackByApp.contentIntent.getWhitelistToken()).isNull(); 14597 assertThat(gottenBackByApp.publicVersion.getAllowlistToken()).isNull(); 14598 assertThat(gottenBackByApp.publicVersion.contentIntent.getWhitelistToken()).isNull(); 14599 assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() 14600 .get(0).getAllowlistToken()).isNull(); 14601 assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() 14602 .get(0).contentIntent.getWhitelistToken()).isNull(); 14603 } 14604 14605 @Test 14606 public void enqueueNotification_allowlistsPendingIntents() throws RemoteException { 14607 PendingIntent contentIntent = createPendingIntent("content"); 14608 PendingIntent actionIntent1 = createPendingIntent("action1"); 14609 PendingIntent actionIntent2 = createPendingIntent("action2"); 14610 Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID) 14611 .setContentIntent(contentIntent) 14612 .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build()) 14613 .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build()) 14614 .build(); 14615 14616 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 14617 parcelAndUnparcel(n, Notification.CREATOR), mUserId); 14618 14619 verify(mAmi, times(3)).setPendingIntentAllowlistDuration( 14620 any(), any(), anyLong(), 14621 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED), 14622 eq(REASON_NOTIFICATION_SERVICE), any()); 14623 verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(), 14624 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER)); 14625 contentIntent.cancel(); 14626 actionIntent2.cancel(); 14627 actionIntent1.cancel(); 14628 } 14629 14630 @Test 14631 public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion() 14632 throws RemoteException { 14633 PendingIntent contentIntent = createPendingIntent("content"); 14634 PendingIntent actionIntent = createPendingIntent("action"); 14635 PendingIntent publicContentIntent = createPendingIntent("publicContent"); 14636 PendingIntent publicActionIntent = createPendingIntent("publicAction"); 14637 Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID) 14638 .setContentIntent(contentIntent) 14639 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build()) 14640 .setPublicVersion(new Notification.Builder(mContext, "channel") 14641 .setContentIntent(publicContentIntent) 14642 .addAction(new Notification.Action.Builder( 14643 null, "publicAction", publicActionIntent).build()) 14644 .build()) 14645 .build(); 14646 14647 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 14648 parcelAndUnparcel(source, Notification.CREATOR), mUserId); 14649 14650 verify(mAmi, times(4)).setPendingIntentAllowlistDuration( 14651 any(), any(), anyLong(), 14652 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED), 14653 eq(REASON_NOTIFICATION_SERVICE), any()); 14654 verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(), 14655 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER)); 14656 contentIntent.cancel(); 14657 publicContentIntent.cancel(); 14658 actionIntent.cancel(); 14659 publicActionIntent.cancel(); 14660 } 14661 14662 @Test 14663 @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL) 14664 public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() { 14665 mService.mZenModeHelper = mock(ZenModeHelper.class); 14666 mService.setPreferencesHelper(mPreferencesHelper); 14667 14668 UserInfo prevUser = new UserInfo(); 14669 prevUser.id = 10; 14670 UserInfo newUser = new UserInfo(); 14671 newUser.id = 20; 14672 14673 mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser)); 14674 14675 InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper); 14676 inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20)); 14677 inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd(); 14678 inOrder.verifyNoMoreInteractions(); 14679 } 14680 14681 @Test 14682 @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL) 14683 public void onUserSwitched_broadcast_updatesZenModeAndChannelsBypassingDnd() { 14684 Intent intent = new Intent(Intent.ACTION_USER_SWITCHED); 14685 intent.putExtra(Intent.EXTRA_USER_HANDLE, 20); 14686 mService.mZenModeHelper = mock(ZenModeHelper.class); 14687 mService.setPreferencesHelper(mPreferencesHelper); 14688 14689 mUserIntentReceiver.onReceive(mContext, intent); 14690 14691 InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper); 14692 inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20)); 14693 inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd(); 14694 inOrder.verifyNoMoreInteractions(); 14695 } 14696 14697 @Test 14698 public void isNotificationPolicyAccessGranted_invalidPackage() throws Exception { 14699 final String notReal = "NOT REAL"; 14700 final var checker = mService.permissionChecker; 14701 14702 when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( 14703 PackageManager.NameNotFoundException.class); 14704 14705 assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse(); 14706 verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt()); 14707 verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean()); 14708 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt()); 14709 verify(mListeners, never()).isComponentEnabledForPackage(any()); 14710 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 14711 } 14712 14713 @Test 14714 public void isNotificationPolicyAccessGranted_hasPermission() throws Exception { 14715 final String packageName = "target"; 14716 final int uid = 123; 14717 final var checker = mService.permissionChecker; 14718 14719 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 14720 when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true)) 14721 .thenReturn(PackageManager.PERMISSION_GRANTED); 14722 14723 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 14724 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 14725 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 14726 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt()); 14727 verify(mListeners, never()).isComponentEnabledForPackage(any()); 14728 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 14729 } 14730 14731 @Test 14732 public void isNotificationPolicyAccessGranted_isPackageAllowed() throws Exception { 14733 final String packageName = "target"; 14734 final int uid = 123; 14735 final var checker = mService.permissionChecker; 14736 14737 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 14738 when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt())) 14739 .thenReturn(true); 14740 14741 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 14742 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 14743 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 14744 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 14745 verify(mListeners, never()).isComponentEnabledForPackage(any()); 14746 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 14747 } 14748 14749 @Test 14750 public void isNotificationPolicyAccessGranted_isComponentEnabled() throws Exception { 14751 final String packageName = "target"; 14752 final int uid = 123; 14753 final var checker = mService.permissionChecker; 14754 14755 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 14756 when(mListeners.isComponentEnabledForPackage(packageName)).thenReturn(true); 14757 14758 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 14759 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 14760 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 14761 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 14762 verify(mListeners).isComponentEnabledForPackage(packageName); 14763 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 14764 } 14765 14766 @Test 14767 public void isNotificationPolicyAccessGranted_isDeviceOwner() throws Exception { 14768 final String packageName = "target"; 14769 final int uid = 123; 14770 final var checker = mService.permissionChecker; 14771 14772 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 14773 when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true); 14774 14775 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 14776 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 14777 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 14778 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 14779 verify(mListeners).isComponentEnabledForPackage(packageName); 14780 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 14781 } 14782 14783 /** 14784 * b/292163859 14785 */ 14786 @Test 14787 public void isNotificationPolicyAccessGranted_callerIsDeviceOwner() throws Exception { 14788 final String packageName = "target"; 14789 final int uid = 123; 14790 final int callingUid = Binder.getCallingUid(); 14791 final var checker = mService.permissionChecker; 14792 14793 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 14794 when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true); 14795 14796 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 14797 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 14798 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 14799 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 14800 verify(mListeners).isComponentEnabledForPackage(packageName); 14801 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 14802 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid); 14803 } 14804 14805 @Test 14806 public void isNotificationPolicyAccessGranted_notGranted() throws Exception { 14807 final String packageName = "target"; 14808 final int uid = 123; 14809 final var checker = mService.permissionChecker; 14810 14811 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 14812 14813 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 14814 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 14815 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 14816 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 14817 verify(mListeners).isComponentEnabledForPackage(packageName); 14818 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 14819 } 14820 14821 @Test 14822 public void testResetDefaultDnd() { 14823 TestableNotificationManagerService service = spy(mService); 14824 UserInfo user = new UserInfo(0, "owner", 0); 14825 when(mUm.getAliveUsers()).thenReturn(List.of(user)); 14826 doReturn(false).when(service).isDNDMigrationDone(anyInt()); 14827 14828 service.resetDefaultDndIfNecessary(); 14829 14830 verify(mConditionProviders, times(1)).removeDefaultFromConfig(user.id); 14831 verify(mConditionProviders, times(1)).resetDefaultFromConfig(); 14832 verify(service, times(1)).allowDndPackages(user.id); 14833 verify(service, times(1)).setDNDMigrationDone(user.id); 14834 } 14835 14836 @Test 14837 public void testProfileUnavailableIntent() throws RemoteException { 14838 mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE, 14839 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 14840 simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE); 14841 verify(mWorkerHandler).post(any(Runnable.class)); 14842 verify(mSnoozeHelper).clearData(anyInt()); 14843 } 14844 14845 14846 @Test 14847 public void testManagedProfileUnavailableIntent() throws RemoteException { 14848 mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE, 14849 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 14850 simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 14851 verify(mWorkerHandler).post(any(Runnable.class)); 14852 verify(mSnoozeHelper).clearData(anyInt()); 14853 } 14854 14855 @Test 14856 @EnableFlags(android.app.Flags.FLAG_MODES_API) 14857 public void setDeviceEffectsApplier_succeeds() throws Exception { 14858 initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY); 14859 14860 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)); 14861 // No exception! 14862 } 14863 14864 @Test 14865 @EnableFlags(android.app.Flags.FLAG_MODES_API) 14866 public void setDeviceEffectsApplier_tooLate_throws() throws Exception { 14867 initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); 14868 14869 assertThrows(IllegalStateException.class, () -> 14870 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class))); 14871 } 14872 14873 @Test 14874 @EnableFlags(android.app.Flags.FLAG_MODES_API) 14875 public void setDeviceEffectsApplier_calledTwice_throws() throws Exception { 14876 initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY); 14877 14878 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)); 14879 assertThrows(IllegalStateException.class, () -> 14880 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class))); 14881 } 14882 14883 @Test 14884 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14885 public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException { 14886 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 14887 mService.setCallerIsNormalPackage(); 14888 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 14889 mService.mZenModeHelper = zenHelper; 14890 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 14891 .thenReturn(true); 14892 14893 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 14894 mBinderService.setNotificationPolicy("package", policy, false); 14895 14896 verify(zenHelper).applyGlobalPolicyAsImplicitZenRule(eq("package"), anyInt(), eq(policy)); 14897 } 14898 14899 @Test 14900 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14901 public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException { 14902 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 14903 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 14904 mService.mZenModeHelper = zenModeHelper; 14905 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 14906 .thenReturn(true); 14907 mService.isSystemUid = true; 14908 14909 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 14910 mBinderService.setNotificationPolicy("package", policy, false); 14911 14912 verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt()); 14913 } 14914 14915 @Test 14916 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14917 public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy() 14918 throws RemoteException { 14919 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 14920 AssociationRequest.DEVICE_PROFILE_WATCH, true); 14921 } 14922 14923 @Test 14924 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14925 public void setNotificationPolicy_autoCompanionApp_setsGlobalPolicy() 14926 throws RemoteException { 14927 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 14928 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true); 14929 } 14930 14931 @Test 14932 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14933 public void setNotificationPolicy_otherCompanionApp_doesNotSetGlobalPolicy() 14934 throws RemoteException { 14935 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 14936 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false); 14937 } 14938 14939 private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 14940 @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy) 14941 throws RemoteException { 14942 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 14943 mService.setCallerIsNormalPackage(); 14944 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 14945 mService.mZenModeHelper = zenModeHelper; 14946 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 14947 .thenReturn(true); 14948 when(mCompanionMgr.getAssociations(anyString(), anyInt())) 14949 .thenReturn(ImmutableList.of( 14950 new AssociationInfo.Builder(1, mUserId, "package") 14951 .setDisplayName("My connected device") 14952 .setDeviceProfile(deviceProfile) 14953 .build())); 14954 14955 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 14956 mBinderService.setNotificationPolicy("package", policy, false); 14957 14958 if (canSetGlobalPolicy) { 14959 verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt()); 14960 } else { 14961 verify(zenModeHelper).applyGlobalPolicyAsImplicitZenRule(anyString(), anyInt(), 14962 eq(policy)); 14963 } 14964 } 14965 14966 @Test 14967 @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14968 public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException { 14969 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 14970 mService.setCallerIsNormalPackage(); 14971 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 14972 mService.mZenModeHelper = zenModeHelper; 14973 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 14974 .thenReturn(true); 14975 14976 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 14977 mBinderService.setNotificationPolicy("package", policy, false); 14978 14979 verify(zenModeHelper).setNotificationPolicy(eq(policy), anyInt(), anyInt()); 14980 } 14981 14982 @Test 14983 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14984 public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException { 14985 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 14986 mService.setCallerIsNormalPackage(); 14987 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 14988 mService.mZenModeHelper = zenHelper; 14989 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 14990 .thenReturn(true); 14991 14992 mBinderService.getNotificationPolicy("package"); 14993 14994 verify(zenHelper).getNotificationPolicyFromImplicitZenRule(eq("package")); 14995 } 14996 14997 @Test 14998 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 14999 public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException { 15000 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 15001 mService.setCallerIsNormalPackage(); 15002 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 15003 mService.mZenModeHelper = zenHelper; 15004 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 15005 .thenReturn(true); 15006 15007 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 15008 15009 verify(zenHelper).applyGlobalZenModeAsImplicitZenRule(eq("package"), anyInt(), 15010 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 15011 } 15012 15013 @Test 15014 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15015 public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException { 15016 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 15017 mService.setCallerIsNormalPackage(); 15018 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 15019 mService.mZenModeHelper = zenModeHelper; 15020 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 15021 .thenReturn(true); 15022 mService.isSystemUid = true; 15023 15024 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 15025 15026 verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null), 15027 eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), eq("package"), 15028 anyInt()); 15029 } 15030 15031 @Test 15032 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15033 public void setInterruptionFilter_watchCompanionApp_setsGlobalZen() throws RemoteException { 15034 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 15035 AssociationRequest.DEVICE_PROFILE_WATCH, true); 15036 } 15037 15038 @Test 15039 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15040 public void setInterruptionFilter_autoCompanionApp_setsGlobalZen() throws RemoteException { 15041 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 15042 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true); 15043 } 15044 15045 @Test 15046 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15047 public void setInterruptionFilter_otherCompanionApp_doesNotSetGlobalZen() 15048 throws RemoteException { 15049 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 15050 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false); 15051 } 15052 15053 private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 15054 @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy) 15055 throws RemoteException { 15056 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 15057 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 15058 mService.mZenModeHelper = zenModeHelper; 15059 mService.setCallerIsNormalPackage(); 15060 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 15061 .thenReturn(true); 15062 when(mCompanionMgr.getAssociations(anyString(), anyInt())) 15063 .thenReturn(ImmutableList.of( 15064 new AssociationInfo.Builder(1, mUserId, "package") 15065 .setDisplayName("My connected device") 15066 .setDeviceProfile(deviceProfile) 15067 .build())); 15068 15069 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 15070 15071 if (canSetGlobalPolicy) { 15072 verify(zenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null), 15073 eq(ZenModeConfig.UPDATE_ORIGIN_APP), anyString(), eq("package"), anyInt()); 15074 } else { 15075 verify(zenModeHelper).applyGlobalZenModeAsImplicitZenRule(anyString(), anyInt(), 15076 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 15077 } 15078 } 15079 15080 @Test 15081 @EnableFlags(android.app.Flags.FLAG_MODES_API) 15082 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15083 public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen() 15084 throws Exception { 15085 mService.setCallerIsNormalPackage(); 15086 mService.mZenModeHelper = mock(ZenModeHelper.class); 15087 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 15088 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 15089 info.component = new ComponentName("pkg", "cls"); 15090 15091 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 15092 INTERRUPTION_FILTER_PRIORITY); 15093 15094 verify(mService.mZenModeHelper).applyGlobalZenModeAsImplicitZenRule(eq("pkg"), eq(mUid), 15095 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 15096 } 15097 15098 @Test 15099 @EnableFlags(android.app.Flags.FLAG_MODES_API) 15100 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15101 public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen() 15102 throws Exception { 15103 mService.isSystemUid = true; 15104 mService.mZenModeHelper = mock(ZenModeHelper.class); 15105 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 15106 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 15107 info.component = new ComponentName("pkg", "cls"); 15108 15109 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 15110 INTERRUPTION_FILTER_PRIORITY); 15111 15112 verify(mService.mZenModeHelper).setManualZenMode(eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), 15113 eq(null), eq(ZenModeConfig.UPDATE_ORIGIN_SYSTEM_OR_SYSTEMUI), anyString(), 15114 eq("pkg"), eq(mUid)); 15115 } 15116 15117 @Test 15118 @DisableFlags(android.app.Flags.FLAG_MODES_API) 15119 public void requestInterruptionFilterFromListener_flagOff_callsRequestFromListener() 15120 throws Exception { 15121 mService.setCallerIsNormalPackage(); 15122 mService.mZenModeHelper = mock(ZenModeHelper.class); 15123 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 15124 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 15125 info.component = new ComponentName("pkg", "cls"); 15126 15127 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 15128 INTERRUPTION_FILTER_PRIORITY); 15129 15130 verify(mService.mZenModeHelper).requestFromListener(eq(info.component), 15131 eq(INTERRUPTION_FILTER_PRIORITY), eq(mUid), /* fromSystemOrSystemUi= */ eq(false)); 15132 } 15133 15134 @Test 15135 @EnableFlags(android.app.Flags.FLAG_MODES_API) 15136 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15137 public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception { 15138 setUpRealZenTest(); 15139 mService.setCallerIsNormalPackage(); 15140 assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); 15141 15142 // Create an implicit zen rule by calling setNotificationPolicy from an app. 15143 mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false); 15144 assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); 15145 Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( 15146 mBinderService.getAutomaticZenRules().entrySet()); 15147 assertThat(rule.getValue().getOwner()).isNull(); 15148 assertThat(rule.getValue().getConfigurationActivity()).isNull(); 15149 15150 // Now try to update said rule (e.g. disable it). Should fail. 15151 // We also validate the exception message because NPE could be thrown by all sorts of test 15152 // issues (e.g. misconfigured mocks). 15153 rule.getValue().setEnabled(false); 15154 NullPointerException e = assertThrows(NullPointerException.class, 15155 () -> mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false)); 15156 assertThat(e.getMessage()).isEqualTo( 15157 "Rule must have a ConditionProviderService and/or configuration activity"); 15158 } 15159 15160 @Test 15161 @EnableFlags(android.app.Flags.FLAG_MODES_API) 15162 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 15163 public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception { 15164 setUpRealZenTest(); 15165 mService.setCallerIsNormalPackage(); 15166 assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); 15167 15168 // Create an implicit zen rule by calling setNotificationPolicy from an app. 15169 mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false); 15170 assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); 15171 Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( 15172 mBinderService.getAutomaticZenRules().entrySet()); 15173 assertThat(rule.getValue().getOwner()).isNull(); 15174 assertThat(rule.getValue().getConfigurationActivity()).isNull(); 15175 15176 // Now update said rule from Settings (e.g. disable it). Should work! 15177 mService.isSystemUid = true; 15178 rule.getValue().setEnabled(false); 15179 mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false); 15180 15181 Map.Entry<String, AutomaticZenRule> updatedRule = getOnlyElement( 15182 mBinderService.getAutomaticZenRules().entrySet()); 15183 assertThat(updatedRule.getValue().isEnabled()).isFalse(); 15184 } 15185 15186 /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */ 15187 private void setUpRealZenTest() throws Exception { 15188 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 15189 .thenReturn(true); 15190 15191 int iconResId = 79; 15192 String iconResName = "icon_79"; 15193 String pkg = mContext.getPackageName(); 15194 ApplicationInfo appInfoSpy = spy(new ApplicationInfo()); 15195 appInfoSpy.icon = iconResId; 15196 when(appInfoSpy.loadLabel(any())).thenReturn("Test App"); 15197 when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy); 15198 15199 when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName); 15200 when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId); 15201 when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources); 15202 } 15203 15204 @Test 15205 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) 15206 public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception { 15207 Notification n = new Notification.Builder(mContext, "test") 15208 .setFlag(FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true) 15209 .build(); 15210 15211 assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 15212 15213 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15214 15215 assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0); 15216 } 15217 15218 @Test 15219 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne() 15220 throws RemoteException { 15221 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 15222 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 15223 15224 // Create recent notification. 15225 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 15226 System.currentTimeMillis()); 15227 mService.addNotification(nr1); 15228 15229 // Create old notification. 15230 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 15231 System.currentTimeMillis() - 60000); 15232 mService.addNotification(nr2); 15233 15234 // Cancel specific notifications via listener. 15235 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 15236 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15237 waitForIdle(); 15238 15239 // Notifications should not be active anymore. 15240 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 15241 assertThat(notifications).isEmpty(); 15242 assertEquals(0, mService.getNotificationRecordCount()); 15243 // Ensure cancel event is logged. 15244 verify(mAppOpsManager).noteOpNoThrow( 15245 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null); 15246 } 15247 15248 @Test 15249 public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException { 15250 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 15251 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 15252 15253 // Create old notifications. 15254 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 15255 System.currentTimeMillis() - 60000); 15256 mService.addNotification(nr1); 15257 15258 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 15259 System.currentTimeMillis() - 60000); 15260 mService.addNotification(nr2); 15261 15262 // Cancel specific notifications via listener. 15263 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 15264 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15265 waitForIdle(); 15266 15267 // Notifications should not be active anymore. 15268 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 15269 assertThat(notifications).isEmpty(); 15270 assertEquals(0, mService.getNotificationRecordCount()); 15271 // Ensure cancel event is not logged. 15272 verify(mAppOpsManager, never()).noteOpNoThrow( 15273 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 15274 any(), any()); 15275 } 15276 15277 @Test 15278 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled() 15279 throws RemoteException { 15280 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 15281 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 15282 15283 // Create recent notification. 15284 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 15285 System.currentTimeMillis()); 15286 mService.addNotification(nr1); 15287 15288 // Create old notification. 15289 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 15290 System.currentTimeMillis() - 60000); 15291 mService.addNotification(nr2); 15292 15293 // Cancel specific notifications via listener. 15294 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 15295 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15296 waitForIdle(); 15297 15298 // Notifications should not be active anymore. 15299 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 15300 assertThat(notifications).isEmpty(); 15301 assertEquals(0, mService.getNotificationRecordCount()); 15302 // Ensure cancel event is not logged due to flag being disabled. 15303 verify(mAppOpsManager, never()).noteOpNoThrow( 15304 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 15305 any(), any()); 15306 } 15307 15308 @Test 15309 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll() 15310 throws RemoteException { 15311 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 15312 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 15313 15314 // Create recent notification. 15315 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 15316 System.currentTimeMillis()); 15317 mService.addNotification(nr1); 15318 15319 // Create old notification. 15320 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 15321 System.currentTimeMillis() - 60000); 15322 mService.addNotification(nr2); 15323 15324 // Cancel all notifications via listener. 15325 mService.getBinderService().cancelNotificationsFromListener(null, null); 15326 waitForIdle(); 15327 15328 // Notifications should not be active anymore. 15329 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 15330 assertThat(notifications).isEmpty(); 15331 assertEquals(0, mService.getNotificationRecordCount()); 15332 // Ensure cancel event is logged. 15333 verify(mAppOpsManager).noteOpNoThrow( 15334 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null); 15335 } 15336 15337 @Test 15338 public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException { 15339 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 15340 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 15341 15342 // Create old notifications. 15343 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 15344 System.currentTimeMillis() - 60000); 15345 mService.addNotification(nr1); 15346 15347 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 15348 System.currentTimeMillis() - 60000); 15349 mService.addNotification(nr2); 15350 15351 // Cancel all notifications via listener. 15352 mService.getBinderService().cancelNotificationsFromListener(null, null); 15353 waitForIdle(); 15354 15355 // Notifications should not be active anymore. 15356 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 15357 assertThat(notifications).isEmpty(); 15358 assertEquals(0, mService.getNotificationRecordCount()); 15359 // Ensure cancel event is not logged. 15360 verify(mAppOpsManager, never()).noteOpNoThrow( 15361 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 15362 any(), any()); 15363 } 15364 15365 @Test 15366 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled() 15367 throws RemoteException { 15368 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 15369 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 15370 15371 // Create recent notification. 15372 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 15373 System.currentTimeMillis()); 15374 mService.addNotification(nr1); 15375 15376 // Create old notification. 15377 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 15378 System.currentTimeMillis() - 60000); 15379 mService.addNotification(nr2); 15380 15381 // Cancel all notifications via listener. 15382 mService.getBinderService().cancelNotificationsFromListener(null, null); 15383 waitForIdle(); 15384 15385 // Notifications should not be active anymore. 15386 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 15387 assertThat(notifications).isEmpty(); 15388 assertEquals(0, mService.getNotificationRecordCount()); 15389 // Ensure cancel event is not logged due to flag being disabled. 15390 verify(mAppOpsManager, never()).noteOpNoThrow( 15391 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 15392 any(), any()); 15393 } 15394 15395 @Test 15396 @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) 15397 public void testSetPrivateNotificationsAllowed() throws Exception { 15398 when(mContext.checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) 15399 .thenReturn(PERMISSION_GRANTED); 15400 mBinderService.setPrivateNotificationsAllowed(false); 15401 Intent expected = new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) 15402 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false); 15403 ArgumentCaptor<Intent> actual = ArgumentCaptor.forClass(Intent.class); 15404 verify(mContext).sendBroadcast(actual.capture(), eq(STATUS_BAR_SERVICE)); 15405 15406 assertEquals(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED, actual.getValue().getAction()); 15407 assertFalse(actual.getValue().getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true)); 15408 assertFalse(mBinderService.getPrivateNotificationsAllowed()); 15409 } 15410 15411 @Test 15412 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 15413 public void testCallNotificationListener_NotifiedOnPostCallStyle() throws Exception { 15414 ICallNotificationEventCallback listener = mock( 15415 ICallNotificationEventCallback.class); 15416 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 15417 mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.CURRENT, listener); 15418 waitForIdle(); 15419 15420 final UserHandle userHandle = UserHandle.getUserHandleForUid(mUid); 15421 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, userHandle, 15422 "testCallNotificationListener_NotifiedOnPostCallStyle"); 15423 15424 verify(listener, times(1)).onCallNotificationPosted(mPkg, userHandle); 15425 15426 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 15427 r.getSbn().getUserId()); 15428 waitForIdle(); 15429 15430 verify(listener, times(1)).onCallNotificationRemoved(mPkg, userHandle); 15431 } 15432 15433 @Test 15434 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 15435 public void testCallNotificationListener_NotNotifiedOnPostNonCallStyle() throws Exception { 15436 ICallNotificationEventCallback listener = mock( 15437 ICallNotificationEventCallback.class); 15438 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 15439 mBinderService.registerCallNotificationEventListener(mPkg, 15440 UserHandle.getUserHandleForUid(mUid), listener); 15441 waitForIdle(); 15442 15443 Notification.Builder nb = new Notification.Builder(mContext, 15444 mTestNotificationChannel.getId()).setSmallIcon(android.R.drawable.sym_def_app_icon); 15445 final NotificationRecord r = createAndPostNotification(nb, 15446 "testCallNotificationListener_NotNotifiedOnPostNonCallStyle"); 15447 15448 verify(listener, never()).onCallNotificationPosted(anyString(), any()); 15449 15450 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 15451 r.getSbn().getUserId()); 15452 waitForIdle(); 15453 15454 verify(listener, never()).onCallNotificationRemoved(anyString(), any()); 15455 } 15456 15457 @Test 15458 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 15459 public void testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId() 15460 throws Exception { 15461 ICallNotificationEventCallback listener = mock( 15462 ICallNotificationEventCallback.class); 15463 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 15464 mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.ALL, listener); 15465 waitForIdle(); 15466 15467 final UserHandle otherUser = UserHandle.of(2); 15468 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, 15469 otherUser, "testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId"); 15470 15471 verify(listener, times(1)).onCallNotificationPosted(mPkg, otherUser); 15472 15473 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 15474 r.getSbn().getUserId()); 15475 waitForIdle(); 15476 15477 verify(listener, times(1)).onCallNotificationRemoved(mPkg, otherUser); 15478 } 15479 15480 @Test 15481 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 15482 public void testCallNotificationListener_differentPackage_notNotified() throws Exception { 15483 final String packageName = "package"; 15484 ICallNotificationEventCallback listener = mock( 15485 ICallNotificationEventCallback.class); 15486 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 15487 mBinderService.registerCallNotificationEventListener(packageName, UserHandle.ALL, listener); 15488 waitForIdle(); 15489 15490 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, 15491 UserHandle.of(mUserId), 15492 "testCallNotificationListener_differentPackage_notNotified"); 15493 15494 verify(listener, never()).onCallNotificationPosted(anyString(), any()); 15495 15496 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 15497 r.getSbn().getUserId()); 15498 waitForIdle(); 15499 15500 verify(listener, never()).onCallNotificationRemoved(anyString(), any()); 15501 } 15502 15503 @Test 15504 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 15505 public void rankingTime_newNotification_noisy_matchesSbn() throws Exception { 15506 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId); 15507 15508 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15509 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 15510 waitForIdle(); 15511 15512 NotificationRecord posted = mService.mNotificationList.get(0); 15513 long originalPostTime = posted.getSbn().getPostTime(); 15514 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 15515 } 15516 15517 @Test 15518 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 15519 public void rankingTime_newNotification_silent_matchesSbn() throws Exception { 15520 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 15521 NotificationRecord nr = generateNotificationRecord(low, mUserId); 15522 15523 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15524 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 15525 waitForIdle(); 15526 15527 NotificationRecord posted = mService.mNotificationList.get(0); 15528 long originalPostTime = posted.getSbn().getPostTime(); 15529 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 15530 } 15531 15532 @Test 15533 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 15534 public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception { 15535 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 15536 NotificationRecord nr = generateNotificationRecord(low, mUserId); 15537 15538 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15539 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 15540 waitForIdle(); 15541 NotificationRecord posted = mService.mNotificationList.get(0); 15542 long originalPostTime = posted.getSbn().getPostTime(); 15543 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 15544 15545 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15546 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 15547 waitForIdle(); 15548 assertThat(mService.mNotificationList.get(0).getRankingTimeMs()) 15549 .isEqualTo(originalPostTime); 15550 } 15551 15552 @Test 15553 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 15554 public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception { 15555 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 15556 NotificationRecord nr = generateNotificationRecord(low, 0, mUserId); 15557 15558 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15559 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 15560 waitForIdle(); 15561 NotificationRecord posted = mService.mNotificationList.get(0); 15562 long originalPostTime = posted.getSbn().getPostTime(); 15563 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 15564 15565 NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar"); 15566 // no attention helper mocked behavior needed because this does not make noise 15567 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15568 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(), 15569 nrUpdate.getSbn().getUserId()); 15570 waitForIdle(); 15571 15572 posted = mService.mNotificationList.get(0); 15573 assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime); 15574 assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime()); 15575 } 15576 15577 @Test 15578 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 15579 public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception { 15580 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 15581 NotificationRecord nr = generateNotificationRecord(low, mUserId); 15582 15583 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15584 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 15585 waitForIdle(); 15586 NotificationRecord posted = mService.mNotificationList.get(0); 15587 long originalPostTime = posted.getSbn().getPostTime(); 15588 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 15589 15590 NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId); 15591 when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() { 15592 public Object answer(InvocationOnMock invocation) { 15593 Object[] args = invocation.getArguments(); 15594 ((NotificationRecord) args[0]).resetRankingTime(); 15595 return 2; // beep 15596 } 15597 }); 15598 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 15599 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(), 15600 nrUpdate.getSbn().getUserId()); 15601 waitForIdle(); 15602 posted = mService.mNotificationList.get(0); 15603 assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime); 15604 assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime()); 15605 } 15606 15607 @Test 15608 @EnableFlags(android.app.Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) 15609 public void testRestrictAudioAttributes_listenersGetCorrectAttributes() throws Exception { 15610 NotificationChannel sound = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); 15611 sound.setSound(Uri.EMPTY, new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build()); 15612 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice( 15613 Arrays.asList(sound))); 15614 15615 Notification n = new Notification.Builder(mContext, "a") 15616 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15617 .build(); 15618 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 15619 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15620 15621 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 15622 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15623 waitForIdle(); 15624 15625 ArgumentCaptor<NotificationRecord> captor = 15626 ArgumentCaptor.forClass(NotificationRecord.class); 15627 verify(mListeners, times(1)).prepareNotifyPostedLocked( 15628 captor.capture(), any(), anyBoolean()); 15629 15630 assertThat(captor.getValue().getChannel().getAudioAttributes().getUsage()) 15631 .isEqualTo(USAGE_NOTIFICATION); 15632 } 15633 15634 @Test 15635 @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL) 15636 public void testFixNotification_missingTtl() throws Exception { 15637 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 15638 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15639 .build(); 15640 15641 mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 15642 15643 assertThat(n.getTimeoutAfter()).isEqualTo(NOTIFICATION_TTL); 15644 } 15645 15646 @Test 15647 @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL) 15648 public void testFixNotification_doesNotOverwriteTtl() throws Exception { 15649 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 15650 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15651 .setTimeoutAfter(20) 15652 .build(); 15653 15654 mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 15655 15656 assertThat(n.getTimeoutAfter()).isEqualTo(20); 15657 } 15658 15659 @Test 15660 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 15661 public void testRejectOldNotification_oldWhen() throws Exception { 15662 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 15663 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15664 .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis()) 15665 .build(); 15666 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 15667 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15668 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15669 15670 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 15671 .isFalse(); 15672 } 15673 15674 @Test 15675 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 15676 public void testRejectOldNotification_mediumOldWhen() throws Exception { 15677 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 15678 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15679 .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis()) 15680 .build(); 15681 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 15682 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15683 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15684 15685 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 15686 .isTrue(); 15687 } 15688 15689 @Test 15690 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 15691 public void testRejectOldNotification_zeroWhen() throws Exception { 15692 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 15693 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15694 .setWhen(0) 15695 .build(); 15696 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 15697 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15698 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15699 15700 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 15701 .isTrue(); 15702 } 15703 15704 @Test 15705 public void testClearUIJFromUninstallingPackage() throws Exception { 15706 NotificationRecord r = 15707 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar"); 15708 mService.addNotification(r); 15709 15710 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())) 15711 .thenThrow(PackageManager.NameNotFoundException.class); 15712 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 15713 15714 mInternalService.cancelNotification(mPkg, mPkg, mUid, 0, r.getSbn().getTag(), 15715 r.getSbn().getId(), mUserId); 15716 15717 // no exception 15718 } 15719 15720 @Test 15721 public void testPostFromMissingPackage_throws() throws Exception { 15722 NotificationRecord r = 15723 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar"); 15724 15725 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())) 15726 .thenThrow(PackageManager.NameNotFoundException.class); 15727 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 15728 15729 try { 15730 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 15731 r.getSbn().getId(), r.getSbn().getNotification(), 15732 r.getSbn().getUserId()); 15733 fail("Allowed to post a notification for an absent package"); 15734 } catch (SecurityException e) { 15735 // yay 15736 } 15737 } 15738 15739 @Test 15740 public void testGetEffectsSuppressor_noSuppressor() throws Exception { 15741 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 15742 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 15743 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true); 15744 assertThat(mBinderService.getEffectsSuppressor()).isNull(); 15745 } 15746 15747 @Test 15748 public void testGetEffectsSuppressor_suppressorSameApp() throws Exception { 15749 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 15750 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 15751 mService.isSystemUid = false; 15752 mService.isSystemAppId = false; 15753 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 15754 HINT_HOST_DISABLE_EFFECTS); 15755 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true); 15756 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); 15757 } 15758 15759 @Test 15760 public void testGetEffectsSuppressor_suppressorDiffApp() throws Exception { 15761 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 15762 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 15763 mService.isSystemUid = false; 15764 mService.isSystemAppId = false; 15765 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 15766 HINT_HOST_DISABLE_EFFECTS); 15767 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 15768 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(null); 15769 } 15770 15771 @Test 15772 public void testGetEffectsSuppressor_suppressorDiffAppSystemCaller() throws Exception { 15773 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 15774 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 15775 mService.isSystemUid = true; 15776 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 15777 HINT_HOST_DISABLE_EFFECTS); 15778 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 15779 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); 15780 } 15781 } 15782