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_GROUP_SUMMARY; 37 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 38 import static android.app.Notification.FLAG_NO_CLEAR; 39 import static android.app.Notification.FLAG_NO_DISMISS; 40 import static android.app.Notification.FLAG_ONGOING_EVENT; 41 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; 42 import static android.app.Notification.FLAG_PROMOTED_ONGOING; 43 import static android.app.Notification.FLAG_USER_INITIATED_JOB; 44 import static android.app.Notification.GROUP_ALERT_CHILDREN; 45 import static android.app.Notification.VISIBILITY_PRIVATE; 46 import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID; 47 import static android.app.NotificationChannel.NEWS_ID; 48 import static android.app.NotificationChannel.PROMOTIONS_ID; 49 import static android.app.NotificationChannel.RECS_ID; 50 import static android.app.NotificationChannel.SOCIAL_MEDIA_ID; 51 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; 52 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; 53 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; 54 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED; 55 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; 56 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; 57 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; 58 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; 59 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; 60 import static android.app.NotificationManager.EXTRA_BLOCKED_STATE; 61 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 62 import static android.app.NotificationManager.IMPORTANCE_HIGH; 63 import static android.app.NotificationManager.IMPORTANCE_LOW; 64 import static android.app.NotificationManager.IMPORTANCE_MAX; 65 import static android.app.NotificationManager.IMPORTANCE_MIN; 66 import static android.app.NotificationManager.IMPORTANCE_NONE; 67 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 68 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; 69 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS; 70 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 71 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 72 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 73 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 74 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 78 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 79 import static android.app.PendingIntent.FLAG_IMMUTABLE; 80 import static android.app.PendingIntent.FLAG_MUTABLE; 81 import static android.app.PendingIntent.FLAG_ONE_SHOT; 82 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; 83 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; 84 import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; 85 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 86 import static android.content.pm.PackageManager.FEATURE_TELECOM; 87 import static android.content.pm.PackageManager.FEATURE_WATCH; 88 import static android.content.pm.PackageManager.PERMISSION_DENIED; 89 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 90 import static android.media.AudioAttributes.USAGE_MEDIA; 91 import static android.media.AudioAttributes.USAGE_NOTIFICATION; 92 import static android.os.Build.VERSION_CODES.O_MR1; 93 import static android.os.Build.VERSION_CODES.P; 94 import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; 95 import static android.os.PowerManager.PARTIAL_WAKE_LOCK; 96 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE; 97 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; 98 import static android.os.UserHandle.USER_SYSTEM; 99 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; 100 import static android.os.UserManager.USER_TYPE_FULL_SYSTEM; 101 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; 102 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; 103 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; 104 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; 105 import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS; 106 import static android.service.notification.Adjustment.KEY_IMPORTANCE; 107 import static android.service.notification.Adjustment.KEY_TEXT_REPLIES; 108 import static android.service.notification.Adjustment.KEY_TYPE; 109 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; 110 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; 111 import static android.service.notification.Adjustment.TYPE_NEWS; 112 import static android.service.notification.Adjustment.TYPE_PROMOTION; 113 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA; 114 import static android.service.notification.Condition.SOURCE_CONTEXT; 115 import static android.service.notification.Condition.SOURCE_USER_ACTION; 116 import static android.service.notification.Condition.STATE_TRUE; 117 import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION; 118 import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT; 119 import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING; 120 import static android.service.notification.Flags.FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION; 121 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS; 122 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; 123 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; 124 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; 125 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 126 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; 127 import static android.service.notification.NotificationListenerService.REASON_CANCEL; 128 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; 129 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; 130 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; 131 import static android.view.Display.DEFAULT_DISPLAY; 132 import static android.view.Display.INVALID_DISPLAY; 133 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 134 135 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; 136 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; 137 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; 138 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; 139 import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL; 140 import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS; 141 import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY; 142 import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION; 143 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 144 import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL; 145 import static com.android.server.notification.NotificationManagerService.TAG; 146 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED; 147 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; 148 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED; 149 150 import static com.google.common.collect.Iterables.getOnlyElement; 151 import static com.google.common.truth.Truth.assertThat; 152 import static com.google.common.truth.Truth.assertWithMessage; 153 154 import static junit.framework.Assert.assertEquals; 155 import static junit.framework.Assert.assertFalse; 156 import static junit.framework.Assert.assertNotNull; 157 import static junit.framework.Assert.assertNotSame; 158 import static junit.framework.Assert.assertNull; 159 import static junit.framework.Assert.assertSame; 160 import static junit.framework.Assert.assertTrue; 161 import static junit.framework.Assert.fail; 162 163 import static org.junit.Assert.assertNotEquals; 164 import static org.junit.Assert.assertThrows; 165 import static org.mockito.ArgumentMatchers.isNull; 166 import static org.mockito.Matchers.anyBoolean; 167 import static org.mockito.Matchers.anyLong; 168 import static org.mockito.Matchers.anyString; 169 import static org.mockito.Matchers.eq; 170 import static org.mockito.Mockito.any; 171 import static org.mockito.Mockito.anyInt; 172 import static org.mockito.Mockito.atLeastOnce; 173 import static org.mockito.Mockito.clearInvocations; 174 import static org.mockito.Mockito.doAnswer; 175 import static org.mockito.Mockito.doNothing; 176 import static org.mockito.Mockito.doReturn; 177 import static org.mockito.Mockito.doThrow; 178 import static org.mockito.Mockito.inOrder; 179 import static org.mockito.Mockito.mock; 180 import static org.mockito.Mockito.never; 181 import static org.mockito.Mockito.reset; 182 import static org.mockito.Mockito.spy; 183 import static org.mockito.Mockito.timeout; 184 import static org.mockito.Mockito.times; 185 import static org.mockito.Mockito.verify; 186 import static org.mockito.Mockito.verifyNoMoreInteractions; 187 import static org.mockito.Mockito.when; 188 189 import static java.util.Collections.emptyList; 190 import static java.util.Collections.singletonList; 191 192 import android.Manifest; 193 import android.annotation.Nullable; 194 import android.annotation.SuppressLint; 195 import android.annotation.UserIdInt; 196 import android.app.ActivityManager; 197 import android.app.ActivityManagerInternal; 198 import android.app.AlarmManager; 199 import android.app.AppOpsManager; 200 import android.app.AutomaticZenRule; 201 import android.app.IActivityManager; 202 import android.app.ICallNotificationEventCallback; 203 import android.app.INotificationManager; 204 import android.app.ITransientNotification; 205 import android.app.IUriGrantsManager; 206 import android.app.Notification; 207 import android.app.Notification.MessagingStyle.Message; 208 import android.app.NotificationChannel; 209 import android.app.NotificationChannelGroup; 210 import android.app.NotificationManager; 211 import android.app.NotificationManager.Policy; 212 import android.app.PendingIntent; 213 import android.app.Person; 214 import android.app.RemoteInput; 215 import android.app.RemoteInputHistoryItem; 216 import android.app.StatsManager; 217 import android.app.ZenBypassingApp; 218 import android.app.admin.DevicePolicyManagerInternal; 219 import android.app.backup.BackupRestoreEventLogger; 220 import android.app.job.JobScheduler; 221 import android.app.role.RoleManager; 222 import android.app.usage.UsageStatsManagerInternal; 223 import android.companion.AssociationInfo; 224 import android.companion.AssociationRequest; 225 import android.companion.ICompanionDeviceManager; 226 import android.compat.testing.PlatformCompatChangeRule; 227 import android.content.BroadcastReceiver; 228 import android.content.ComponentName; 229 import android.content.ContentUris; 230 import android.content.Context; 231 import android.content.IIntentSender; 232 import android.content.Intent; 233 import android.content.IntentFilter; 234 import android.content.pm.ActivityInfo; 235 import android.content.pm.ApplicationInfo; 236 import android.content.pm.IPackageManager; 237 import android.content.pm.LauncherApps; 238 import android.content.pm.ModuleInfo; 239 import android.content.pm.PackageManager; 240 import android.content.pm.PackageManagerInternal; 241 import android.content.pm.ParceledListSlice; 242 import android.content.pm.ResolveInfo; 243 import android.content.pm.ShortcutInfo; 244 import android.content.pm.ShortcutServiceInternal; 245 import android.content.pm.UserInfo; 246 import android.content.pm.VersionedPackage; 247 import android.content.res.Resources; 248 import android.graphics.Bitmap; 249 import android.graphics.Color; 250 import android.graphics.drawable.Icon; 251 import android.media.AudioAttributes; 252 import android.media.AudioManager; 253 import android.media.session.MediaSession; 254 import android.net.Uri; 255 import android.os.Binder; 256 import android.os.Build; 257 import android.os.Bundle; 258 import android.os.IBinder; 259 import android.os.Looper; 260 import android.os.Parcel; 261 import android.os.Parcelable; 262 import android.os.PowerManager; 263 import android.os.PowerManager.WakeLock; 264 import android.os.Process; 265 import android.os.RemoteException; 266 import android.os.SystemClock; 267 import android.os.UserHandle; 268 import android.os.UserManager; 269 import android.os.WorkSource; 270 import android.permission.PermissionManager; 271 import android.platform.test.annotations.DisableFlags; 272 import android.platform.test.annotations.EnableFlags; 273 import android.platform.test.annotations.RequiresFlagsEnabled; 274 import android.platform.test.flag.junit.FlagsParameterization; 275 import android.platform.test.flag.junit.SetFlagsRule; 276 import android.platform.test.rule.LimitDevicesRule; 277 import android.provider.MediaStore; 278 import android.provider.Settings; 279 import android.service.notification.Adjustment; 280 import android.service.notification.Condition; 281 import android.service.notification.ConversationChannelWrapper; 282 import android.service.notification.DeviceEffectsApplier; 283 import android.service.notification.INotificationListener; 284 import android.service.notification.NotificationListenerFilter; 285 import android.service.notification.NotificationListenerService; 286 import android.service.notification.NotificationRankingUpdate; 287 import android.service.notification.NotificationStats; 288 import android.service.notification.StatusBarNotification; 289 import android.service.notification.ZenModeConfig; 290 import android.service.notification.ZenPolicy; 291 import android.telecom.TelecomManager; 292 import android.testing.TestWithLooperRule; 293 import android.testing.TestableContentResolver; 294 import android.testing.TestableLooper; 295 import android.testing.TestableLooper.RunWithLooper; 296 import android.testing.TestablePermissions; 297 import android.testing.TestableResources; 298 import android.text.Html; 299 import android.text.TextUtils; 300 import android.util.ArrayMap; 301 import android.util.ArraySet; 302 import android.util.AtomicFile; 303 import android.util.Log; 304 import android.util.Pair; 305 import android.util.Xml; 306 import android.view.accessibility.AccessibilityManager; 307 import android.widget.RemoteViews; 308 309 import androidx.test.InstrumentationRegistry; 310 import androidx.test.filters.SmallTest; 311 312 import com.android.internal.R; 313 import com.android.internal.config.sysui.TestableFlagResolver; 314 import com.android.internal.logging.InstanceIdSequence; 315 import com.android.internal.logging.InstanceIdSequenceFake; 316 import com.android.internal.messages.nano.SystemMessageProto; 317 import com.android.internal.statusbar.NotificationVisibility; 318 import com.android.internal.widget.LockPatternUtils; 319 import com.android.modules.utils.TypedXmlPullParser; 320 import com.android.modules.utils.TypedXmlSerializer; 321 import com.android.server.DeviceIdleInternal; 322 import com.android.server.LocalServices; 323 import com.android.server.SystemService; 324 import com.android.server.SystemService.TargetUser; 325 import com.android.server.UiServiceTestCase; 326 import com.android.server.job.JobSchedulerInternal; 327 import com.android.server.lights.LightsManager; 328 import com.android.server.lights.LogicalLight; 329 import com.android.server.notification.GroupHelper.NotificationAttributes; 330 import com.android.server.notification.NotificationManagerService.NotificationAssistants; 331 import com.android.server.notification.NotificationManagerService.NotificationListeners; 332 import com.android.server.notification.NotificationManagerService.PostNotificationTracker; 333 import com.android.server.notification.NotificationManagerService.PostNotificationTrackerFactory; 334 import com.android.server.pm.PackageManagerService; 335 import com.android.server.pm.UserManagerInternal; 336 import com.android.server.policy.PermissionPolicyInternal; 337 import com.android.server.statusbar.StatusBarManagerInternal; 338 import com.android.server.uri.UriGrantsManagerInternal; 339 import com.android.server.utils.quota.MultiRateLimiter; 340 import com.android.server.wm.ActivityTaskManagerInternal; 341 import com.android.server.wm.WindowManagerInternal; 342 343 import com.google.android.collect.Lists; 344 import com.google.common.collect.ImmutableList; 345 346 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; 347 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; 348 349 import org.junit.After; 350 import org.junit.Assert; 351 import org.junit.Before; 352 import org.junit.ClassRule; 353 import org.junit.Rule; 354 import org.junit.Test; 355 import org.junit.rules.TestRule; 356 import org.junit.runner.RunWith; 357 import org.mockito.ArgumentCaptor; 358 import org.mockito.ArgumentMatcher; 359 import org.mockito.ArgumentMatchers; 360 import org.mockito.InOrder; 361 import org.mockito.Mock; 362 import org.mockito.Mockito; 363 import org.mockito.MockitoAnnotations; 364 import org.mockito.invocation.InvocationOnMock; 365 import org.mockito.stubbing.Answer; 366 367 import java.io.BufferedInputStream; 368 import java.io.BufferedOutputStream; 369 import java.io.ByteArrayInputStream; 370 import java.io.ByteArrayOutputStream; 371 import java.io.File; 372 import java.io.FileOutputStream; 373 import java.time.Duration; 374 import java.util.ArrayList; 375 import java.util.Arrays; 376 import java.util.HashSet; 377 import java.util.List; 378 import java.util.Map; 379 import java.util.concurrent.CountDownLatch; 380 import java.util.function.Consumer; 381 382 import platform.test.runner.parameterized.ParameterizedAndroidJunit4; 383 import platform.test.runner.parameterized.Parameters; 384 385 @SmallTest 386 @RunWith(ParameterizedAndroidJunit4.class) 387 @RunWithLooper 388 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. 389 public class NotificationManagerServiceTest extends UiServiceTestCase { 390 private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"; 391 private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package"; 392 private static final String PKG_NO_CHANNELS = "com.example.no.channels"; 393 private static final int TEST_TASK_ID = 1; 394 private static final int UID_HEADLESS = 1_000_000; 395 private static final int TOAST_DURATION = 2_000; 396 private static final int SECONDARY_DISPLAY_ID = 42; 397 private static final int TEST_PROFILE_USERHANDLE = 12; 398 private static final long DELAY_FORCE_REGROUP_TIME = 3000; 399 400 private static final String ACTION_NOTIFICATION_TIMEOUT = 401 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 402 private static final String EXTRA_KEY = "key"; 403 private static final String SCHEME_TIMEOUT = "timeout"; 404 private static final String REDACTED_TEXT = "redacted text"; 405 406 private static final AutomaticZenRule SOME_ZEN_RULE = 407 new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 408 .setOwner(new ComponentName("pkg", "cls")) 409 .build(); 410 411 @ClassRule 412 public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule(); 413 414 @Rule 415 public TestRule compatChangeRule = new PlatformCompatChangeRule(); 416 417 private TestableNotificationManagerService mService; 418 private INotificationManager mBinderService; 419 private NotificationManagerInternal mInternalService; 420 private ShortcutHelper mShortcutHelper; 421 @Mock 422 private IPackageManager mPackageManager; 423 @Mock 424 private PackageManager mPackageManagerClient; 425 @Mock 426 private PackageManagerInternal mPackageManagerInternal; 427 @Mock 428 private PermissionPolicyInternal mPermissionPolicyInternal; 429 @Mock 430 private WindowManagerInternal mWindowManagerInternal; 431 @Mock 432 private PermissionHelper mPermissionHelper; 433 private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake(); 434 @Rule(order = Integer.MAX_VALUE) 435 public TestWithLooperRule mlooperRule = new TestWithLooperRule(); 436 private TestableLooper mTestableLooper; 437 @Mock 438 private RankingHelper mRankingHelper; 439 @Mock private PreferencesHelper mPreferencesHelper; 440 AtomicFile mPolicyFile; 441 File mFile; 442 @Mock 443 private NotificationUsageStats mUsageStats; 444 @Mock 445 private UsageStatsManagerInternal mAppUsageStats; 446 @Mock 447 private AudioManager mAudioManager; 448 @Mock 449 private LauncherApps mLauncherApps; 450 @Mock 451 private ShortcutServiceInternal mShortcutServiceInternal; 452 @Mock 453 private UserManager mUserManager; 454 @Mock 455 ActivityManager mActivityManager; 456 @Mock 457 TelecomManager mTelecomManager; 458 @Mock 459 Resources mResources; 460 @Mock 461 RankingHandler mRankingHandler; 462 @Mock 463 ActivityManagerInternal mAmi; 464 @Mock 465 JobSchedulerInternal mJsi; 466 @Mock 467 private Looper mMainLooper; 468 @Mock 469 private NotificationManager mMockNm; 470 @Mock 471 private PermissionManager mPermissionManager; 472 @Mock 473 private DevicePolicyManagerInternal mDevicePolicyManager; 474 @Mock 475 private PowerManager mPowerManager; 476 @Mock 477 private LightsManager mLightsManager; 478 private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>(); 479 private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory = 480 new TestPostNotificationTrackerFactory(); 481 482 private PendingIntent mActivityIntent; 483 private PendingIntent mActivityIntentImmutable; 484 485 private static final int MAX_POST_DELAY = 1000; 486 487 private NotificationChannel mTestNotificationChannel = new NotificationChannel( 488 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 489 490 NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW); 491 492 NotificationChannel mMinChannel = new NotificationChannel("min", "min", IMPORTANCE_MIN); 493 494 private final NotificationChannel mParentChannel = 495 new NotificationChannel(PARENT_CHANNEL_ID, "parentName", IMPORTANCE_DEFAULT); 496 private final NotificationChannel mConversationChannel = 497 new NotificationChannel( 498 CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT); 499 500 private static final String PARENT_CHANNEL_ID = "parentChannelId"; 501 private static final String CONVERSATION_CHANNEL_ID = "conversationChannelId"; 502 private static final String CONVERSATION_ID = "conversationId"; 503 504 private static final int NOTIFICATION_LOCATION_UNKNOWN = 0; 505 506 private static final String VALID_CONVO_SHORTCUT_ID = "shortcut"; 507 private static final String SEARCH_SELECTOR_PKG = "searchSelector"; 508 private static final String ADSERVICES_MODULE_PKG = "com.android.adservices"; 509 private static final String ADSERVICES_APK_PKG = "com.android.adservices.api"; 510 511 @Mock 512 private NotificationListeners mListeners; 513 @Mock 514 private NotificationListenerFilter mNlf; 515 @Mock private NotificationAssistants mAssistants; 516 @Mock private ConditionProviders mConditionProviders; 517 private ManagedServices.ManagedServiceInfo mListener; 518 @Mock private ICompanionDeviceManager mCompanionMgr; 519 @Mock SnoozeHelper mSnoozeHelper; 520 @Mock GroupHelper mGroupHelper; 521 @Mock 522 IBinder mPermOwner; 523 @Mock 524 IActivityManager mAm; 525 @Mock 526 ActivityTaskManagerInternal mAtm; 527 @Mock 528 IUriGrantsManager mUgm; 529 @Mock 530 UriGrantsManagerInternal mUgmInternal; 531 @Mock 532 AppOpsManager mAppOpsManager; 533 private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener; 534 @Mock 535 private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback 536 mNotificationAssistantAccessGrantedCallback; 537 @Mock 538 UserManager mUm; 539 @Mock 540 UserManagerInternal mUmInternal; 541 @Mock 542 NotificationHistoryManager mHistoryManager; 543 @Mock 544 StatsManager mStatsManager; 545 @Mock 546 AlarmManager mAlarmManager; 547 @Mock JobScheduler mJobScheduler; 548 @Mock 549 MultiRateLimiter mToastRateLimiter; 550 BroadcastReceiver mPackageIntentReceiver; 551 BroadcastReceiver mUserIntentReceiver; 552 BroadcastReceiver mNotificationTimeoutReceiver; 553 NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); 554 TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker; 555 556 TestableFlagResolver mTestFlagResolver = new TestableFlagResolver(); 557 @Rule 558 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 559 private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( 560 1 << 30); 561 @Mock 562 StatusBarManagerInternal mStatusBar; 563 564 @Mock 565 NotificationAttentionHelper mAttentionHelper; 566 567 private NotificationManagerService.WorkerHandler mWorkerHandler; 568 569 private class TestableToastCallback extends ITransientNotification.Stub { 570 @Override show(IBinder windowToken)571 public void show(IBinder windowToken) { 572 } 573 574 @Override hide()575 public void hide() { 576 } 577 } 578 579 private class TestPostNotificationTrackerFactory implements PostNotificationTrackerFactory { 580 581 private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>(); 582 583 @Override newTracker(@ullable WakeLock optionalWakeLock)584 public PostNotificationTracker newTracker(@Nullable WakeLock optionalWakeLock) { 585 PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker( 586 optionalWakeLock); 587 mCreatedTrackers.add(tracker); 588 return tracker; 589 } 590 } 591 592 @Parameters(name = "{0}") getParams()593 public static List<FlagsParameterization> getParams() { 594 return FlagsParameterization.allCombinationsOf(); 595 } 596 NotificationManagerServiceTest(FlagsParameterization flags)597 public NotificationManagerServiceTest(FlagsParameterization flags) { 598 mSetFlagsRule.setFlagsParameterization(flags); 599 } 600 601 @Before setUp()602 public void setUp() throws Exception { 603 // Shell permisssions will override permissions of our app, so add all necessary permissions 604 // for this test here: 605 InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 606 "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG", 607 "android.permission.READ_DEVICE_CONFIG", 608 "android.permission.READ_CONTACTS"); 609 610 MockitoAnnotations.initMocks(this); 611 612 DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class); 613 when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L); 614 615 LocalServices.removeServiceForTest(UserManagerInternal.class); 616 LocalServices.addService(UserManagerInternal.class, mUmInternal); 617 LocalServices.removeServiceForTest(UriGrantsManagerInternal.class); 618 LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal); 619 LocalServices.removeServiceForTest(WindowManagerInternal.class); 620 LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal); 621 LocalServices.removeServiceForTest(StatusBarManagerInternal.class); 622 LocalServices.addService(StatusBarManagerInternal.class, mStatusBar); 623 LocalServices.removeServiceForTest(DeviceIdleInternal.class); 624 LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal); 625 LocalServices.removeServiceForTest(ActivityManagerInternal.class); 626 LocalServices.addService(ActivityManagerInternal.class, mAmi); 627 LocalServices.removeServiceForTest(JobSchedulerInternal.class); 628 LocalServices.addService(JobSchedulerInternal.class, mJsi); 629 LocalServices.removeServiceForTest(PackageManagerInternal.class); 630 LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); 631 LocalServices.removeServiceForTest(PermissionPolicyInternal.class); 632 LocalServices.addService(PermissionPolicyInternal.class, mPermissionPolicyInternal); 633 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 634 LocalServices.addService(ShortcutServiceInternal.class, mShortcutServiceInternal); 635 mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); 636 mContext.addMockSystemService(NotificationManager.class, mMockNm); 637 mContext.addMockSystemService(RoleManager.class, mock(RoleManager.class)); 638 mContext.addMockSystemService(Context.LAUNCHER_APPS_SERVICE, mLauncherApps); 639 mContext.addMockSystemService(Context.USER_SERVICE, mUm); 640 mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, 641 mock(AccessibilityManager.class)); 642 643 doNothing().when(mContext).sendBroadcast(any(), anyString()); 644 doNothing().when(mContext).sendBroadcastAsUser(any(), any()); 645 doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); 646 TestableContentResolver cr = mock(TestableContentResolver.class); 647 when(mContext.getContentResolver()).thenReturn(cr); 648 doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt()); 649 650 when(mAppOpsManager.checkOpNoThrow( 651 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 652 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED); 653 654 // Use this testable looper. 655 mTestableLooper = TestableLooper.get(this); 656 // MockPackageManager - default returns ApplicationInfo with matching calling UID 657 mContext.setMockPackageManager(mPackageManagerClient); 658 659 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())) 660 .thenAnswer((Answer<ApplicationInfo>) invocation -> { 661 Object[] args = invocation.getArguments(); 662 return getApplicationInfo((String) args[0], mUid); 663 }); 664 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 665 .thenAnswer((Answer<ApplicationInfo>) invocation -> { 666 Object[] args = invocation.getArguments(); 667 return getApplicationInfo((String) args[0], mUid); 668 }); 669 when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid); 670 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer( 671 (Answer<Boolean>) invocation -> { 672 // TODO: b/317957802 - This is overly broad and basically makes ANY 673 // isSameApp() check pass, requiring Mockito.reset() for meaningful 674 // tests! Make it more precise. 675 Object[] args = invocation.getArguments(); 676 return (int) args[1] == mUid; 677 }); 678 when(mLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class)); 679 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); 680 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false); 681 when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner); 682 when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{mPkg}); 683 when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{mPkg}); 684 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())) 685 .thenReturn(INVALID_TASK_ID); 686 mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); 687 when(mUm.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId}); 688 when(mUmInternal.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId}); 689 when(mAmi.getCurrentUserId()).thenReturn(mUserId); 690 691 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true); 692 693 ActivityManager.AppTask task = mock(ActivityManager.AppTask.class); 694 List<ActivityManager.AppTask> taskList = new ArrayList<>(); 695 ActivityManager.RecentTaskInfo taskInfo = new ActivityManager.RecentTaskInfo(); 696 taskInfo.taskId = TEST_TASK_ID; 697 when(task.getTaskInfo()).thenReturn(taskInfo); 698 taskList.add(task); 699 when(mAtm.getAppTasks(anyString(), anyInt())).thenReturn(taskList); 700 701 // write to a test file; the system file isn't readable from tests 702 mFile = new File(mContext.getCacheDir(), "test.xml"); 703 mFile.createNewFile(); 704 final String preupgradeXml = "<notification-policy></notification-policy>"; 705 mPolicyFile = new AtomicFile(mFile); 706 FileOutputStream fos = mPolicyFile.startWrite(); 707 fos.write(preupgradeXml.getBytes()); 708 mPolicyFile.finishWrite(fos); 709 710 // Setup managed services 711 when(mNlf.isTypeAllowed(anyInt())).thenReturn(true); 712 when(mNlf.isPackageAllowed(any())).thenReturn(true); 713 when(mNlf.isPackageAllowed(null)).thenReturn(true); 714 when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf); 715 mListener = mListeners.new ManagedServiceInfo( 716 null, new ComponentName(mPkg, "test_class"), 717 mUserId, true, null, 0, 123); 718 ComponentName defaultComponent = ComponentName.unflattenFromString("config/device"); 719 ArraySet<ComponentName> components = new ArraySet<>(); 720 components.add(defaultComponent); 721 when(mListeners.getDefaultComponents()).thenReturn(components); 722 when(mConditionProviders.getDefaultPackages()) 723 .thenReturn(new ArraySet<>(Arrays.asList("config"))); 724 when(mAssistants.getDefaultComponents()).thenReturn(components); 725 when(mAssistants.queryPackageForServices( 726 anyString(), anyInt(), anyInt())).thenReturn(components); 727 when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener); 728 ManagedServices.Config listenerConfig = new ManagedServices.Config(); 729 listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS; 730 when(mListeners.getConfig()).thenReturn(listenerConfig); 731 ManagedServices.Config assistantConfig = new ManagedServices.Config(); 732 assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS; 733 when(mAssistants.getConfig()).thenReturn(assistantConfig); 734 ManagedServices.Config dndConfig = new ManagedServices.Config(); 735 dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS; 736 when(mConditionProviders.getConfig()).thenReturn(dndConfig); 737 738 when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); 739 740 // Use the real PowerManager to back up the mock w.r.t. creating WakeLocks. 741 // This is because 1) we need a mock to verify() calls and tracking the created WakeLocks, 742 // but 2) PowerManager and WakeLock perform their own checks (e.g. correct arguments, don't 743 // call release twice, etc) and we want the test to fail if such misuse happens, too. 744 PowerManager realPowerManager = mContext.getSystemService(PowerManager.class); 745 when(mPowerManager.newWakeLock(anyInt(), anyString())).then( 746 (Answer<WakeLock>) invocation -> { 747 WakeLock wl = realPowerManager.newWakeLock(invocation.getArgument(0), 748 invocation.getArgument(1)); 749 mAcquiredWakeLocks.add(wl); 750 return wl; 751 }); 752 753 // TODO (b/291907312): remove feature flag 754 // NOTE: Prefer using the @EnableFlags annotation where possible. Do not add any android.app 755 // flags here. 756 mSetFlagsRule.disableFlags( 757 Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE); 758 759 mActivityIntent = spy(PendingIntent.getActivity(mContext, 0, 760 new Intent().setPackage(mPkg), PendingIntent.FLAG_MUTABLE)); 761 mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0, 762 new Intent().setPackage(mPkg), FLAG_IMMUTABLE)); 763 764 initNMS(); 765 } 766 initNMS()767 private void initNMS() throws Exception { 768 initNMS(SystemService.PHASE_BOOT_COMPLETED); 769 } 770 initNMS(int upToBootPhase)771 private void initNMS(int upToBootPhase) throws Exception { 772 mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, 773 mNotificationInstanceIdSequence); 774 775 // apps allowed as convos 776 mService.setStringArrayResourceValue(PKG_O); 777 778 TestableResources tr = mContext.getOrCreateTestableResources(); 779 tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName, 780 SEARCH_SELECTOR_PKG); 781 782 doAnswer(invocation -> { 783 mOnPermissionChangeListener = invocation.getArgument(2); 784 return null; 785 }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(), 786 any()); 787 when(mUmInternal.isUserInitialized(anyInt())).thenReturn(true); 788 789 mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper())); 790 mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient, 791 mLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr, 792 mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm, 793 mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal, 794 mAppOpsManager, mUm, mHistoryManager, mStatsManager, 795 mAmi, mToastRateLimiter, mPermissionHelper, mock(UsageStatsManagerInternal.class), 796 mTelecomManager, mLogger, mTestFlagResolver, mPermissionManager, 797 mPowerManager, mPostNotificationTrackerFactory); 798 799 mService.setAttentionHelper(mAttentionHelper); 800 mService.setLockPatternUtils(mock(LockPatternUtils.class)); 801 802 // Return first true for RoleObserver main-thread check 803 when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); 804 ModuleInfo moduleInfo = new ModuleInfo(); 805 moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG); 806 moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG)); 807 when(mPackageManagerClient.getInstalledModules(anyInt())) 808 .thenReturn(List.of(moduleInfo)); 809 if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) { 810 mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper); 811 } 812 813 Mockito.reset(mHistoryManager); 814 verify(mHistoryManager, never()).onBootPhaseAppsCanStart(); 815 816 if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 817 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 818 verify(mHistoryManager).onBootPhaseAppsCanStart(); 819 } 820 821 mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext); 822 mService.setStrongAuthTracker(mStrongAuthTracker); 823 824 mShortcutHelper = mService.getShortcutHelper(); 825 mShortcutHelper.setLauncherApps(mLauncherApps); 826 mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal); 827 mShortcutHelper.setUserManager(mUserManager); 828 829 // Capture PackageIntentReceiver 830 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = 831 ArgumentCaptor.forClass(BroadcastReceiver.class); 832 ArgumentCaptor<IntentFilter> intentFilterCaptor = 833 ArgumentCaptor.forClass(IntentFilter.class); 834 835 verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(), 836 any(), intentFilterCaptor.capture(), any(), any()); 837 verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(), 838 intentFilterCaptor.capture(), anyInt()); 839 verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(), 840 intentFilterCaptor.capture()); 841 List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues(); 842 List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues(); 843 844 for (int i = 0; i < intentFilters.size(); i++) { 845 final IntentFilter filter = intentFilters.get(i); 846 if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED) 847 && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED) 848 && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) { 849 mPackageIntentReceiver = broadcastReceivers.get(i); 850 } 851 if (filter.hasAction(Intent.ACTION_USER_SWITCHED) 852 || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE) 853 || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { 854 // There may be multiple receivers, get the NMS one 855 if (broadcastReceivers.get(i).toString().contains( 856 NotificationManagerService.class.getName())) { 857 mUserIntentReceiver = broadcastReceivers.get(i); 858 } 859 } 860 if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT) 861 && filter.hasDataScheme(SCHEME_TIMEOUT)) { 862 mNotificationTimeoutReceiver = broadcastReceivers.get(i); 863 } 864 } 865 assertNotNull("package intent receiver should exist", mPackageIntentReceiver); 866 assertNotNull("User receiver should exist", mUserIntentReceiver); 867 if (!Flags.allNotifsNeedTtl()) { 868 assertNotNull("Notification timeout receiver should exist", 869 mNotificationTimeoutReceiver); 870 } 871 872 // Pretend the shortcut exists 873 List<ShortcutInfo> shortcutInfos = new ArrayList<>(); 874 shortcutInfos.add(createMockConvoShortcut()); 875 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); 876 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 877 anyString(), anyInt(), any())).thenReturn(true); 878 when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true); 879 mockIsUserVisible(DEFAULT_DISPLAY, true); 880 mockIsVisibleBackgroundUsersSupported(false); 881 882 // Set the testable bubble extractor 883 RankingHelper rankingHelper = mService.getRankingHelper(); 884 BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class); 885 extractor.setActivityManager(mActivityManager); 886 887 // Tests call directly into the Binder. 888 mBinderService = mService.getBinderService(); 889 mInternalService = mService.getInternalService(); 890 891 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice( 892 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 893 mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice( 894 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 895 mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice( 896 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 897 assertNotNull(mBinderService.getNotificationChannel( 898 mPkg, mContext.getUserId(), mPkg, TEST_CHANNEL_ID)); 899 assertNotNull(mBinderService.getNotificationChannel( 900 mPkg, mContext.getUserId(), mPkg, mSilentChannel.getId())); 901 assertNotNull(mBinderService.getNotificationChannel( 902 mPkg, mContext.getUserId(), mPkg, mMinChannel.getId())); 903 clearInvocations(mRankingHandler); 904 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 905 906 var checker = mock(TestableNotificationManagerService.ComponentPermissionChecker.class); 907 mService.permissionChecker = checker; 908 when(checker.check(anyString(), anyInt(), anyInt(), anyBoolean())) 909 .thenReturn(PackageManager.PERMISSION_DENIED); 910 } 911 912 @After assertNotificationRecordLoggerCallsValid()913 public void assertNotificationRecordLoggerCallsValid() { 914 waitForIdle(); // Finish async work, including all logging calls done by Runnables. 915 for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) { 916 if (call.wasLogged) { 917 assertNotNull(call.event); 918 if (call.event == NOTIFICATION_POSTED || call.event == NOTIFICATION_UPDATED) { 919 assertThat(call.postDurationMillisLogged).isGreaterThan(0); 920 } else { 921 assertThat(call.postDurationMillisLogged).isNull(); 922 } 923 } 924 } 925 assertThat(mNotificationRecordLogger.getPendingLogs()).isEmpty(); 926 } 927 928 @After assertAllTrackersFinishedOrCancelled()929 public void assertAllTrackersFinishedOrCancelled() { 930 waitForIdle(); // Finish async work. 931 // Verify that no trackers were left dangling. 932 for (PostNotificationTracker tracker : mPostNotificationTrackerFactory.mCreatedTrackers) { 933 assertThat(tracker.isOngoing()).isFalse(); 934 } 935 mPostNotificationTrackerFactory.mCreatedTrackers.clear(); 936 } 937 938 @After assertAllWakeLocksReleased()939 public void assertAllWakeLocksReleased() { 940 waitForIdle(); // Finish async work. 941 for (WakeLock wakeLock : mAcquiredWakeLocks) { 942 assertThat(wakeLock.isHeld()).isFalse(); 943 } 944 } 945 946 @After tearDown()947 public void tearDown() throws Exception { 948 if (mFile != null) mFile.delete(); 949 950 if (mActivityIntent != null) { 951 mActivityIntent.cancel(); 952 } 953 954 mService.clearNotifications(); 955 if (mTestableLooper != null) { 956 mTestableLooper.processAllMessages(); 957 } 958 959 try { 960 mService.onDestroy(); 961 } catch (IllegalStateException | IllegalArgumentException e) { 962 Log.e(TAG, "failed to destroy", e); 963 // can throw if a broadcast receiver was never registered 964 } 965 966 InstrumentationRegistry.getInstrumentation() 967 .getUiAutomation().dropShellPermissionIdentity(); 968 if (mWorkerHandler != null) { 969 // Remove scheduled messages that would be processed when the test is already done, and 970 // could cause issues, for example, messages that remove/cancel shown toasts (this causes 971 // problematic interactions with mocks when they're no longer working as expected). 972 mWorkerHandler.removeCallbacksAndMessages(null); 973 } 974 975 if (mTestableLooper != null) { 976 // Must remove static reference to this test object to prevent leak (b/261039202) 977 mTestableLooper.remove(this); 978 } 979 } 980 createMockConvoShortcut()981 private ShortcutInfo createMockConvoShortcut() { 982 ShortcutInfo info = mock(ShortcutInfo.class); 983 when(info.getPackage()).thenReturn(mPkg); 984 when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID); 985 when(info.getUserId()).thenReturn(USER_SYSTEM); 986 when(info.isLongLived()).thenReturn(true); 987 when(info.isEnabled()).thenReturn(true); 988 return info; 989 } 990 simulatePackageSuspendBroadcast(boolean suspend, String pkg, int uid)991 private void simulatePackageSuspendBroadcast(boolean suspend, String pkg, 992 int uid) { 993 // mimics receive broadcast that package is (un)suspended 994 // but does not actually (un)suspend the package 995 final Bundle extras = new Bundle(); 996 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, 997 new String[]{pkg}); 998 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid}); 999 1000 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED 1001 : Intent.ACTION_PACKAGES_UNSUSPENDED; 1002 final Intent intent = new Intent(action); 1003 intent.putExtras(extras); 1004 1005 mPackageIntentReceiver.onReceive(getContext(), intent); 1006 } 1007 simulatePackageRemovedBroadcast(String pkg, int uid)1008 private void simulatePackageRemovedBroadcast(String pkg, int uid) { 1009 // mimics receive broadcast that package is removed, but doesn't remove the package. 1010 final Bundle extras = new Bundle(); 1011 extras.putInt(Intent.EXTRA_UID, uid); 1012 1013 final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); 1014 intent.setData(Uri.parse("package:" + pkg)); 1015 intent.putExtras(extras); 1016 1017 mPackageIntentReceiver.onReceive(getContext(), intent); 1018 } 1019 simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids)1020 private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) { 1021 // mimics receive broadcast that package is (un)distracting 1022 // but does not actually register that info with packagemanager 1023 final Bundle extras = new Bundle(); 1024 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs); 1025 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag); 1026 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids); 1027 1028 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 1029 intent.putExtras(extras); 1030 1031 mPackageIntentReceiver.onReceive(getContext(), intent); 1032 } 1033 simulateProfileAvailabilityActions(String intentAction)1034 private void simulateProfileAvailabilityActions(String intentAction) { 1035 final Intent intent = new Intent(intentAction); 1036 intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE); 1037 mUserIntentReceiver.onReceive(mContext, intent); 1038 } 1039 generateResetComponentValues()1040 private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() { 1041 ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>(); 1042 changed.put(true, new ArrayList<>()); 1043 changed.put(false, new ArrayList<>()); 1044 return changed; 1045 } getApplicationInfo(String pkg, int uid)1046 private ApplicationInfo getApplicationInfo(String pkg, int uid) { 1047 final ApplicationInfo applicationInfo = new ApplicationInfo(); 1048 applicationInfo.packageName = pkg; 1049 applicationInfo.uid = uid; 1050 applicationInfo.sourceDir = mContext.getApplicationInfo().sourceDir; 1051 switch (pkg) { 1052 case PKG_N_MR1: 1053 applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1054 break; 1055 case PKG_O: 1056 applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; 1057 break; 1058 case PKG_P: 1059 applicationInfo.targetSdkVersion = Build.VERSION_CODES.P; 1060 break; 1061 default: 1062 applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; 1063 break; 1064 } 1065 return applicationInfo; 1066 } 1067 waitForIdle()1068 public void waitForIdle() { 1069 if (mTestableLooper != null) { 1070 mTestableLooper.processAllMessages(); 1071 } 1072 } 1073 setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, int pkgPref, boolean channelEnabled)1074 private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, 1075 int pkgPref, boolean channelEnabled) { 1076 Settings.Secure.putInt(mContext.getContentResolver(), 1077 Settings.Secure.NOTIFICATION_BUBBLES, globalEnabled ? 1 : 0); 1078 mService.mPreferencesHelper.updateBubblesEnabled(); 1079 assertEquals(globalEnabled, mService.mPreferencesHelper.bubblesEnabled( 1080 mock(UserHandle.class))); 1081 try { 1082 mBinderService.setBubblesAllowed(pkg, uid, pkgPref); 1083 } catch (RemoteException e) { 1084 e.printStackTrace(); 1085 } 1086 mTestNotificationChannel.setAllowBubbles(channelEnabled); 1087 } 1088 setUpPrefsForHistory(@serIdInt int userId, boolean globalEnabled)1089 private void setUpPrefsForHistory(@UserIdInt int userId, boolean globalEnabled) 1090 throws Exception { 1091 initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY); 1092 1093 // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid 1094 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1095 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, userId); 1096 // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0 1097 Settings.Secure.putInt(mContext.getContentResolver(), 1098 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0); 1099 setUsers(new int[] {0, userId}); 1100 1101 // Forces an update by calling observe on mSettingsObserver, which picks up the settings 1102 // changes above. 1103 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 1104 1105 assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(), 1106 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, userId) != 0); 1107 } 1108 generateSbn(String pkg, int uid, long postTime, int userId)1109 private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) { 1110 Notification.Builder nb = new Notification.Builder(mContext, "a") 1111 .setContentTitle("foo") 1112 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1113 StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid, 1114 "tag" + System.currentTimeMillis(), uid, 0, 1115 nb.build(), new UserHandle(userId), null, postTime); 1116 return sbn; 1117 } 1118 generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary)1119 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1120 String groupKey, boolean isSummary) { 1121 return generateNotificationRecord(channel, id, "tag" + System.currentTimeMillis(), groupKey, 1122 isSummary); 1123 } 1124 generateNotificationRecord(NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary)1125 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1126 String tag, String groupKey, boolean isSummary) { 1127 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1128 .setContentTitle("foo") 1129 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1130 .setGroup(groupKey) 1131 .setGroupSummary(isSummary); 1132 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, 1133 tag, mUid, 0, 1134 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1135 return new NotificationRecord(mContext, sbn, channel); 1136 } 1137 generateNotificationRecord(NotificationChannel channel)1138 private NotificationRecord generateNotificationRecord(NotificationChannel channel) { 1139 return generateNotificationRecord(channel, null); 1140 } 1141 generateNotificationRecord(NotificationChannel channel, Notification.TvExtender extender)1142 private NotificationRecord generateNotificationRecord(NotificationChannel channel, 1143 Notification.TvExtender extender) { 1144 if (channel == null) { 1145 channel = mTestNotificationChannel; 1146 } 1147 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1148 .setContentTitle("foo") 1149 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1150 .addAction(new Notification.Action.Builder(null, "test", mActivityIntent).build()) 1151 .addAction(new Notification.Action.Builder( 1152 null, "test", mActivityIntentImmutable).build()); 1153 if (extender != null) { 1154 nb.extend(extender); 1155 } 1156 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 1157 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1158 return new NotificationRecord(mContext, sbn, channel); 1159 } 1160 generateNotificationRecord(NotificationChannel channel, long postTime)1161 private NotificationRecord generateNotificationRecord(NotificationChannel channel, 1162 long postTime) { 1163 final StatusBarNotification sbn = generateSbn(mPkg, mUid, postTime, mUserId); 1164 return new NotificationRecord(mContext, sbn, channel); 1165 } 1166 generateNotificationRecord(NotificationChannel channel, int userId)1167 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) { 1168 return generateNotificationRecord(channel, 1, userId); 1169 } 1170 generateNotificationRecord(NotificationChannel channel, int id, int userId)1171 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1172 int userId) { 1173 return generateNotificationRecord(channel, id, userId, "foo"); 1174 } 1175 generateNotificationRecord(NotificationChannel channel, int id, int userId, String title)1176 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1177 int userId, String title) { 1178 if (channel == null) { 1179 channel = mTestNotificationChannel; 1180 } 1181 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1182 .setContentTitle(title) 1183 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1184 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0, 1185 nb.build(), new UserHandle(userId), null, 0); 1186 NotificationRecord r = new NotificationRecord(mContext, sbn, channel); 1187 return r; 1188 } 1189 generateMessageBubbleNotifRecord(NotificationChannel channel, String tag)1190 private NotificationRecord generateMessageBubbleNotifRecord(NotificationChannel channel, 1191 String tag) { 1192 return generateMessageBubbleNotifRecord(true, channel, 1, tag, null, false, true); 1193 } 1194 generateMessageBubbleNotifRecord(boolean addMetadata, NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, boolean mutable)1195 private NotificationRecord generateMessageBubbleNotifRecord(boolean addMetadata, 1196 NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, 1197 boolean mutable) { 1198 if (channel == null) { 1199 channel = mTestNotificationChannel; 1200 } 1201 if (tag == null) { 1202 tag = "tag"; 1203 } 1204 Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey, 1205 isSummary, mutable); 1206 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, 1207 tag, mUid, 0, 1208 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1209 return new NotificationRecord(mContext, sbn, channel); 1210 } 1211 generateRedactedSbn(NotificationChannel channel, int id, int userId)1212 private StatusBarNotification generateRedactedSbn(NotificationChannel channel, int id, 1213 int userId) { 1214 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1215 .setContentTitle("foo") 1216 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1217 .setContentText(REDACTED_TEXT); 1218 return new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0, 1219 nb.build(), new UserHandle(userId), null, 0); 1220 } 1221 getSignalExtractorSideEffects()1222 private Map<String, Answer> getSignalExtractorSideEffects() { 1223 Map<String, Answer> answers = new ArrayMap<>(); 1224 1225 answers.put("override group key", invocationOnMock -> { 1226 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1227 .setOverrideGroupKey("bananas"); 1228 return null; 1229 }); 1230 answers.put("override people", invocationOnMock -> { 1231 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1232 .setPeopleOverride(new ArrayList<>()); 1233 return null; 1234 }); 1235 answers.put("snooze criteria", invocationOnMock -> { 1236 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1237 .setSnoozeCriteria(new ArrayList<>()); 1238 return null; 1239 }); 1240 answers.put("notification channel", invocationOnMock -> { 1241 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1242 .updateNotificationChannel(new NotificationChannel("a", "", IMPORTANCE_LOW)); 1243 return null; 1244 }); 1245 answers.put("badging", invocationOnMock -> { 1246 NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0]; 1247 r.setShowBadge(!r.canShowBadge()); 1248 return null; 1249 }); 1250 answers.put("bubbles", invocationOnMock -> { 1251 NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0]; 1252 r.setAllowBubble(!r.canBubble()); 1253 return null; 1254 }); 1255 answers.put("package visibility", invocationOnMock -> { 1256 ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride( 1257 Notification.VISIBILITY_SECRET); 1258 return null; 1259 }); 1260 1261 return answers; 1262 } 1263 getMessageStyleNotifBuilder(boolean addBubbleMetadata, String groupKey, boolean isSummary, boolean mutable)1264 private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata, 1265 String groupKey, boolean isSummary, boolean mutable) { 1266 // Give it a person 1267 Person person = new Person.Builder() 1268 .setName("bubblebot") 1269 .build(); 1270 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 1271 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 1272 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 1273 mutable ? mActivityIntent : mActivityIntentImmutable).addRemoteInput(remoteInput) 1274 .build(); 1275 // Make it messaging style 1276 Notification.Builder nb = new Notification.Builder(mContext, 1277 mTestNotificationChannel.getId()) 1278 .setContentTitle("foo") 1279 .setStyle(new Notification.MessagingStyle(person) 1280 .setConversationTitle("Bubble Chat") 1281 .addMessage("Hello?", 1282 SystemClock.currentThreadTimeMillis() - 300000, person) 1283 .addMessage("Is it me you're looking for?", 1284 SystemClock.currentThreadTimeMillis(), person) 1285 ) 1286 .setActions(replyAction) 1287 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1288 .setShortcutId(VALID_CONVO_SHORTCUT_ID) 1289 .setGroupSummary(isSummary); 1290 if (groupKey != null) { 1291 nb.setGroup(groupKey); 1292 } 1293 if (addBubbleMetadata) { 1294 nb.setBubbleMetadata(getBubbleMetadata()); 1295 } 1296 return nb; 1297 } 1298 getBubbleMetadata()1299 private Notification.BubbleMetadata getBubbleMetadata() { 1300 ActivityInfo info = new ActivityInfo(); 1301 info.resizeMode = RESIZE_MODE_RESIZEABLE; 1302 ResolveInfo ri = new ResolveInfo(); 1303 ri.activityInfo = info; 1304 when(mPackageManagerClient.resolveActivityAsUser(any(), anyInt(), anyInt())).thenReturn(ri); 1305 1306 return new Notification.BubbleMetadata.Builder( 1307 mActivityIntent, 1308 Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon)) 1309 .build(); 1310 } 1311 addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)1312 private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel) 1313 throws RemoteException { 1314 1315 String groupKey = "BUBBLE_GROUP"; 1316 1317 // Notification that has bubble metadata 1318 NotificationRecord nrBubble = generateMessageBubbleNotifRecord(true /* addMetadata */, 1319 mTestNotificationChannel, 1 /* id */, "tag", groupKey, false /* isSummary */, 1320 true); 1321 1322 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrBubble.getSbn().getTag(), 1323 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(), 1324 nrBubble.getSbn().getUserId()); 1325 waitForIdle(); 1326 1327 // Make sure we are a bubble 1328 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 1329 assertEquals(1, notifsAfter.length); 1330 assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0); 1331 1332 // Notification without bubble metadata 1333 NotificationRecord nrPlain = generateMessageBubbleNotifRecord(false /* addMetadata */, 1334 mTestNotificationChannel, 2 /* id */, "tag", groupKey, false /* isSummary */, 1335 true); 1336 1337 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrPlain.getSbn().getTag(), 1338 nrPlain.getSbn().getId(), nrPlain.getSbn().getNotification(), 1339 nrPlain.getSbn().getUserId()); 1340 waitForIdle(); 1341 1342 notifsAfter = mBinderService.getActiveNotifications(mPkg); 1343 assertEquals(2, notifsAfter.length); 1344 1345 // Summary notification for both of those 1346 NotificationRecord nrSummary = generateMessageBubbleNotifRecord(false /* addMetadata */, 1347 mTestNotificationChannel, 3 /* id */, "tag", groupKey, true /* isSummary */, 1348 true); 1349 1350 if (summaryAutoCancel) { 1351 nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL; 1352 } 1353 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrSummary.getSbn().getTag(), 1354 nrSummary.getSbn().getId(), nrSummary.getSbn().getNotification(), 1355 nrSummary.getSbn().getUserId()); 1356 waitForIdle(); 1357 1358 notifsAfter = mBinderService.getActiveNotifications(mPkg); 1359 assertEquals(3, notifsAfter.length); 1360 1361 return nrSummary; 1362 } 1363 createAndPostCallStyleNotification(String packageName, UserHandle userHandle, String testName)1364 private NotificationRecord createAndPostCallStyleNotification(String packageName, 1365 UserHandle userHandle, String testName) throws Exception { 1366 Person person = new Person.Builder().setName("caller").build(); 1367 Notification.Builder nb = new Notification.Builder(mContext, 1368 mTestNotificationChannel.getId()) 1369 .setFlag(FLAG_USER_INITIATED_JOB, true) 1370 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 1371 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1372 StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1, 1373 testName, mUid, 0, nb.build(), userHandle, null, 0); 1374 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 1375 1376 mService.addEnqueuedNotification(r); 1377 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1378 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run(); 1379 waitForIdle(); 1380 1381 return mService.findNotificationLocked( 1382 packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId()); 1383 } 1384 createAndPostNotification(Notification.Builder nb, String testName)1385 private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName) 1386 throws RemoteException { 1387 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0, 1388 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1389 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 1390 1391 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1392 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 1393 waitForIdle(); 1394 1395 return mService.findNotificationLocked( 1396 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 1397 } 1398 parcelAndUnparcel(T source, Parcelable.Creator<T> creator)1399 private static <T extends Parcelable> T parcelAndUnparcel(T source, 1400 Parcelable.Creator<T> creator) { 1401 Parcel parcel = Parcel.obtain(); 1402 source.writeToParcel(parcel, 0); 1403 parcel.setDataPosition(0); 1404 return creator.createFromParcel(parcel); 1405 } 1406 createPendingIntent(String action)1407 private PendingIntent createPendingIntent(String action) { 1408 return PendingIntent.getActivity(mContext, 0, 1409 new Intent(action).setPackage(mContext.getPackageName()), 1410 PendingIntent.FLAG_MUTABLE); 1411 } 1412 allowTestPackageToToast()1413 private void allowTestPackageToToast() throws Exception { 1414 assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty(); 1415 mService.isSystemUid = false; 1416 mService.isSystemAppId = false; 1417 setToastRateIsWithinQuota(true); 1418 setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false); 1419 // package is not suspended 1420 when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId)) 1421 .thenReturn(false); 1422 } 1423 enqueueToast(String testPackage, ITransientNotification callback)1424 private boolean enqueueToast(String testPackage, ITransientNotification callback) 1425 throws RemoteException { 1426 return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), 1427 callback); 1428 } 1429 enqueueToast(INotificationManager service, String testPackage, IBinder token, ITransientNotification callback)1430 private boolean enqueueToast(INotificationManager service, String testPackage, 1431 IBinder token, ITransientNotification callback) throws RemoteException { 1432 return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ 1433 true, DEFAULT_DISPLAY); 1434 } 1435 enqueueTextToast(String testPackage, CharSequence text)1436 private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { 1437 return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY); 1438 } 1439 enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, int displayId)1440 private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, 1441 int displayId) throws RemoteException { 1442 return ((INotificationManager) mService.mService).enqueueTextToast(testPackage, 1443 new Binder(), text, TOAST_DURATION, isUiContext, displayId, 1444 /* textCallback= */ null); 1445 } 1446 mockIsVisibleBackgroundUsersSupported(boolean supported)1447 private void mockIsVisibleBackgroundUsersSupported(boolean supported) { 1448 when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported); 1449 } 1450 mockIsUserVisible(int displayId, boolean visible)1451 private void mockIsUserVisible(int displayId, boolean visible) { 1452 when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible); 1453 } 1454 mockDisplayAssignedToUser(int displayId)1455 private void mockDisplayAssignedToUser(int displayId) { 1456 when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId); 1457 } 1458 verifyToastShownForTestPackage(String text, int displayId)1459 private void verifyToastShownForTestPackage(String text, int displayId) { 1460 verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(), 1461 eq(TOAST_DURATION), any(), eq(displayId)); 1462 } 1463 1464 @Test 1465 @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL) testLimitTimeOutBroadcast()1466 public void testLimitTimeOutBroadcast() { 1467 NotificationChannel channel = new NotificationChannel("id", "name", 1468 NotificationManager.IMPORTANCE_HIGH); 1469 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1470 .setContentTitle("foo") 1471 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1472 .setTimeoutAfter(1); 1473 1474 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 1475 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1476 NotificationRecord r = new NotificationRecord(mContext, sbn, channel); 1477 1478 mService.scheduleTimeoutLocked(r); 1479 ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class); 1480 verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture()); 1481 assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, 1482 captor.getValue().getIntent().getPackage()); 1483 1484 mService.cancelScheduledTimeoutLocked(r); 1485 verify(mAlarmManager).cancel(captor.capture()); 1486 assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, 1487 captor.getValue().getIntent().getPackage()); 1488 } 1489 1490 @Test testDefaultAssistant_overrideDefault()1491 public void testDefaultAssistant_overrideDefault() { 1492 final int userId = mContext.getUserId(); 1493 final String testComponent = "package/class"; 1494 final List<UserInfo> userInfos = new ArrayList<>(); 1495 userInfos.add(new UserInfo(userId, "", 0)); 1496 final ArraySet<ComponentName> validAssistants = new ArraySet<>(); 1497 validAssistants.add(ComponentName.unflattenFromString(testComponent)); 1498 when(mActivityManager.isLowRamDevice()).thenReturn(false); 1499 when(mAssistants.queryPackageForServices(isNull(), anyInt(), anyInt())) 1500 .thenReturn(validAssistants); 1501 when(mAssistants.getDefaultComponents()).thenReturn(validAssistants); 1502 when(mUm.getEnabledProfiles(anyInt())).thenReturn(userInfos); 1503 1504 mService.setDefaultAssistantForUser(userId); 1505 1506 verify(mAssistants).setPackageOrComponentEnabled( 1507 eq(testComponent), eq(userId), eq(true), eq(true), eq(false)); 1508 } 1509 1510 @Test testCreateNotificationChannels_SingleChannel()1511 public void testCreateNotificationChannels_SingleChannel() throws Exception { 1512 final NotificationChannel channel = 1513 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1514 mBinderService.createNotificationChannels(mPkg, 1515 new ParceledListSlice(Arrays.asList(channel))); 1516 final NotificationChannel createdChannel = 1517 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1518 assertTrue(createdChannel != null); 1519 } 1520 1521 @Test testCreateNotificationChannels_NullChannelThrowsException()1522 public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception { 1523 try { 1524 mBinderService.createNotificationChannels(mPkg, 1525 new ParceledListSlice(Arrays.asList((Object[])null))); 1526 fail("Exception should be thrown immediately."); 1527 } catch (NullPointerException e) { 1528 // pass 1529 } 1530 } 1531 1532 @Test testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()1533 public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog() 1534 throws Exception { 1535 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1536 final NotificationChannel channel = 1537 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1538 mBinderService.createNotificationChannels(PKG_NO_CHANNELS, 1539 new ParceledListSlice(Arrays.asList(channel))); 1540 verify(mWorkerHandler).post(eq(new NotificationManagerService 1541 .ShowNotificationPermissionPromptRunnable(PKG_NO_CHANNELS, 1542 mUserId, TEST_TASK_ID, mPermissionPolicyInternal))); 1543 } 1544 1545 @Test testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()1546 public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog() 1547 throws Exception { 1548 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1549 assertTrue(mBinderService.getNumNotificationChannelsForPackage(mPkg, mUid, true) > 0); 1550 1551 final NotificationChannel channel = 1552 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1553 mBinderService.createNotificationChannels(mPkg, 1554 new ParceledListSlice(Arrays.asList(channel))); 1555 verify(mWorkerHandler, never()).post(any( 1556 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class)); 1557 } 1558 1559 @Test testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()1560 public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog() 1561 throws Exception { 1562 reset(mPermissionPolicyInternal); 1563 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1564 1565 final NotificationChannel channel = 1566 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1567 mBinderService.createNotificationChannels(mPkg, 1568 new ParceledListSlice(Arrays.asList(channel))); 1569 1570 verify(mWorkerHandler, never()).post(any( 1571 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class)); 1572 } 1573 1574 @Test testCreateNotificationChannels_TwoChannels()1575 public void testCreateNotificationChannels_TwoChannels() throws Exception { 1576 final NotificationChannel channel1 = 1577 new NotificationChannel("id1", "name", IMPORTANCE_DEFAULT); 1578 final NotificationChannel channel2 = 1579 new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT); 1580 mBinderService.createNotificationChannels(mPkg, 1581 new ParceledListSlice(Arrays.asList(channel1, channel2))); 1582 assertTrue(mBinderService.getNotificationChannel( 1583 mPkg, mContext.getUserId(), mPkg, "id1") != null); 1584 assertTrue(mBinderService.getNotificationChannel( 1585 mPkg, mContext.getUserId(), mPkg, "id2") != null); 1586 } 1587 1588 @Test testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()1589 public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance() 1590 throws Exception { 1591 final NotificationChannel channel = 1592 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1593 mBinderService.createNotificationChannels(mPkg, 1594 new ParceledListSlice(Arrays.asList(channel))); 1595 1596 // Recreating the channel doesn't throw, but ignores importance. 1597 final NotificationChannel dupeChannel = 1598 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1599 mBinderService.createNotificationChannels(mPkg, 1600 new ParceledListSlice(Arrays.asList(dupeChannel))); 1601 final NotificationChannel createdChannel = 1602 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1603 assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance()); 1604 } 1605 1606 @Test testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()1607 public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance() 1608 throws Exception { 1609 final NotificationChannel channel = 1610 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1611 mBinderService.createNotificationChannels(mPkg, 1612 new ParceledListSlice(Arrays.asList(channel))); 1613 1614 // Recreating with a lower importance is allowed to modify the channel. 1615 final NotificationChannel dupeChannel = 1616 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); 1617 mBinderService.createNotificationChannels(mPkg, 1618 new ParceledListSlice(Arrays.asList(dupeChannel))); 1619 final NotificationChannel createdChannel = 1620 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1621 assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance()); 1622 } 1623 1624 @Test testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()1625 public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated() 1626 throws Exception { 1627 final NotificationChannel channel = 1628 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1629 mBinderService.createNotificationChannels(mPkg, 1630 new ParceledListSlice(Arrays.asList(channel))); 1631 1632 // The user modifies importance directly, can no longer be changed by the app. 1633 final NotificationChannel updatedChannel = 1634 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1635 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, updatedChannel); 1636 1637 // Recreating with a lower importance leaves channel unchanged. 1638 final NotificationChannel dupeChannel = 1639 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); 1640 mBinderService.createNotificationChannels(mPkg, 1641 new ParceledListSlice(Arrays.asList(dupeChannel))); 1642 final NotificationChannel createdChannel = 1643 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1644 assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance()); 1645 } 1646 1647 @Test testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()1648 public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond() 1649 throws Exception { 1650 final NotificationChannel channel1 = 1651 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1652 final NotificationChannel channel2 = 1653 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1654 mBinderService.createNotificationChannels(mPkg, 1655 new ParceledListSlice(Arrays.asList(channel1, channel2))); 1656 final NotificationChannel createdChannel = 1657 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1658 assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance()); 1659 } 1660 1661 @Test testBlockedNotifications_suspended()1662 public void testBlockedNotifications_suspended() throws Exception { 1663 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true); 1664 1665 NotificationChannel channel = new NotificationChannel("id", "name", 1666 IMPORTANCE_HIGH); 1667 NotificationRecord r = generateNotificationRecord(channel); 1668 1669 // isBlocked is only used for user blocking, not app suspension 1670 assertFalse(mService.isRecordBlockedLocked(r)); 1671 } 1672 1673 @Test testBlockedNotifications_blockedChannel()1674 public void testBlockedNotifications_blockedChannel() throws Exception { 1675 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1676 1677 NotificationChannel channel = new NotificationChannel("id", "name", 1678 NotificationManager.IMPORTANCE_NONE); 1679 NotificationRecord r = generateNotificationRecord(channel); 1680 assertTrue(mService.isRecordBlockedLocked(r)); 1681 1682 mBinderService.createNotificationChannels( 1683 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1684 final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1685 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1686 "testBlockedNotifications_blockedChannel", 1687 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1688 waitForIdle(); 1689 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1690 } 1691 1692 @Test testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()1693 public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService() 1694 throws Exception { 1695 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1696 when(mAmi.applyForegroundServiceNotification( 1697 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1698 1699 NotificationChannel channel = new NotificationChannel("blocked", "name", 1700 NotificationManager.IMPORTANCE_NONE); 1701 mBinderService.createNotificationChannels( 1702 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1703 1704 final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1705 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1706 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1707 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1708 waitForIdle(); 1709 assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1710 assertEquals(IMPORTANCE_LOW, 1711 mService.getNotificationRecord(sbn.getKey()).getImportance()); 1712 assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel( 1713 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1714 } 1715 1716 @Test testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()1717 public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService() 1718 throws Exception { 1719 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1720 when(mAmi.applyForegroundServiceNotification( 1721 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1722 1723 NotificationChannel channel = 1724 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH); 1725 mBinderService.createNotificationChannels( 1726 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1727 1728 NotificationChannel update = 1729 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE); 1730 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update); 1731 waitForIdle(); 1732 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1733 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1734 1735 StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1736 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1737 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1738 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1739 waitForIdle(); 1740 // The first time a foreground service notification is shown, we allow the channel 1741 // to be updated to allow it to be seen. 1742 assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1743 assertEquals(IMPORTANCE_LOW, 1744 mService.getNotificationRecord(sbn.getKey()).getImportance()); 1745 assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel( 1746 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1747 mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId()); 1748 waitForIdle(); 1749 1750 update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE); 1751 update.setUserVisibleTaskShown(true); 1752 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update); 1753 waitForIdle(); 1754 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1755 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1756 1757 sbn = generateNotificationRecord(channel).getSbn(); 1758 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1759 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1760 "testEnqueuedBlockedNotifications_userBlockedChannelForegroundService", 1761 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1762 waitForIdle(); 1763 // The second time it is shown, we keep the user's preference. 1764 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1765 assertNull(mService.getNotificationRecord(sbn.getKey())); 1766 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1767 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1768 } 1769 1770 @Test testBlockedNotifications_blockedChannelGroup()1771 public void testBlockedNotifications_blockedChannelGroup() throws Exception { 1772 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1773 mService.setPreferencesHelper(mPreferencesHelper); 1774 when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())). 1775 thenReturn(true); 1776 1777 NotificationChannel channel = new NotificationChannel("id", "name", 1778 NotificationManager.IMPORTANCE_HIGH); 1779 channel.setGroup("something"); 1780 NotificationRecord r = generateNotificationRecord(channel); 1781 assertTrue(mService.isRecordBlockedLocked(r)); 1782 } 1783 1784 @Test testEnqueuedBlockedNotifications_blockedApp()1785 public void testEnqueuedBlockedNotifications_blockedApp() throws Exception { 1786 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1787 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1788 1789 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1790 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1791 "testEnqueuedBlockedNotifications_blockedApp", 1792 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1793 waitForIdle(); 1794 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1795 } 1796 1797 @Test testEnqueuedBlockedNotifications_blockedAppForegroundService()1798 public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception { 1799 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1800 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1801 when(mAmi.applyForegroundServiceNotification( 1802 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1803 1804 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1805 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1806 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1807 "testEnqueuedBlockedNotifications_blockedAppForegroundService", 1808 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1809 waitForIdle(); 1810 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1811 assertNull(mService.getNotificationRecord(sbn.getKey())); 1812 } 1813 1814 /** 1815 * Confirm an application with the SEND_CATEGORY_CAR_NOTIFICATIONS permission on automotive 1816 * devices can use car categories. 1817 */ 1818 @Test testEnqueuedRestrictedNotifications_hasPermission()1819 public void testEnqueuedRestrictedNotifications_hasPermission() throws Exception { 1820 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1821 .thenReturn(true); 1822 // SEND_CATEGORY_CAR_NOTIFICATIONS is a system-level permission that this test cannot 1823 // obtain. Mocking out enforce permission call to ensure notifications can be created when 1824 // permitted. 1825 doNothing().when(mContext).enforceCallingPermission( 1826 eq("android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"), anyString()); 1827 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1828 Notification.CATEGORY_CAR_WARNING, 1829 Notification.CATEGORY_CAR_INFORMATION); 1830 int id = 0; 1831 for (String category: categories) { 1832 final StatusBarNotification sbn = 1833 generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn(); 1834 sbn.getNotification().category = category; 1835 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1836 "testEnqueuedRestrictedNotifications_asSystem", 1837 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1838 } 1839 waitForIdle(); 1840 assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length); 1841 } 1842 1843 1844 /** 1845 * Confirm restricted notification categories only apply to automotive. 1846 */ 1847 @Test testEnqueuedRestrictedNotifications_notAutomotive()1848 public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception { 1849 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1850 .thenReturn(false); 1851 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1852 Notification.CATEGORY_CAR_WARNING, 1853 Notification.CATEGORY_CAR_INFORMATION); 1854 int id = 0; 1855 for (String category: categories) { 1856 final StatusBarNotification sbn = 1857 generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn(); 1858 sbn.getNotification().category = category; 1859 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1860 "testEnqueuedRestrictedNotifications_notAutomotive", 1861 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1862 } 1863 waitForIdle(); 1864 assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length); 1865 } 1866 1867 /** 1868 * Confirm if an application tries to use the car categories on a automotive device without the 1869 * SEND_CATEGORY_CAR_NOTIFICATIONS permission that a security exception will be thrown. 1870 */ 1871 @Test testEnqueuedRestrictedNotifications_noPermission()1872 public void testEnqueuedRestrictedNotifications_noPermission() throws Exception { 1873 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1874 .thenReturn(true); 1875 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1876 Notification.CATEGORY_CAR_WARNING, 1877 Notification.CATEGORY_CAR_INFORMATION); 1878 for (String category: categories) { 1879 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1880 sbn.getNotification().category = category; 1881 try { 1882 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1883 "testEnqueuedRestrictedNotifications_badUser", 1884 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1885 fail("Calls from non system apps should not allow use of restricted categories"); 1886 } catch (SecurityException e) { 1887 // pass 1888 } 1889 } 1890 waitForIdle(); 1891 assertEquals(0, mBinderService.getActiveNotifications(mPkg).length); 1892 } 1893 1894 @Test testSetNotificationsEnabledForPackage_noChange()1895 public void testSetNotificationsEnabledForPackage_noChange() throws Exception { 1896 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1897 mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true); 1898 1899 verify(mPermissionHelper, never()).setNotificationPermission( 1900 anyString(), anyInt(), anyBoolean(), anyBoolean()); 1901 } 1902 1903 @Test testSetNotificationsEnabledForPackage()1904 public void testSetNotificationsEnabledForPackage() throws Exception { 1905 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1906 mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false); 1907 1908 verify(mPermissionHelper).setNotificationPermission( 1909 mContext.getPackageName(), mUserId, false, true); 1910 1911 verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt()); 1912 List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls(); 1913 Assert.assertEquals( 1914 NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED, 1915 calls.get(calls.size() -1).event); 1916 } 1917 1918 @Test testBlockedNotifications_blockedByAssistant()1919 public void testBlockedNotifications_blockedByAssistant() throws Exception { 1920 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1921 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 1922 1923 NotificationChannel channel = new NotificationChannel("id", "name", 1924 NotificationManager.IMPORTANCE_HIGH); 1925 NotificationRecord r = generateNotificationRecord(channel); 1926 mService.addEnqueuedNotification(r); 1927 1928 Bundle bundle = new Bundle(); 1929 bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE); 1930 Adjustment adjustment = new Adjustment( 1931 r.getSbn().getPackageName(), r.getKey(), bundle, "", r.getUser().getIdentifier()); 1932 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 1933 1934 NotificationManagerService.PostNotificationRunnable runnable = 1935 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1936 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 1937 runnable.run(); 1938 waitForIdle(); 1939 1940 verify(mUsageStats, never()).registerPostedByApp(any()); 1941 } 1942 1943 @Test testBlockedNotifications_blockedByUser()1944 public void testBlockedNotifications_blockedByUser() throws Exception { 1945 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1946 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 1947 1948 NotificationChannel channel = new NotificationChannel("id", "name", 1949 NotificationManager.IMPORTANCE_HIGH); 1950 NotificationRecord r = generateNotificationRecord(channel); 1951 mService.addEnqueuedNotification(r); 1952 1953 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 1954 1955 NotificationManagerService.PostNotificationRunnable runnable = 1956 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1957 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 1958 runnable.run(); 1959 waitForIdle(); 1960 1961 verify(mUsageStats).registerBlocked(any()); 1962 verify(mUsageStats, never()).registerPostedByApp(any()); 1963 } 1964 1965 @Test testEnqueueNotificationInternal_noChannel()1966 public void testEnqueueNotificationInternal_noChannel() throws Exception { 1967 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1968 NotificationRecord nr = generateNotificationRecord( 1969 new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT)); 1970 1971 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 1972 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 1973 waitForIdle(); 1974 1975 verify(mPermissionHelper).hasPermission(mUid); 1976 verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID); 1977 1978 reset(mPermissionHelper); 1979 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1980 1981 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 1982 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 1983 waitForIdle(); 1984 1985 verify(mPermissionHelper).hasPermission(mUid); 1986 assertThat(mService.mChannelToastsSent).contains(mUid); 1987 } 1988 1989 @Test testEnqueueNotification_appBlocked()1990 public void testEnqueueNotification_appBlocked() throws Exception { 1991 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1992 1993 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1994 "testEnqueueNotification_appBlocked", 0, 1995 generateNotificationRecord(null).getNotification(), mUserId); 1996 waitForIdle(); 1997 verify(mWorkerHandler, never()).post( 1998 any(NotificationManagerService.EnqueueNotificationRunnable.class)); 1999 } 2000 2001 @Test testEnqueueNotificationWithTag_PopulatesGetActiveNotifications()2002 public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception { 2003 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2004 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2005 generateNotificationRecord(null).getNotification(), mUserId); 2006 waitForIdle(); 2007 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 2008 assertEquals(1, notifs.length); 2009 assertEquals(1, mService.getNotificationRecordCount()); 2010 } 2011 2012 @Test testEnqueueNotificationWithTag_WritesExpectedLogs()2013 public void testEnqueueNotificationWithTag_WritesExpectedLogs() throws Exception { 2014 final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog"; 2015 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2016 generateNotificationRecord(null).getNotification(), mUserId); 2017 waitForIdle(); 2018 assertEquals(1, mNotificationRecordLogger.numCalls()); 2019 2020 NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0); 2021 assertTrue(call.wasLogged); 2022 assertEquals(NOTIFICATION_POSTED, call.event); 2023 assertNotNull(call.r); 2024 assertNull(call.old); 2025 assertEquals(0, call.position); 2026 assertEquals(0, call.buzzBeepBlink); 2027 assertEquals(mPkg, call.r.getSbn().getPackageName()); 2028 assertEquals(0, call.r.getSbn().getId()); 2029 assertEquals(tag, call.r.getSbn().getTag()); 2030 assertEquals(1, call.getInstanceId()); // Fake instance IDs are assigned in order 2031 assertThat(call.postDurationMillisLogged).isGreaterThan(0); 2032 } 2033 2034 @Test testEnqueueNotificationWithTag_LogsOnMajorUpdates()2035 public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception { 2036 final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates"; 2037 Notification original = new Notification.Builder(mContext, 2038 mTestNotificationChannel.getId()) 2039 .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); 2040 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, original, mUserId); 2041 Notification update = new Notification.Builder(mContext, 2042 mTestNotificationChannel.getId()) 2043 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2044 .setCategory(Notification.CATEGORY_ALARM).build(); 2045 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, update, mUserId); 2046 waitForIdle(); 2047 assertEquals(2, mNotificationRecordLogger.numCalls()); 2048 2049 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2050 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2051 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 2052 assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0); 2053 2054 assertTrue(mNotificationRecordLogger.get(1).wasLogged); 2055 assertEquals(NOTIFICATION_UPDATED, mNotificationRecordLogger.event(1)); 2056 // Instance ID doesn't change on update of an active notification 2057 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 2058 assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isGreaterThan(0); 2059 } 2060 2061 @Test testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate()2062 public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate() throws Exception { 2063 final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate"; 2064 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2065 generateNotificationRecord(null).getNotification(), mUserId); 2066 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2067 generateNotificationRecord(null).getNotification(), mUserId); 2068 waitForIdle(); 2069 assertEquals(2, mNotificationRecordLogger.numCalls()); 2070 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2071 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2072 assertFalse(mNotificationRecordLogger.get(1).wasLogged); 2073 assertNull(mNotificationRecordLogger.event(1)); 2074 } 2075 2076 @Test testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate()2077 public void testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate() throws Exception { 2078 final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate"; 2079 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2080 generateNotificationRecord(null).getNotification(), 2081 mUserId); 2082 final Notification notif = generateNotificationRecord(null).getNotification(); 2083 notif.extras.putString(Notification.EXTRA_TITLE, "Changed title"); 2084 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notif, mUserId); 2085 waitForIdle(); 2086 assertEquals(2, mNotificationRecordLogger.numCalls()); 2087 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2088 assertNull(mNotificationRecordLogger.event(1)); 2089 } 2090 2091 @Test testEnqueueNotificationWithTag_LogsAgainAfterCancel()2092 public void testEnqueueNotificationWithTag_LogsAgainAfterCancel() throws Exception { 2093 final String tag = "testEnqueueNotificationWithTag_LogsAgainAfterCancel"; 2094 Notification notification = new Notification.Builder(mContext, 2095 mTestNotificationChannel.getId()) 2096 .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); 2097 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId); 2098 waitForIdle(); 2099 mBinderService.cancelNotificationWithTag(mPkg, mPkg, tag, 0, mUserId); 2100 waitForIdle(); 2101 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId); 2102 waitForIdle(); 2103 assertEquals(3, mNotificationRecordLogger.numCalls()); 2104 2105 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2106 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2107 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 2108 assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0); 2109 2110 assertEquals( 2111 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL, 2112 mNotificationRecordLogger.event(1)); 2113 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 2114 // Cancel is not post, so no logged post_duration_millis. 2115 assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isNull(); 2116 2117 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(2)); 2118 assertTrue(mNotificationRecordLogger.get(2).wasLogged); 2119 // New instance ID because notification was canceled before re-post 2120 assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId()); 2121 assertThat(mNotificationRecordLogger.get(2).postDurationMillisLogged).isGreaterThan(0); 2122 } 2123 2124 @Test testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed()2125 public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception { 2126 when(mAmi.applyForegroundServiceNotification( 2127 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 2128 mContext.getTestablePermissions().setPermission( 2129 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); 2130 2131 final String tag = "testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed"; 2132 2133 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2134 .setContentTitle("foo") 2135 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2136 .setFlag(FLAG_FOREGROUND_SERVICE, true) 2137 .build(); 2138 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, tag, mUid, 0, 2139 n, UserHandle.getUserHandleForUid(mUid), null, 0); 2140 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 2141 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2142 waitForIdle(); 2143 2144 StatusBarNotification[] notifs = 2145 mBinderService.getActiveNotifications(mPkg); 2146 assertThat(notifs[0].getNotification().flags).isEqualTo( 2147 FLAG_FOREGROUND_SERVICE | FLAG_CAN_COLORIZE | FLAG_NO_CLEAR); 2148 } 2149 2150 @Test testEnqueueNotificationWithTag_nullAction_fixed()2151 public void testEnqueueNotificationWithTag_nullAction_fixed() throws Exception { 2152 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2153 .setContentTitle("foo") 2154 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2155 .addAction(new Notification.Action.Builder(null, "one", null).build()) 2156 .addAction(new Notification.Action.Builder(null, "two", null).build()) 2157 .addAction(new Notification.Action.Builder(null, "three", null).build()) 2158 .build(); 2159 n.actions[1] = null; 2160 2161 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 2162 waitForIdle(); 2163 2164 StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg); 2165 assertThat(posted).hasLength(1); 2166 assertThat(posted[0].getNotification().actions).hasLength(2); 2167 assertThat(posted[0].getNotification().actions[0].title.toString()).isEqualTo("one"); 2168 assertThat(posted[0].getNotification().actions[1].title.toString()).isEqualTo("three"); 2169 } 2170 2171 @Test testEnqueueNotificationWithTag_allNullActions_fixed()2172 public void testEnqueueNotificationWithTag_allNullActions_fixed() throws Exception { 2173 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2174 .setContentTitle("foo") 2175 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2176 .addAction(new Notification.Action.Builder(null, "one", null).build()) 2177 .addAction(new Notification.Action.Builder(null, "two", null).build()) 2178 .build(); 2179 n.actions[0] = null; 2180 n.actions[1] = null; 2181 2182 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 2183 waitForIdle(); 2184 2185 StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg); 2186 assertThat(posted).hasLength(1); 2187 assertThat(posted[0].getNotification().actions).isNull(); 2188 } 2189 2190 @Test enqueueNotificationWithTag_usesAndFinishesTracker()2191 public void enqueueNotificationWithTag_usesAndFinishesTracker() throws Exception { 2192 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2193 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2194 generateNotificationRecord(null).getNotification(), mUserId); 2195 2196 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2197 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isTrue(); 2198 2199 waitForIdle(); 2200 2201 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(1); 2202 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2203 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2204 } 2205 2206 @Test enqueueNotificationWithTag_throws_usesAndCancelsTracker()2207 public void enqueueNotificationWithTag_throws_usesAndCancelsTracker() throws Exception { 2208 // Simulate not enqueued due to rejected inputs. 2209 assertThrows(Exception.class, 2210 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2211 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2212 /* notification= */ null, mUserId)); 2213 2214 waitForIdle(); 2215 2216 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2217 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2218 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2219 } 2220 2221 @Test enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker()2222 public void enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker() throws Exception { 2223 // Simulate not enqueued due to snoozing inputs. 2224 when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any())) 2225 .thenReturn("zzzzzzz"); 2226 2227 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2228 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2229 generateNotificationRecord(null).getNotification(), mUserId); 2230 waitForIdle(); 2231 2232 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2233 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2234 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2235 } 2236 2237 @Test enqueueNotificationWithTag_notPosted_usesAndCancelsTracker()2238 public void enqueueNotificationWithTag_notPosted_usesAndCancelsTracker() throws Exception { 2239 // Simulate not posted due to blocked app. 2240 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 2241 2242 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2243 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2244 generateNotificationRecord(null).getNotification(), mUserId); 2245 waitForIdle(); 2246 2247 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2248 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2249 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2250 } 2251 2252 @Test enqueueNotification_acquiresAndReleasesWakeLock()2253 public void enqueueNotification_acquiresAndReleasesWakeLock() throws Exception { 2254 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2255 "enqueueNotification_acquiresAndReleasesWakeLock", 0, 2256 generateNotificationRecord(null).getNotification(), mUserId); 2257 2258 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2259 assertThat(mAcquiredWakeLocks).hasSize(1); 2260 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2261 2262 waitForIdle(); 2263 2264 assertThat(mAcquiredWakeLocks).hasSize(1); 2265 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2266 } 2267 2268 @Test enqueueNotification_throws_acquiresAndReleasesWakeLock()2269 public void enqueueNotification_throws_acquiresAndReleasesWakeLock() throws Exception { 2270 // Simulate not enqueued due to rejected inputs. 2271 assertThrows(Exception.class, 2272 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2273 "enqueueNotification_throws_acquiresAndReleasesWakeLock", 0, 2274 /* notification= */ null, mUserId)); 2275 2276 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2277 assertThat(mAcquiredWakeLocks).hasSize(1); 2278 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2279 } 2280 2281 @Test enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock()2282 public void enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock() throws Exception { 2283 // Simulate not enqueued due to snoozing inputs. 2284 when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any())) 2285 .thenReturn("zzzzzzz"); 2286 2287 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2288 "enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock", 0, 2289 generateNotificationRecord(null).getNotification(), mUserId); 2290 2291 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2292 assertThat(mAcquiredWakeLocks).hasSize(1); 2293 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2294 2295 waitForIdle(); 2296 2297 assertThat(mAcquiredWakeLocks).hasSize(1); 2298 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2299 } 2300 2301 @Test enqueueNotification_notPosted_acquiresAndReleasesWakeLock()2302 public void enqueueNotification_notPosted_acquiresAndReleasesWakeLock() throws Exception { 2303 // Simulate enqueued but not posted due to missing small icon. 2304 Notification notif = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2305 .setContentTitle("foo") 2306 .build(); 2307 2308 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2309 "enqueueNotification_notPosted_acquiresAndReleasesWakeLock", 0, 2310 notif, mUserId); 2311 2312 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2313 assertThat(mAcquiredWakeLocks).hasSize(1); 2314 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2315 2316 waitForIdle(); 2317 2318 // NLSes were not called. 2319 verify(mListeners, never()).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 2320 2321 assertThat(mAcquiredWakeLocks).hasSize(1); 2322 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2323 } 2324 2325 @Test enqueueNotification_setsWakeLockWorkSource()2326 public void enqueueNotification_setsWakeLockWorkSource() throws Exception { 2327 // Use a "full" mock for the PowerManager (instead of the one that delegates to the real 2328 // service) so we can return a mocked WakeLock that we can verify() on. 2329 reset(mPowerManager); 2330 WakeLock wakeLock = mock(WakeLock.class); 2331 when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(wakeLock); 2332 2333 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2334 "enqueueNotification_setsWakeLockWorkSource", 0, 2335 generateNotificationRecord(null).getNotification(), mUserId); 2336 waitForIdle(); 2337 2338 InOrder inOrder = inOrder(mPowerManager, wakeLock); 2339 inOrder.verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2340 inOrder.verify(wakeLock).setWorkSource(eq(new WorkSource(mUid, mPkg))); 2341 inOrder.verify(wakeLock).acquire(anyLong()); 2342 inOrder.verify(wakeLock).release(); 2343 inOrder.verifyNoMoreInteractions(); 2344 } 2345 2346 @Test testCancelNonexistentNotification()2347 public void testCancelNonexistentNotification() throws Exception { 2348 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2349 "testCancelNonexistentNotification", 0, mUserId); 2350 waitForIdle(); 2351 // The notification record logger doesn't even get called when a nonexistent notification 2352 // is cancelled, because that happens very frequently and is not interesting. 2353 assertEquals(0, mNotificationRecordLogger.numCalls()); 2354 } 2355 2356 @Test testCancelNotificationImmediatelyAfterEnqueue()2357 public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception { 2358 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2359 "testCancelNotificationImmediatelyAfterEnqueue", 0, 2360 generateNotificationRecord(null).getNotification(), mUserId); 2361 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2362 "testCancelNotificationImmediatelyAfterEnqueue", 0, mUserId); 2363 waitForIdle(); 2364 StatusBarNotification[] notifs = 2365 mBinderService.getActiveNotifications(mPkg); 2366 assertEquals(0, notifs.length); 2367 assertEquals(0, mService.getNotificationRecordCount()); 2368 } 2369 2370 @Test testPostCancelPostNotifiesListeners()2371 public void testPostCancelPostNotifiesListeners() throws Exception { 2372 // WHEN a notification is posted 2373 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2374 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), 2375 sbn.getNotification(), sbn.getUserId()); 2376 mTestableLooper.moveTimeForward(1); 2377 // THEN it is canceled 2378 mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId()); 2379 mTestableLooper.moveTimeForward(1); 2380 // THEN it is posted again (before the cancel has a chance to finish) 2381 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), 2382 sbn.getNotification(), sbn.getUserId()); 2383 // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected 2384 waitForIdle(); 2385 2386 // The final enqueue made it to the listener instead of being canceled 2387 StatusBarNotification[] notifs = 2388 mBinderService.getActiveNotifications(mPkg); 2389 assertEquals(1, notifs.length); 2390 assertEquals(1, mService.getNotificationRecordCount()); 2391 } 2392 2393 @Test testCancelNotificationWhilePostedAndEnqueued()2394 public void testCancelNotificationWhilePostedAndEnqueued() throws Exception { 2395 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2396 "testCancelNotificationWhilePostedAndEnqueued", 0, 2397 generateNotificationRecord(null).getNotification(), mUserId); 2398 waitForIdle(); 2399 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2400 "testCancelNotificationWhilePostedAndEnqueued", 0, 2401 generateNotificationRecord(null).getNotification(), mUserId); 2402 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2403 "testCancelNotificationWhilePostedAndEnqueued", 0, mUserId); 2404 waitForIdle(); 2405 StatusBarNotification[] notifs = 2406 mBinderService.getActiveNotifications(mPkg); 2407 assertEquals(0, notifs.length); 2408 assertEquals(0, mService.getNotificationRecordCount()); 2409 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 2410 verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture()); 2411 assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface()); 2412 } 2413 2414 @Test testCancelNotificationsFromListenerImmediatelyAfterEnqueue()2415 public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception { 2416 NotificationRecord r = generateNotificationRecord(null); 2417 final StatusBarNotification sbn = r.getSbn(); 2418 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2419 "testCancelNotificationsFromListenerImmediatelyAfterEnqueue", 2420 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2421 mBinderService.cancelNotificationsFromListener(null, null); 2422 waitForIdle(); 2423 StatusBarNotification[] notifs = 2424 mBinderService.getActiveNotifications(sbn.getPackageName()); 2425 assertEquals(0, notifs.length); 2426 assertEquals(0, mService.getNotificationRecordCount()); 2427 } 2428 2429 @Test testCancelAllNotificationsImmediatelyAfterEnqueue()2430 public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception { 2431 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2432 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2433 "testCancelAllNotificationsImmediatelyAfterEnqueue", 2434 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2435 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2436 waitForIdle(); 2437 StatusBarNotification[] notifs = 2438 mBinderService.getActiveNotifications(sbn.getPackageName()); 2439 assertEquals(0, notifs.length); 2440 assertEquals(0, mService.getNotificationRecordCount()); 2441 } 2442 2443 @Test testUserInitiatedClearAll_noLeak()2444 public void testUserInitiatedClearAll_noLeak() throws Exception { 2445 final NotificationRecord n = generateNotificationRecord( 2446 mTestNotificationChannel, 1, "group", true); 2447 2448 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2449 "testUserInitiatedClearAll_noLeak", 2450 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId()); 2451 waitForIdle(); 2452 2453 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 2454 n.getUserId()); 2455 waitForIdle(); 2456 StatusBarNotification[] notifs = 2457 mBinderService.getActiveNotifications(n.getSbn().getPackageName()); 2458 assertEquals(0, notifs.length); 2459 assertEquals(0, mService.getNotificationRecordCount()); 2460 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 2461 verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture()); 2462 assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface()); 2463 } 2464 2465 @Test testCancelAllNotificationsCancelsChildren()2466 public void testCancelAllNotificationsCancelsChildren() throws Exception { 2467 final NotificationRecord parent = generateNotificationRecord( 2468 mTestNotificationChannel, 1, "group1", true); 2469 final NotificationRecord child = generateNotificationRecord( 2470 mTestNotificationChannel, 2, "group1", false); 2471 2472 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2473 "testCancelAllNotificationsCancelsChildren", 2474 parent.getSbn().getId(), parent.getSbn().getNotification(), 2475 parent.getSbn().getUserId()); 2476 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2477 "testCancelAllNotificationsCancelsChildren", 2478 child.getSbn().getId(), child.getSbn().getNotification(), 2479 child.getSbn().getUserId()); 2480 waitForIdle(); 2481 2482 mBinderService.cancelAllNotifications(mPkg, parent.getSbn().getUserId()); 2483 waitForIdle(); 2484 assertEquals(0, mService.getNotificationRecordCount()); 2485 } 2486 2487 @Test testCancelAllNotificationsMultipleEnqueuedDoesNotCrash()2488 public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception { 2489 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2490 for (int i = 0; i < 10; i++) { 2491 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2492 "testCancelAllNotificationsMultipleEnqueuedDoesNotCrash", 2493 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2494 } 2495 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2496 waitForIdle(); 2497 2498 assertEquals(0, mService.getNotificationRecordCount()); 2499 } 2500 2501 @Test testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash()2502 public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception { 2503 final NotificationRecord parent = generateNotificationRecord( 2504 mTestNotificationChannel, 1, "group1", true); 2505 final NotificationRecord parentAsChild = generateNotificationRecord( 2506 mTestNotificationChannel, 1, "group1", false); 2507 final NotificationRecord child = generateNotificationRecord( 2508 mTestNotificationChannel, 2, "group1", false); 2509 2510 // fully post parent notification 2511 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2512 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2513 parent.getSbn().getId(), parent.getSbn().getNotification(), 2514 parent.getSbn().getUserId()); 2515 waitForIdle(); 2516 2517 // enqueue the child several times 2518 for (int i = 0; i < 10; i++) { 2519 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2520 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2521 child.getSbn().getId(), child.getSbn().getNotification(), 2522 child.getSbn().getUserId()); 2523 } 2524 // make the parent a child, which will cancel the child notification 2525 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2526 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2527 parentAsChild.getSbn().getId(), parentAsChild.getSbn().getNotification(), 2528 parentAsChild.getSbn().getUserId()); 2529 waitForIdle(); 2530 2531 assertEquals(0, mService.getNotificationRecordCount()); 2532 } 2533 2534 @Test 2535 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationAdded()2536 public void testAutobundledSummary_notificationAdded() { 2537 NotificationRecord summary = 2538 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2539 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2540 mService.addNotification(summary); 2541 mService.mSummaryByGroupKey.put("pkg", summary); 2542 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2543 mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); 2544 2545 mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY, 2546 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, 2547 mock(Icon.class), 0, 2548 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2549 waitForIdle(); 2550 2551 assertTrue(summary.getSbn().isOngoing()); 2552 } 2553 2554 @Test 2555 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationAdded_forcedGrouping()2556 public void testAutobundledSummary_notificationAdded_forcedGrouping() { 2557 NotificationRecord summary = 2558 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2559 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2560 mService.addNotification(summary); 2561 mService.mSummaryByGroupKey.put("pkg", summary); 2562 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2563 mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey()); 2564 2565 mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(), 2566 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, 2567 mock(Icon.class), 0, 2568 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2569 waitForIdle(); 2570 2571 assertTrue(summary.getSbn().isOngoing()); 2572 } 2573 2574 @Test 2575 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationRemoved()2576 public void testAutobundledSummary_notificationRemoved() { 2577 NotificationRecord summary = 2578 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2579 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2580 summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 2581 mService.addNotification(summary); 2582 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2583 mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); 2584 mService.mSummaryByGroupKey.put(summary.getGroupKey(), summary); 2585 2586 mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY, 2587 new NotificationAttributes(GroupHelper.BASE_FLAGS, 2588 mock(Icon.class), 0, 2589 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2590 waitForIdle(); 2591 2592 assertFalse(summary.getSbn().isOngoing()); 2593 } 2594 2595 @Test 2596 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationRemoved_forceGrouping()2597 public void testAutobundledSummary_notificationRemoved_forceGrouping() { 2598 NotificationRecord summary = 2599 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2600 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2601 summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 2602 mService.addNotification(summary); 2603 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2604 mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey()); 2605 2606 mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(), 2607 new NotificationAttributes(GroupHelper.BASE_FLAGS, 2608 mock(Icon.class), 0, 2609 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2610 waitForIdle(); 2611 2612 assertFalse(summary.getSbn().isOngoing()); 2613 } 2614 2615 @Test 2616 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAggregatedSummary_updateSummaryAttributes()2617 public void testAggregatedSummary_updateSummaryAttributes() { 2618 final String aggregateGroupName = "Aggregate_Test"; 2619 final String newChannelId = "newChannelId"; 2620 final NotificationChannel newChannel = new NotificationChannel( 2621 newChannelId, newChannelId, IMPORTANCE_DEFAULT); 2622 mService.setPreferencesHelper(mPreferencesHelper); 2623 final NotificationRecord summary = 2624 generateNotificationRecord(mTestNotificationChannel, 0, aggregateGroupName, true); 2625 final String groupKey = summary.getGroupKey(); 2626 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2627 mService.addNotification(summary); 2628 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2629 mService.mAutobundledSummaries.get(0).put(groupKey, summary.getKey()); 2630 when(mPreferencesHelper.getNotificationChannel(eq("pkg"), anyInt(), 2631 eq(newChannelId), anyBoolean())).thenReturn(newChannel); 2632 2633 mService.updateAutobundledSummaryLocked(0, "pkg", groupKey, 2634 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, 2635 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, newChannelId), 2636 false); 2637 waitForIdle(); 2638 2639 assertTrue(summary.getSbn().isOngoing()); 2640 assertThat(summary.getNotification().getGroupAlertBehavior()).isEqualTo( 2641 GROUP_ALERT_CHILDREN); 2642 2643 assertThat(summary.getChannel().getId()).isEqualTo(newChannelId); 2644 } 2645 2646 @Test 2647 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAddAggregateNotification_notifyPostedLocked()2648 public void testAddAggregateNotification_notifyPostedLocked() throws Exception { 2649 final String originalGroupName = "originalGroup"; 2650 final NotificationRecord r = 2651 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 2652 mService.addNotification(r); 2653 mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true); 2654 2655 assertThat(r.getSbn().getOverrideGroupKey()).isEqualTo("grpKey"); 2656 verify(mRankingHandler, times(1)).requestSort(); 2657 verify(mListeners, times(1)).notifyPostedLocked(eq(r), eq(r)); 2658 } 2659 2660 @Test 2661 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAddAggregateSummaryNotification_convertSummary()2662 public void testAddAggregateSummaryNotification_convertSummary() throws Exception { 2663 final String originalGroupName = "originalGroup"; 2664 final NotificationRecord r = 2665 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 2666 final String groupKey = r.getGroupKey(); 2667 mService.addNotification(r); 2668 assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isTrue(); 2669 boolean isConverted = mService.convertSummaryToNotificationLocked(r.getKey()); 2670 2671 assertThat(isConverted).isTrue(); 2672 assertThat(r.getSbn().isGroup()).isTrue(); 2673 assertThat(r.getNotification().isGroupSummary()).isFalse(); 2674 assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isFalse(); 2675 } 2676 2677 @Test 2678 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2679 Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS}) testAggregateGroups_RemoveAppSummary()2680 public void testAggregateGroups_RemoveAppSummary() throws Exception { 2681 final String originalGroupName = "originalGroup"; 2682 final NotificationRecord r = 2683 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 2684 mService.addNotification(r); 2685 mService.removeAppSummaryLocked(r.getKey()); 2686 2687 assertThat(r.isCanceled).isTrue(); 2688 waitForIdle(); 2689 verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(0)); 2690 } 2691 2692 @Test 2693 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) testAggregateGroups_RemoveAppSummary_onClassification()2694 public void testAggregateGroups_RemoveAppSummary_onClassification() throws Exception { 2695 final String originalGroupName = "originalGroup"; 2696 final int summaryId = 0; 2697 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 2698 summaryId + 1, originalGroupName, false); 2699 mService.addNotification(r1); 2700 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 2701 summaryId + 2, originalGroupName, false); 2702 mService.addNotification(r2); 2703 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 2704 summaryId, originalGroupName, true); 2705 mService.addNotification(summary); 2706 final String originalGroupKey = summary.getGroupKey(); 2707 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 2708 2709 // Regroup first child notification 2710 r1.setOverrideGroupKey("newGroup"); 2711 // Check that removeAppProvidedSummaryOnClassificationLocked is null 2712 // => there is still one child left in the original group 2713 assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r1.getKey(), 2714 originalGroupKey)).isNull(); 2715 2716 // Regroup last child notification 2717 r2.setOverrideGroupKey("newGroup"); 2718 // Check that removeAppProvidedSummaryOnClassificationLocked returns the original summary 2719 // and that the original app-provided summary is canceled 2720 assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r2.getKey(), 2721 originalGroupKey)).isEqualTo(summary); 2722 waitForIdle(); 2723 verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(summaryId)); 2724 assertThat(mService.mSummaryByGroupKey).doesNotContainKey(originalGroupKey); 2725 } 2726 2727 @Test 2728 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testUngroupingAggregateSummary()2729 public void testUngroupingAggregateSummary() throws Exception { 2730 final String originalGroupName = "originalGroup"; 2731 final String aggregateGroupName = "Aggregate_Test"; 2732 final int summaryId = Integer.MAX_VALUE; 2733 // Add 2 group notifications without a summary 2734 NotificationRecord nr0 = 2735 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 2736 NotificationRecord nr1 = 2737 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 2738 mService.addNotification(nr0); 2739 mService.addNotification(nr1); 2740 mService.mSummaryByGroupKey.remove(nr0.getGroupKey()); 2741 2742 // GroupHelper is a mock, so make the calls it would make 2743 // Add aggregate group summary 2744 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 2745 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 2746 nr0.getChannel().getId()); 2747 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 2748 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 2749 mService.addNotification(aggregateSummary); 2750 nr0.setOverrideGroupKey(aggregateGroupName); 2751 nr1.setOverrideGroupKey(aggregateGroupName); 2752 final String fullAggregateGroupKey = nr0.getGroupKey(); 2753 2754 // Check that the aggregate group summary was created 2755 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 2756 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 2757 nr0.getChannel().getId()); 2758 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 2759 2760 // Cancel both children 2761 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(), 2762 nr0.getSbn().getId(), nr0.getSbn().getUserId()); 2763 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(), 2764 nr1.getSbn().getId(), nr1.getSbn().getUserId()); 2765 waitForIdle(); 2766 2767 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any()); 2768 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any()); 2769 2770 // GroupHelper would send 'remove summary' event 2771 mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(), 2772 fullAggregateGroupKey); 2773 waitForIdle(); 2774 2775 // Make sure the summary was removed and not re-posted 2776 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 2777 } 2778 2779 @Test 2780 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2781 Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS}) testCancelGroupChildrenForCanceledSummary_singletonGroup()2782 public void testCancelGroupChildrenForCanceledSummary_singletonGroup() throws Exception { 2783 final String originalGroupName = "originalGroup"; 2784 final String aggregateGroupName = "Aggregate_Test"; 2785 final int summaryId = Integer.MAX_VALUE; 2786 // Add a "singleton group" 2787 NotificationRecord nr0 = 2788 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 2789 NotificationRecord nr1 = 2790 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 2791 final NotificationRecord summary = 2792 generateNotificationRecord(mTestNotificationChannel, 2, originalGroupName, true); 2793 final String originalGroupKey = summary.getGroupKey(); 2794 mService.addNotification(nr0); 2795 mService.addNotification(nr1); 2796 mService.addNotification(summary); 2797 2798 // GroupHelper is a mock, so make the calls it would make 2799 // Remove the app's summary notification 2800 mService.removeAppSummaryLocked(summary.getKey()); 2801 waitForIdle(); 2802 2803 // Add aggregate group summary 2804 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 2805 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 2806 nr0.getChannel().getId()); 2807 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 2808 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 2809 mService.addNotification(aggregateSummary); 2810 2811 nr0.setOverrideGroupKey(aggregateGroupName); 2812 nr1.setOverrideGroupKey(aggregateGroupName); 2813 final String fullAggregateGroupKey = nr0.getGroupKey(); 2814 2815 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 2816 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 2817 nr0.getChannel().getId()); 2818 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 2819 assertThat(mService.mSummaryByGroupKey.containsKey(originalGroupKey)).isFalse(); 2820 2821 // Cancel the original app summary (is already removed) 2822 mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(), 2823 summary.getSbn().getPackageName(), summary.getSbn().getTag(), 2824 summary.getSbn().getId(), summary.getSbn().getUserId()); 2825 waitForIdle(); 2826 2827 // Check if NMS.CancelNotificationRunnable calls maybeCancelGroupChildrenForCanceledSummary 2828 verify(mGroupHelper, times(1)).maybeCancelGroupChildrenForCanceledSummary( 2829 eq(summary.getSbn().getPackageName()), eq(summary.getSbn().getTag()), 2830 eq(summary.getSbn().getId()), eq(summary.getSbn().getUserId()), 2831 eq(REASON_APP_CANCEL)); 2832 } 2833 2834 @Test 2835 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testUpdateChannel_notifyGroupHelper()2836 public void testUpdateChannel_notifyGroupHelper() throws Exception { 2837 mService.setPreferencesHelper(mPreferencesHelper); 2838 mTestNotificationChannel.setLightColor(Color.CYAN); 2839 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 2840 eq(mTestNotificationChannel.getId()), anyBoolean())) 2841 .thenReturn(mTestNotificationChannel); 2842 2843 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel); 2844 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2845 waitForIdle(); 2846 2847 verify(mGroupHelper, times(1)).onChannelUpdated(eq(Process.myUserHandle().getIdentifier()), 2848 eq(mPkg), eq(mTestNotificationChannel), any()); 2849 } 2850 2851 @Test 2852 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed()2853 public void testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed() throws Exception { 2854 final String aggregateGroupName = "Aggregate_Test"; 2855 2856 // build autogroup summary notification 2857 Notification.Builder nb = new Notification.Builder(mContext, 2858 mTestNotificationChannel.getId()) 2859 .setContentTitle("foo") 2860 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2861 .setGroup(aggregateGroupName) 2862 .setGroupSummary(true) 2863 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true); 2864 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 2865 "tag" + System.currentTimeMillis(), mUid, 0, nb.build(), 2866 UserHandle.getUserHandleForUid(mUid), null, 0); 2867 final NotificationRecord summary = new NotificationRecord(mContext, sbn, 2868 mTestNotificationChannel); 2869 2870 final NotificationRecord child = generateNotificationRecord( 2871 mTestNotificationChannel, 2, aggregateGroupName, false); 2872 mService.addNotification(summary); 2873 mService.addNotification(child); 2874 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 2875 2876 // snooze child only 2877 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 2878 mService.new SnoozeNotificationRunnable( 2879 child.getKey(), 100, null); 2880 snoozeNotificationRunnable.run(); 2881 2882 // only child should be snoozed 2883 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 2884 2885 // both group summary and child should be cancelled 2886 assertNull(mService.getNotificationRecord(summary.getKey())); 2887 assertNull(mService.getNotificationRecord(child.getKey())); 2888 2889 assertEquals(4, mNotificationRecordLogger.numCalls()); 2890 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 2891 mNotificationRecordLogger.event(0)); 2892 assertEquals( 2893 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 2894 mNotificationRecordLogger.event(1)); 2895 } 2896 2897 @Test 2898 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2899 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testOnlyForceGroupIfNeeded_newNotification_notAutogrouped()2900 public void testOnlyForceGroupIfNeeded_newNotification_notAutogrouped() { 2901 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 2902 when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false); 2903 mService.addEnqueuedNotification(r); 2904 NotificationManagerService.PostNotificationRunnable runnable = 2905 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 2906 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 2907 runnable.run(); 2908 waitForIdle(); 2909 2910 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2911 waitForIdle(); 2912 2913 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 2914 verify(mGroupHelper, times(1)).onNotificationPostedWithDelay(eq(r), any(), any()); 2915 } 2916 2917 @Test 2918 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2919 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped()2920 public void testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped() { 2921 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 2922 when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(true); 2923 mService.addEnqueuedNotification(r); 2924 NotificationManagerService.PostNotificationRunnable runnable = 2925 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 2926 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 2927 runnable.run(); 2928 waitForIdle(); 2929 2930 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2931 waitForIdle(); 2932 2933 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 2934 verify(mGroupHelper, never()).onNotificationPostedWithDelay(eq(r), any(), any()); 2935 } 2936 2937 @Test 2938 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2939 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testRemoveScheduledForceGroup_onNotificationCanceled()2940 public void testRemoveScheduledForceGroup_onNotificationCanceled() throws Exception { 2941 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "tag", null, 2942 false); 2943 when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false); 2944 mService.addEnqueuedNotification(r); 2945 NotificationManagerService.PostNotificationRunnable runnable = 2946 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 2947 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 2948 runnable.run(); 2949 waitForIdle(); 2950 2951 // Post an update to the notification 2952 NotificationRecord r_update = 2953 generateNotificationRecord(mTestNotificationChannel, 0, "tag", null, false); 2954 mService.addEnqueuedNotification(r_update); 2955 runnable = mService.new PostNotificationRunnable(r_update.getKey(), 2956 r_update.getSbn().getPackageName(), r_update.getUid(), 2957 mPostNotificationTrackerFactory.newTracker(null)); 2958 runnable.run(); 2959 waitForIdle(); 2960 2961 // Cancel the notification 2962 mBinderService.cancelNotificationWithTag(r.getSbn().getPackageName(), 2963 r.getSbn().getPackageName(), r.getSbn().getTag(), 2964 r.getSbn().getId(), r.getSbn().getUserId()); 2965 waitForIdle(); 2966 2967 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2968 waitForIdle(); 2969 2970 // Check that onNotificationPostedWithDelay was canceled 2971 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 2972 verify(mGroupHelper, never()).onNotificationPostedWithDelay(any(), any(), any()); 2973 } 2974 2975 @Test 2976 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testEnqueueNotification_forceGrouped_clearsSummaryFlag()2977 public void testEnqueueNotification_forceGrouped_clearsSummaryFlag() throws Exception { 2978 final String originalGroupName = "originalGroup"; 2979 final String aggregateGroupName = "Aggregate_Test"; 2980 2981 // Old record was a summary and it was auto-grouped 2982 final NotificationRecord r = 2983 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 2984 mService.addNotification(r); 2985 mService.convertSummaryToNotificationLocked(r.getKey()); 2986 mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true); 2987 2988 assertThat(mService.mNotificationList).hasSize(1); 2989 2990 // Update record is a summary 2991 final Notification updatedNotification = generateNotificationRecord( 2992 mTestNotificationChannel, 0, originalGroupName, true).getNotification(); 2993 assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY); 2994 2995 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 2996 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId()); 2997 waitForIdle(); 2998 2999 // Check that FLAG_GROUP_SUMMARY was removed 3000 assertThat(mService.mNotificationList).hasSize(1); 3001 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0); 3002 } 3003 3004 @Test 3005 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag()3006 public void testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag() 3007 throws Exception { 3008 final String originalGroupName = "originalGroup"; 3009 final String aggregateGroupName = "Aggregate_Test"; 3010 3011 // Old record was not summary and it was auto-grouped 3012 final NotificationRecord r = 3013 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 3014 mService.addNotification(r); 3015 mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true); 3016 assertThat(mService.mNotificationList).hasSize(1); 3017 3018 // Update record is a summary 3019 final Notification updatedNotification = generateNotificationRecord( 3020 mTestNotificationChannel, 0, originalGroupName, true).getNotification(); 3021 assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY); 3022 3023 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 3024 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId()); 3025 waitForIdle(); 3026 3027 // Check that FLAG_GROUP_SUMMARY was removed 3028 assertThat(mService.mNotificationList).hasSize(1); 3029 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0); 3030 } 3031 3032 @Test 3033 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testEnqueueNotification_notForceGrouped_dontClearSummaryFlag()3034 public void testEnqueueNotification_notForceGrouped_dontClearSummaryFlag() 3035 throws Exception { 3036 final String originalGroupName = "originalGroup"; 3037 3038 // Old record was a summary and it was not auto-grouped 3039 final NotificationRecord r = 3040 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 3041 mService.addNotification(r); 3042 assertThat(mService.mNotificationList).hasSize(1); 3043 3044 // Update record is a summary 3045 final Notification updatedNotification = generateNotificationRecord( 3046 mTestNotificationChannel, 0, originalGroupName, true).getNotification(); 3047 assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY); 3048 3049 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 3050 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId()); 3051 waitForIdle(); 3052 3053 // Check that FLAG_GROUP_SUMMARY was not removed 3054 assertThat(mService.mNotificationList).hasSize(1); 3055 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo( 3056 FLAG_GROUP_SUMMARY); 3057 } 3058 3059 @Test 3060 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag()3061 public void testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag() { 3062 final String originalGroupName = "originalGroup"; 3063 final String aggregateGroupName = "Aggregate_Test"; 3064 3065 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, 3066 originalGroupName, true); 3067 r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY; 3068 r.setOverrideGroupKey(aggregateGroupName); 3069 mService.addEnqueuedNotification(r); 3070 3071 mInternalService.removeForegroundServiceFlagFromNotification( 3072 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 3073 waitForIdle(); 3074 3075 assertThat(mService.mEnqueuedNotifications).hasSize(1); 3076 assertThat(mService.mEnqueuedNotifications.get(0).getFlags() & FLAG_GROUP_SUMMARY) 3077 .isEqualTo(0); 3078 } 3079 3080 @Test 3081 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag()3082 public void testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag() { 3083 final String originalGroupName = "originalGroup"; 3084 final String aggregateGroupName = "Aggregate_Test"; 3085 3086 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, 3087 originalGroupName, true); 3088 r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY; 3089 r.setOverrideGroupKey(aggregateGroupName); 3090 mService.addNotification(r); 3091 3092 mInternalService.removeForegroundServiceFlagFromNotification( 3093 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 3094 waitForIdle(); 3095 3096 assertThat(mService.mNotificationList).hasSize(1); 3097 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0); 3098 } 3099 3100 @Test 3101 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 3102 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testScheduleGroupHelperWithDelay_onChildNotificationCanceled()3103 public void testScheduleGroupHelperWithDelay_onChildNotificationCanceled() throws Exception { 3104 // Post summary + 2 child notification 3105 final String originalGroupName = "originalGroup"; 3106 final int summaryId = 0; 3107 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 3108 summaryId + 1, originalGroupName, false); 3109 mService.addNotification(r1); 3110 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 3111 summaryId + 2, originalGroupName, false); 3112 mService.addNotification(r2); 3113 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 3114 summaryId, originalGroupName, true); 3115 mService.addNotification(summary); 3116 final String originalGroupKey = summary.getGroupKey(); 3117 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 3118 3119 // Cancel the child notifications 3120 mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(), 3121 r1.getSbn().getPackageName(), r1.getSbn().getTag(), 3122 r1.getSbn().getId(), r1.getSbn().getUserId()); 3123 waitForIdle(); 3124 3125 mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(), 3126 r2.getSbn().getPackageName(), r2.getSbn().getTag(), 3127 r2.getSbn().getId(), r2.getSbn().getUserId()); 3128 waitForIdle(); 3129 3130 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 3131 waitForIdle(); 3132 3133 // Check that onGroupedNotificationRemovedWithDelay was called only once 3134 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any()); 3135 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any()); 3136 verify(mGroupHelper, times(1)).onGroupedNotificationRemovedWithDelay(eq(summary), any(), 3137 any()); 3138 } 3139 3140 @Test 3141 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 3142 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()3143 public void testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled() 3144 throws Exception { 3145 // Post summary + 2 child notification 3146 final String originalGroupName = "originalGroup"; 3147 final int summaryId = 0; 3148 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 3149 summaryId + 1, originalGroupName, false); 3150 mService.addNotification(r1); 3151 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 3152 summaryId + 2, originalGroupName, false); 3153 mService.addNotification(r2); 3154 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 3155 summaryId, originalGroupName, true); 3156 mService.addNotification(summary); 3157 final String originalGroupKey = summary.getGroupKey(); 3158 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 3159 3160 // Cancel all notifications: children + summary 3161 mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(), 3162 r1.getSbn().getPackageName(), r1.getSbn().getTag(), 3163 r1.getSbn().getId(), r1.getSbn().getUserId()); 3164 waitForIdle(); 3165 3166 mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(), 3167 r2.getSbn().getPackageName(), r2.getSbn().getTag(), 3168 r2.getSbn().getId(), r2.getSbn().getUserId()); 3169 waitForIdle(); 3170 3171 mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(), 3172 summary.getSbn().getPackageName(), summary.getSbn().getTag(), 3173 summary.getSbn().getId(), summary.getSbn().getUserId()); 3174 waitForIdle(); 3175 3176 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 3177 waitForIdle(); 3178 3179 // Check that onGroupedNotificationRemovedWithDelay was never called: summary was canceled 3180 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any()); 3181 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any()); 3182 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(summary), any()); 3183 verify(mGroupHelper, never()).onGroupedNotificationRemovedWithDelay(any(), any(), any()); 3184 } 3185 3186 @Test testCancelAllNotifications_IgnoreForegroundService()3187 public void testCancelAllNotifications_IgnoreForegroundService() throws Exception { 3188 when(mAmi.applyForegroundServiceNotification( 3189 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 3190 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3191 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3192 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3193 "testCancelAllNotifications_IgnoreForegroundService", 3194 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3195 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 3196 waitForIdle(); 3197 StatusBarNotification[] notifs = 3198 mBinderService.getActiveNotifications(sbn.getPackageName()); 3199 assertEquals(1, notifs.length); 3200 assertEquals(1, mService.getNotificationRecordCount()); 3201 } 3202 3203 @Test testCancelAllNotifications_FgsFlag_NoFgs_Allowed()3204 public void testCancelAllNotifications_FgsFlag_NoFgs_Allowed() throws Exception { 3205 when(mAmi.applyForegroundServiceNotification( 3206 any(), anyString(), anyInt(), anyString(), anyInt())) 3207 .thenReturn(NOT_FOREGROUND_SERVICE); 3208 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3209 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3210 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3211 "testCancelAllNotifications_IgnoreForegroundService", 3212 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3213 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 3214 waitForIdle(); 3215 StatusBarNotification[] notifs = 3216 mBinderService.getActiveNotifications(sbn.getPackageName()); 3217 assertEquals(0, notifs.length); 3218 } 3219 3220 @Test testCancelAllNotifications_IgnoreOtherPackages()3221 public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception { 3222 when(mAmi.applyForegroundServiceNotification( 3223 any(), anyString(), anyInt(), anyString(), anyInt())) 3224 .thenReturn(SHOW_IMMEDIATELY); 3225 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3226 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3227 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3228 "testCancelAllNotifications_IgnoreOtherPackages", 3229 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3230 mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); 3231 waitForIdle(); 3232 StatusBarNotification[] notifs = 3233 mBinderService.getActiveNotifications(sbn.getPackageName()); 3234 assertEquals(1, notifs.length); 3235 assertEquals(1, mService.getNotificationRecordCount()); 3236 } 3237 3238 @Test testCancelAllNotifications_NullPkgRemovesAll()3239 public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception { 3240 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3241 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3242 "testCancelAllNotifications_NullPkgRemovesAll", 3243 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3244 mBinderService.cancelAllNotifications(null, sbn.getUserId()); 3245 waitForIdle(); 3246 StatusBarNotification[] notifs = 3247 mBinderService.getActiveNotifications(sbn.getPackageName()); 3248 assertEquals(0, notifs.length); 3249 assertEquals(0, mService.getNotificationRecordCount()); 3250 } 3251 3252 @Test testCancelAllNotifications_NullPkgIgnoresUserAllNotifications()3253 public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception { 3254 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3255 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3256 "testCancelAllNotifications_NullPkgIgnoresUserAllNotifications", 3257 sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL); 3258 // Null pkg is how we signal a user switch. 3259 mBinderService.cancelAllNotifications(null, sbn.getUserId()); 3260 waitForIdle(); 3261 StatusBarNotification[] notifs = 3262 mBinderService.getActiveNotifications(sbn.getPackageName()); 3263 assertEquals(1, notifs.length); 3264 assertEquals(1, mService.getNotificationRecordCount()); 3265 } 3266 3267 @Test testAppInitiatedCancelAllNotifications_CancelsNoClearFlag()3268 public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception { 3269 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3270 sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3271 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3272 "testAppInitiatedCancelAllNotifications_CancelsNoClearFlag", 3273 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3274 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 3275 waitForIdle(); 3276 StatusBarNotification[] notifs = 3277 mBinderService.getActiveNotifications(sbn.getPackageName()); 3278 assertEquals(0, notifs.length); 3279 } 3280 3281 @Test testCancelAllNotifications_CancelsNoClearFlag()3282 public void testCancelAllNotifications_CancelsNoClearFlag() throws Exception { 3283 final NotificationRecord notif = generateNotificationRecord( 3284 mTestNotificationChannel, 1, "group", true); 3285 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3286 mService.addNotification(notif); 3287 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 3288 notif.getUserId(), REASON_CANCEL); 3289 waitForIdle(); 3290 StatusBarNotification[] notifs = 3291 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3292 assertEquals(0, notifs.length); 3293 } 3294 3295 @Test testUserInitiatedCancelAllOnClearAll_NoClearFlag()3296 public void testUserInitiatedCancelAllOnClearAll_NoClearFlag() throws Exception { 3297 final NotificationRecord notif = generateNotificationRecord( 3298 mTestNotificationChannel, 1, "group", true); 3299 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3300 mService.addNotification(notif); 3301 3302 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 3303 notif.getUserId()); 3304 waitForIdle(); 3305 StatusBarNotification[] notifs = 3306 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3307 assertEquals(1, notifs.length); 3308 } 3309 3310 @Test testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue()3311 public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception { 3312 when(mAmi.applyForegroundServiceNotification( 3313 any(), anyString(), anyInt(), anyString(), anyInt())) 3314 .thenReturn(SHOW_IMMEDIATELY); 3315 Notification n = 3316 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 3317 .setSmallIcon(android.R.drawable.sym_def_app_icon) 3318 .build(); 3319 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, 3320 n, UserHandle.getUserHandleForUid(mUid), null, 0); 3321 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3322 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null, 3323 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3324 mInternalService.removeForegroundServiceFlagFromNotification(mPkg, sbn.getId(), 3325 sbn.getUserId()); 3326 waitForIdle(); 3327 StatusBarNotification[] notifs = 3328 mBinderService.getActiveNotifications(sbn.getPackageName()); 3329 assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE); 3330 } 3331 3332 @Test testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag()3333 public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception { 3334 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3335 sbn.getNotification().flags = 3336 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE; 3337 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 3338 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3339 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; 3340 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 3341 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3342 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3343 sbn.getUserId()); 3344 waitForIdle(); 3345 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 3346 assertEquals(0, mService.getNotificationRecordCount()); 3347 } 3348 3349 @Test 3350 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelWithTagDoesNotCancelLifetimeExtended()3351 public void testCancelWithTagDoesNotCancelLifetimeExtended() throws Exception { 3352 final NotificationRecord notif = generateNotificationRecord(null); 3353 notif.getSbn().getNotification().flags = 3354 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3355 mService.addNotification(notif); 3356 final StatusBarNotification sbn = notif.getSbn(); 3357 3358 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3359 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3360 3361 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3362 sbn.getUserId()); 3363 waitForIdle(); 3364 3365 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3366 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3367 3368 // Checks that a post update is sent. 3369 verify(mWorkerHandler, times(1)) 3370 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3371 ArgumentCaptor<NotificationRecord> captor = 3372 ArgumentCaptor.forClass(NotificationRecord.class); 3373 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3374 anyBoolean()); 3375 assertThat(captor.getValue().getNotification().flags 3376 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3377 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3378 } 3379 3380 @Test 3381 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testMultipleCancelOfLifetimeExtendedSendsOneUpdate()3382 public void testMultipleCancelOfLifetimeExtendedSendsOneUpdate() throws Exception { 3383 final NotificationRecord notif = generateNotificationRecord(null); 3384 notif.getSbn().getNotification().flags = 3385 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3386 mService.addNotification(notif); 3387 final StatusBarNotification sbn = notif.getSbn(); 3388 3389 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3390 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3391 3392 // Send two cancelations. 3393 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3394 sbn.getUserId()); 3395 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3396 sbn.getUserId()); 3397 waitForIdle(); 3398 3399 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3400 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3401 3402 // Checks that only one post update is sent. 3403 verify(mWorkerHandler, times(1)) 3404 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3405 ArgumentCaptor<NotificationRecord> captor = 3406 ArgumentCaptor.forClass(NotificationRecord.class); 3407 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3408 anyBoolean()); 3409 assertThat(captor.getValue().getNotification().flags 3410 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3411 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3412 } 3413 3414 @Test 3415 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelAllClearsLifetimeExtended()3416 public void testCancelAllClearsLifetimeExtended() throws Exception { 3417 final NotificationRecord notif = generateNotificationRecord( 3418 mTestNotificationChannel, 1, "group", true); 3419 notif.getNotification().flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3420 mService.addNotification(notif); 3421 StatusBarNotification[] notifs = 3422 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3423 assertThat(notifs.length).isEqualTo(1); 3424 3425 // Simulate a "cancel all" received. 3426 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 3427 notif.getUserId()); 3428 waitForIdle(); 3429 notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3430 assertThat(notifs.length).isEqualTo(0); 3431 3432 // Test that no update post is sent to System UI. 3433 verify(mWorkerHandler, never()) 3434 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 3435 } 3436 3437 @Test 3438 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testAppCancelAllDoesNotCancelLifetimeExtended()3439 public void testAppCancelAllDoesNotCancelLifetimeExtended() throws Exception { 3440 // Adds a lifetime extended notification. 3441 final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1, 3442 null, false); 3443 notif.getSbn().getNotification().flags = 3444 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3445 mService.addNotification(notif); 3446 // Adds a second, non-lifetime extended notification. 3447 final NotificationRecord notifCancelable = generateNotificationRecord( 3448 mTestNotificationChannel, 2, null, false); 3449 mService.addNotification(notifCancelable); 3450 // Verify that both notifications have been posted and are active. 3451 assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(2); 3452 3453 mBinderService.cancelAllNotifications(mPkg, notif.getSbn().getUserId()); 3454 waitForIdle(); 3455 3456 // The non-lifetime extended notification, with id = 2, has been cancelled. 3457 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 3458 assertThat(notifs.length).isEqualTo(1); 3459 assertThat(notifs[0].getId()).isEqualTo(1); 3460 3461 // Checks that a post update is sent. 3462 verify(mWorkerHandler, times(1)) 3463 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3464 ArgumentCaptor<NotificationRecord> captor = 3465 ArgumentCaptor.forClass(NotificationRecord.class); 3466 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3467 anyBoolean()); 3468 assertThat(captor.getValue().getNotification().flags 3469 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3470 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3471 } 3472 3473 @Test 3474 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testLifetimeExtendedCancelledOnClick()3475 public void testLifetimeExtendedCancelledOnClick() throws Exception { 3476 // Adds a lifetime extended notification. 3477 final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1, 3478 null, false); 3479 notif.getSbn().getNotification().flags = 3480 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3481 mService.addNotification(notif); 3482 // Verify that the notification is posted and active. 3483 assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(1); 3484 3485 // Click the notification. 3486 final NotificationVisibility nv = NotificationVisibility.obtain(notif.getKey(), 1, 2, true); 3487 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 3488 notif.getKey(), nv); 3489 waitForIdle(); 3490 3491 // The notification has been cancelled. 3492 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 3493 assertThat(notifs.length).isEqualTo(0); 3494 } 3495 3496 @Test testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()3497 public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild() 3498 throws Exception { 3499 when(mAmi.applyForegroundServiceNotification( 3500 any(), anyString(), anyInt(), anyString(), anyInt())) 3501 .thenReturn(SHOW_IMMEDIATELY); 3502 mService.isSystemUid = false; 3503 mService.isSystemAppId = false; 3504 final NotificationRecord parent = generateNotificationRecord( 3505 mTestNotificationChannel, 1, "group", true); 3506 final NotificationRecord child = generateNotificationRecord( 3507 mTestNotificationChannel, 2, "group", false); 3508 final NotificationRecord child2 = generateNotificationRecord( 3509 mTestNotificationChannel, 3, "group", false); 3510 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3511 mService.addNotification(parent); 3512 mService.addNotification(child); 3513 mService.addNotification(child2); 3514 mService.getBinderService().cancelNotificationWithTag( 3515 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 3516 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 3517 waitForIdle(); 3518 StatusBarNotification[] notifs = 3519 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3520 assertEquals(1, notifs.length); 3521 } 3522 3523 @Test testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()3524 public void testCancelNotificationWithTag_fromApp_cannotCancelFgsParent() 3525 throws Exception { 3526 when(mAmi.applyForegroundServiceNotification( 3527 any(), anyString(), anyInt(), anyString(), anyInt())) 3528 .thenReturn(SHOW_IMMEDIATELY); 3529 mService.isSystemUid = false; 3530 mService.isSystemAppId = false; 3531 final NotificationRecord parent = generateNotificationRecord( 3532 mTestNotificationChannel, 1, "group", true); 3533 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3534 final NotificationRecord child = generateNotificationRecord( 3535 mTestNotificationChannel, 2, "group", false); 3536 final NotificationRecord child2 = generateNotificationRecord( 3537 mTestNotificationChannel, 3, "group", false); 3538 mService.addNotification(parent); 3539 mService.addNotification(child); 3540 mService.addNotification(child2); 3541 mService.getBinderService().cancelNotificationWithTag( 3542 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 3543 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 3544 waitForIdle(); 3545 StatusBarNotification[] notifs = 3546 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3547 assertEquals(3, notifs.length); 3548 } 3549 3550 @Test testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()3551 public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild() 3552 throws Exception { 3553 mService.isSystemUid = false; 3554 mService.isSystemAppId = false; 3555 final NotificationRecord parent = generateNotificationRecord( 3556 mTestNotificationChannel, 1, "group", true); 3557 final NotificationRecord child = generateNotificationRecord( 3558 mTestNotificationChannel, 2, "group", false); 3559 final NotificationRecord child2 = generateNotificationRecord( 3560 mTestNotificationChannel, 3, "group", false); 3561 child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3562 mService.addNotification(parent); 3563 mService.addNotification(child); 3564 mService.addNotification(child2); 3565 mService.getBinderService().cancelNotificationWithTag( 3566 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 3567 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 3568 waitForIdle(); 3569 StatusBarNotification[] notifs = 3570 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3571 assertEquals(0, notifs.length); 3572 } 3573 3574 @Test testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()3575 public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent() 3576 throws Exception { 3577 mService.isSystemUid = false; 3578 mService.isSystemAppId = false; 3579 final NotificationRecord parent = generateNotificationRecord( 3580 mTestNotificationChannel, 1, "group", true); 3581 parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3582 final NotificationRecord child = generateNotificationRecord( 3583 mTestNotificationChannel, 2, "group", false); 3584 final NotificationRecord child2 = generateNotificationRecord( 3585 mTestNotificationChannel, 3, "group", false); 3586 mService.addNotification(parent); 3587 mService.addNotification(child); 3588 mService.addNotification(child2); 3589 mService.getBinderService().cancelNotificationWithTag( 3590 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 3591 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 3592 waitForIdle(); 3593 StatusBarNotification[] notifs = 3594 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3595 assertEquals(0, notifs.length); 3596 } 3597 3598 @Test testCancelAllNotificationsFromApp_cannotCancelFgsChild()3599 public void testCancelAllNotificationsFromApp_cannotCancelFgsChild() 3600 throws Exception { 3601 when(mAmi.applyForegroundServiceNotification( 3602 any(), anyString(), anyInt(), anyString(), anyInt())) 3603 .thenReturn(SHOW_IMMEDIATELY); 3604 mService.isSystemUid = false; 3605 mService.isSystemAppId = false; 3606 final NotificationRecord parent = generateNotificationRecord( 3607 mTestNotificationChannel, 1, "group", true); 3608 final NotificationRecord child = generateNotificationRecord( 3609 mTestNotificationChannel, 2, "group", false); 3610 final NotificationRecord child2 = generateNotificationRecord( 3611 mTestNotificationChannel, 3, "group", false); 3612 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3613 final NotificationRecord newGroup = generateNotificationRecord( 3614 mTestNotificationChannel, 4, "group2", false); 3615 mService.addNotification(parent); 3616 mService.addNotification(child); 3617 mService.addNotification(child2); 3618 mService.addNotification(newGroup); 3619 mService.getBinderService().cancelAllNotifications( 3620 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3621 waitForIdle(); 3622 StatusBarNotification[] notifs = 3623 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3624 assertEquals(1, notifs.length); 3625 } 3626 3627 @Test testCancelAllNotifications_fromApp_cannotCancelFgsParent()3628 public void testCancelAllNotifications_fromApp_cannotCancelFgsParent() 3629 throws Exception { 3630 when(mAmi.applyForegroundServiceNotification( 3631 any(), anyString(), anyInt(), anyString(), anyInt())) 3632 .thenReturn(SHOW_IMMEDIATELY); 3633 mService.isSystemUid = false; 3634 mService.isSystemAppId = false; 3635 final NotificationRecord parent = generateNotificationRecord( 3636 mTestNotificationChannel, 1, "group", true); 3637 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3638 final NotificationRecord child = generateNotificationRecord( 3639 mTestNotificationChannel, 2, "group", false); 3640 final NotificationRecord child2 = generateNotificationRecord( 3641 mTestNotificationChannel, 3, "group", false); 3642 final NotificationRecord newGroup = generateNotificationRecord( 3643 mTestNotificationChannel, 4, "group2", false); 3644 mService.addNotification(parent); 3645 mService.addNotification(child); 3646 mService.addNotification(child2); 3647 mService.addNotification(newGroup); 3648 mService.getBinderService().cancelAllNotifications( 3649 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3650 waitForIdle(); 3651 StatusBarNotification[] notifs = 3652 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3653 assertEquals(1, notifs.length); 3654 } 3655 3656 @Test testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()3657 public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild() 3658 throws Exception { 3659 mService.isSystemUid = false; 3660 mService.isSystemAppId = false; 3661 final NotificationRecord parent = generateNotificationRecord( 3662 mTestNotificationChannel, 1, "group", true); 3663 final NotificationRecord child = generateNotificationRecord( 3664 mTestNotificationChannel, 2, "group", false); 3665 final NotificationRecord child2 = generateNotificationRecord( 3666 mTestNotificationChannel, 3, "group", false); 3667 child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3668 final NotificationRecord newGroup = generateNotificationRecord( 3669 mTestNotificationChannel, 4, "group2", false); 3670 mService.addNotification(parent); 3671 mService.addNotification(child); 3672 mService.addNotification(child2); 3673 mService.addNotification(newGroup); 3674 mService.getBinderService().cancelAllNotifications( 3675 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3676 waitForIdle(); 3677 StatusBarNotification[] notifs = 3678 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3679 assertEquals(0, notifs.length); 3680 } 3681 3682 @Test testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()3683 public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent() 3684 throws Exception { 3685 mService.isSystemUid = false; 3686 mService.isSystemAppId = false; 3687 final NotificationRecord parent = generateNotificationRecord( 3688 mTestNotificationChannel, 1, "group", true); 3689 parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3690 final NotificationRecord child = generateNotificationRecord( 3691 mTestNotificationChannel, 2, "group", false); 3692 final NotificationRecord child2 = generateNotificationRecord( 3693 mTestNotificationChannel, 3, "group", false); 3694 final NotificationRecord newGroup = generateNotificationRecord( 3695 mTestNotificationChannel, 4, "group2", false); 3696 mService.addNotification(parent); 3697 mService.addNotification(child); 3698 mService.addNotification(child2); 3699 mService.addNotification(newGroup); 3700 mService.getBinderService().cancelAllNotifications( 3701 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3702 waitForIdle(); 3703 StatusBarNotification[] notifs = 3704 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3705 assertEquals(0, notifs.length); 3706 } 3707 3708 @Test testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()3709 public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent() 3710 throws Exception { 3711 final NotificationRecord parent = generateNotificationRecord( 3712 mTestNotificationChannel, 1, "group", true); 3713 parent.getNotification().flags |= FLAG_ONGOING_EVENT; 3714 final NotificationRecord child = generateNotificationRecord( 3715 mTestNotificationChannel, 2, "group", false); 3716 final NotificationRecord child2 = generateNotificationRecord( 3717 mTestNotificationChannel, 3, "group", false); 3718 final NotificationRecord newGroup = generateNotificationRecord( 3719 mTestNotificationChannel, 4, "group2", false); 3720 mService.addNotification(parent); 3721 mService.addNotification(child); 3722 mService.addNotification(child2); 3723 mService.addNotification(newGroup); 3724 mService.getBinderService().cancelNotificationsFromListener(null, null); 3725 waitForIdle(); 3726 StatusBarNotification[] notifs = 3727 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3728 assertEquals(1, notifs.length); 3729 } 3730 3731 @Test testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()3732 public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild() 3733 throws Exception { 3734 final NotificationRecord parent = generateNotificationRecord( 3735 mTestNotificationChannel, 1, "group", true); 3736 final NotificationRecord child = generateNotificationRecord( 3737 mTestNotificationChannel, 2, "group", false); 3738 final NotificationRecord child2 = generateNotificationRecord( 3739 mTestNotificationChannel, 3, "group", false); 3740 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3741 final NotificationRecord newGroup = generateNotificationRecord( 3742 mTestNotificationChannel, 4, "group2", false); 3743 mService.addNotification(parent); 3744 mService.addNotification(child); 3745 mService.addNotification(child2); 3746 mService.addNotification(newGroup); 3747 mService.getBinderService().cancelNotificationsFromListener(null, null); 3748 waitForIdle(); 3749 StatusBarNotification[] notifs = 3750 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3751 assertEquals(1, notifs.length); 3752 } 3753 3754 @Test testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()3755 public void testCancelNotificationsFromListener_clearAll_GroupWithFgsParent() 3756 throws Exception { 3757 when(mAmi.applyForegroundServiceNotification( 3758 any(), anyString(), anyInt(), anyString(), anyInt())) 3759 .thenReturn(SHOW_IMMEDIATELY); 3760 final NotificationRecord parent = generateNotificationRecord( 3761 mTestNotificationChannel, 1, "group", true); 3762 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3763 final NotificationRecord child = generateNotificationRecord( 3764 mTestNotificationChannel, 2, "group", false); 3765 final NotificationRecord child2 = generateNotificationRecord( 3766 mTestNotificationChannel, 3, "group", false); 3767 final NotificationRecord newGroup = generateNotificationRecord( 3768 mTestNotificationChannel, 4, "group2", false); 3769 mService.addNotification(parent); 3770 mService.addNotification(child); 3771 mService.addNotification(child2); 3772 mService.addNotification(newGroup); 3773 mService.getBinderService().cancelNotificationsFromListener(null, null); 3774 waitForIdle(); 3775 StatusBarNotification[] notifs = 3776 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3777 assertEquals(0, notifs.length); 3778 } 3779 3780 @Test testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()3781 public void testCancelNotificationsFromListener_clearAll_GroupWithFgsChild() 3782 throws Exception { 3783 when(mAmi.applyForegroundServiceNotification( 3784 any(), anyString(), anyInt(), anyString(), anyInt())) 3785 .thenReturn(SHOW_IMMEDIATELY); 3786 final NotificationRecord parent = generateNotificationRecord( 3787 mTestNotificationChannel, 1, "group", true); 3788 final NotificationRecord child = generateNotificationRecord( 3789 mTestNotificationChannel, 2, "group", false); 3790 final NotificationRecord child2 = generateNotificationRecord( 3791 mTestNotificationChannel, 3, "group", false); 3792 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3793 final NotificationRecord newGroup = generateNotificationRecord( 3794 mTestNotificationChannel, 4, "group2", false); 3795 mService.addNotification(parent); 3796 mService.addNotification(child); 3797 mService.addNotification(child2); 3798 mService.addNotification(newGroup); 3799 mService.getBinderService().cancelNotificationsFromListener(null, null); 3800 waitForIdle(); 3801 StatusBarNotification[] notifs = 3802 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3803 assertEquals(0, notifs.length); 3804 } 3805 3806 @Test testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()3807 public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent() 3808 throws Exception { 3809 final NotificationRecord parent = generateNotificationRecord( 3810 mTestNotificationChannel, 1, "group", true); 3811 parent.getNotification().flags |= FLAG_NO_CLEAR; 3812 final NotificationRecord child = generateNotificationRecord( 3813 mTestNotificationChannel, 2, "group", false); 3814 final NotificationRecord child2 = generateNotificationRecord( 3815 mTestNotificationChannel, 3, "group", false); 3816 final NotificationRecord newGroup = generateNotificationRecord( 3817 mTestNotificationChannel, 4, "group2", false); 3818 mService.addNotification(parent); 3819 mService.addNotification(child); 3820 mService.addNotification(child2); 3821 mService.addNotification(newGroup); 3822 mService.getBinderService().cancelNotificationsFromListener(null, null); 3823 waitForIdle(); 3824 StatusBarNotification[] notifs = 3825 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3826 assertEquals(1, notifs.length); 3827 } 3828 3829 @Test testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()3830 public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild() 3831 throws Exception { 3832 final NotificationRecord parent = generateNotificationRecord( 3833 mTestNotificationChannel, 1, "group", true); 3834 final NotificationRecord child = generateNotificationRecord( 3835 mTestNotificationChannel, 2, "group", false); 3836 final NotificationRecord child2 = generateNotificationRecord( 3837 mTestNotificationChannel, 3, "group", false); 3838 child2.getNotification().flags |= FLAG_NO_CLEAR; 3839 final NotificationRecord newGroup = generateNotificationRecord( 3840 mTestNotificationChannel, 4, "group2", false); 3841 mService.addNotification(parent); 3842 mService.addNotification(child); 3843 mService.addNotification(child2); 3844 mService.addNotification(newGroup); 3845 mService.getBinderService().cancelNotificationsFromListener(null, null); 3846 waitForIdle(); 3847 StatusBarNotification[] notifs = 3848 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3849 assertEquals(1, notifs.length); 3850 } 3851 3852 @Test testCancelNotificationsFromListener_clearAll_Ongoing()3853 public void testCancelNotificationsFromListener_clearAll_Ongoing() 3854 throws Exception { 3855 final NotificationRecord child2 = generateNotificationRecord( 3856 mTestNotificationChannel, 3, null, false); 3857 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3858 mService.addNotification(child2); 3859 String[] keys = {child2.getSbn().getKey()}; 3860 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3861 waitForIdle(); 3862 StatusBarNotification[] notifs = 3863 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3864 assertEquals(1, notifs.length); 3865 } 3866 3867 @Test testCancelNotificationsFromListener_clearAll_NoClear()3868 public void testCancelNotificationsFromListener_clearAll_NoClear() 3869 throws Exception { 3870 final NotificationRecord child2 = generateNotificationRecord( 3871 mTestNotificationChannel, 3, null, false); 3872 child2.getNotification().flags |= FLAG_NO_CLEAR; 3873 mService.addNotification(child2); 3874 mService.getBinderService().cancelNotificationsFromListener(null, null); 3875 waitForIdle(); 3876 StatusBarNotification[] notifs = 3877 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3878 assertEquals(1, notifs.length); 3879 } 3880 3881 @Test testCancelNotificationsFromListener_clearAll_Fgs()3882 public void testCancelNotificationsFromListener_clearAll_Fgs() 3883 throws Exception { 3884 when(mAmi.applyForegroundServiceNotification( 3885 any(), anyString(), anyInt(), anyString(), anyInt())) 3886 .thenReturn(SHOW_IMMEDIATELY); 3887 final NotificationRecord child2 = generateNotificationRecord( 3888 mTestNotificationChannel, 3, null, false); 3889 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3890 mService.addNotification(child2); 3891 mService.getBinderService().cancelNotificationsFromListener(null, null); 3892 waitForIdle(); 3893 StatusBarNotification[] notifs = 3894 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3895 assertEquals(0, notifs.length); 3896 } 3897 3898 @Test 3899 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()3900 public void testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt() 3901 throws Exception { 3902 final NotificationRecord notif = generateNotificationRecord( 3903 mTestNotificationChannel, 1, null, false); 3904 notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3905 mService.addNotification(notif); 3906 verify(mWorkerHandler, times(0)) 3907 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3908 mService.getBinderService().cancelNotificationsFromListener(null, null); 3909 waitForIdle(); 3910 // Notification not cancelled. 3911 StatusBarNotification[] notifs = 3912 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3913 assertThat(notifs.length).isEqualTo(1); 3914 3915 // Checks that a post update is sent. 3916 verify(mWorkerHandler, times(1)) 3917 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3918 ArgumentCaptor<NotificationRecord> captor = 3919 ArgumentCaptor.forClass(NotificationRecord.class); 3920 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3921 anyBoolean()); 3922 assertThat(captor.getValue().getNotification().flags 3923 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3924 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3925 } 3926 3927 @Test testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()3928 public void testCancelNotificationsFromListener_byKey_GroupWithOngoingParent() 3929 throws Exception { 3930 final NotificationRecord parent = generateNotificationRecord( 3931 mTestNotificationChannel, 1, "group", true); 3932 parent.getNotification().flags |= FLAG_ONGOING_EVENT; 3933 final NotificationRecord child = generateNotificationRecord( 3934 mTestNotificationChannel, 2, "group", false); 3935 final NotificationRecord child2 = generateNotificationRecord( 3936 mTestNotificationChannel, 3, "group", false); 3937 final NotificationRecord newGroup = generateNotificationRecord( 3938 mTestNotificationChannel, 4, "group2", false); 3939 mService.addNotification(parent); 3940 mService.addNotification(child); 3941 mService.addNotification(child2); 3942 mService.addNotification(newGroup); 3943 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3944 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3945 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3946 waitForIdle(); 3947 StatusBarNotification[] notifs = 3948 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3949 assertEquals(1, notifs.length); 3950 } 3951 3952 @Test testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()3953 public void testCancelNotificationsFromListener_byKey_GroupWithOngoingChild() 3954 throws Exception { 3955 final NotificationRecord parent = generateNotificationRecord( 3956 mTestNotificationChannel, 1, "group", true); 3957 final NotificationRecord child = generateNotificationRecord( 3958 mTestNotificationChannel, 2, "group", false); 3959 final NotificationRecord child2 = generateNotificationRecord( 3960 mTestNotificationChannel, 3, "group", false); 3961 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3962 final NotificationRecord newGroup = generateNotificationRecord( 3963 mTestNotificationChannel, 4, "group2", false); 3964 mService.addNotification(parent); 3965 mService.addNotification(child); 3966 mService.addNotification(child2); 3967 mService.addNotification(newGroup); 3968 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3969 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3970 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3971 waitForIdle(); 3972 StatusBarNotification[] notifs = 3973 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3974 assertEquals(1, notifs.length); 3975 } 3976 3977 @Test testCancelNotificationsFromListener_byKey_GroupWithFgsParent()3978 public void testCancelNotificationsFromListener_byKey_GroupWithFgsParent() 3979 throws Exception { 3980 when(mAmi.applyForegroundServiceNotification( 3981 any(), anyString(), anyInt(), anyString(), anyInt())) 3982 .thenReturn(SHOW_IMMEDIATELY); 3983 final NotificationRecord parent = generateNotificationRecord( 3984 mTestNotificationChannel, 1, "group", true); 3985 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3986 final NotificationRecord child = generateNotificationRecord( 3987 mTestNotificationChannel, 2, "group", false); 3988 final NotificationRecord child2 = generateNotificationRecord( 3989 mTestNotificationChannel, 3, "group", false); 3990 final NotificationRecord newGroup = generateNotificationRecord( 3991 mTestNotificationChannel, 4, "group2", false); 3992 mService.addNotification(parent); 3993 mService.addNotification(child); 3994 mService.addNotification(child2); 3995 mService.addNotification(newGroup); 3996 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3997 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3998 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3999 waitForIdle(); 4000 StatusBarNotification[] notifs = 4001 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4002 assertEquals(0, notifs.length); 4003 } 4004 4005 @Test testCancelNotificationsFromListener_byKey_GroupWithFgsChild()4006 public void testCancelNotificationsFromListener_byKey_GroupWithFgsChild() 4007 throws Exception { 4008 when(mAmi.applyForegroundServiceNotification( 4009 any(), anyString(), anyInt(), anyString(), anyInt())) 4010 .thenReturn(SHOW_IMMEDIATELY); 4011 final NotificationRecord parent = generateNotificationRecord( 4012 mTestNotificationChannel, 1, "group", true); 4013 final NotificationRecord child = generateNotificationRecord( 4014 mTestNotificationChannel, 2, "group", false); 4015 final NotificationRecord child2 = generateNotificationRecord( 4016 mTestNotificationChannel, 3, "group", false); 4017 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 4018 final NotificationRecord newGroup = generateNotificationRecord( 4019 mTestNotificationChannel, 4, "group2", false); 4020 mService.addNotification(parent); 4021 mService.addNotification(child); 4022 mService.addNotification(child2); 4023 mService.addNotification(newGroup); 4024 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 4025 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 4026 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4027 waitForIdle(); 4028 StatusBarNotification[] notifs = 4029 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4030 assertEquals(0, notifs.length); 4031 } 4032 4033 @Test testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()4034 public void testCancelNotificationsFromListener_byKey_GroupWithNoClearParent() 4035 throws Exception { 4036 final NotificationRecord parent = generateNotificationRecord( 4037 mTestNotificationChannel, 1, "group", true); 4038 parent.getNotification().flags |= FLAG_NO_CLEAR; 4039 final NotificationRecord child = generateNotificationRecord( 4040 mTestNotificationChannel, 2, "group", false); 4041 final NotificationRecord child2 = generateNotificationRecord( 4042 mTestNotificationChannel, 3, "group", false); 4043 final NotificationRecord newGroup = generateNotificationRecord( 4044 mTestNotificationChannel, 4, "group2", false); 4045 mService.addNotification(parent); 4046 mService.addNotification(child); 4047 mService.addNotification(child2); 4048 mService.addNotification(newGroup); 4049 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 4050 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 4051 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4052 waitForIdle(); 4053 StatusBarNotification[] notifs = 4054 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4055 assertEquals(0, notifs.length); 4056 } 4057 4058 @Test testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()4059 public void testCancelNotificationsFromListener_byKey_GroupWithNoClearChild() 4060 throws Exception { 4061 final NotificationRecord parent = generateNotificationRecord( 4062 mTestNotificationChannel, 1, "group", true); 4063 final NotificationRecord child = generateNotificationRecord( 4064 mTestNotificationChannel, 2, "group", false); 4065 final NotificationRecord child2 = generateNotificationRecord( 4066 mTestNotificationChannel, 3, "group", false); 4067 child2.getNotification().flags |= FLAG_NO_CLEAR; 4068 final NotificationRecord newGroup = generateNotificationRecord( 4069 mTestNotificationChannel, 4, "group2", false); 4070 mService.addNotification(parent); 4071 mService.addNotification(child); 4072 mService.addNotification(child2); 4073 mService.addNotification(newGroup); 4074 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 4075 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 4076 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4077 waitForIdle(); 4078 StatusBarNotification[] notifs = 4079 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4080 assertEquals(0, notifs.length); 4081 } 4082 4083 @Test testCancelNotificationsFromListener_byKey_Ongoing()4084 public void testCancelNotificationsFromListener_byKey_Ongoing() 4085 throws Exception { 4086 final NotificationRecord child2 = generateNotificationRecord( 4087 mTestNotificationChannel, 3, null, false); 4088 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 4089 mService.addNotification(child2); 4090 String[] keys = {child2.getSbn().getKey()}; 4091 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4092 waitForIdle(); 4093 StatusBarNotification[] notifs = 4094 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 4095 assertEquals(1, notifs.length); 4096 } 4097 4098 @Test testCancelNotificationsFromListener_byKey_NoClear()4099 public void testCancelNotificationsFromListener_byKey_NoClear() 4100 throws Exception { 4101 final NotificationRecord child2 = generateNotificationRecord( 4102 mTestNotificationChannel, 3, null, false); 4103 child2.getNotification().flags |= FLAG_NO_CLEAR; 4104 mService.addNotification(child2); 4105 String[] keys = {child2.getSbn().getKey()}; 4106 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4107 waitForIdle(); 4108 StatusBarNotification[] notifs = 4109 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 4110 assertEquals(0, notifs.length); 4111 } 4112 4113 @Test testCancelNotificationsFromListener_byKey_Fgs()4114 public void testCancelNotificationsFromListener_byKey_Fgs() 4115 throws Exception { 4116 when(mAmi.applyForegroundServiceNotification( 4117 any(), anyString(), anyInt(), anyString(), anyInt())) 4118 .thenReturn(SHOW_IMMEDIATELY); 4119 final NotificationRecord child2 = generateNotificationRecord( 4120 mTestNotificationChannel, 3, null, false); 4121 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 4122 mService.addNotification(child2); 4123 String[] keys = {child2.getSbn().getKey()}; 4124 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4125 waitForIdle(); 4126 StatusBarNotification[] notifs = 4127 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 4128 assertEquals(0, notifs.length); 4129 } 4130 4131 @Test 4132 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()4133 public void testCancelNotificationsFromListener_byKey_NoClearLifetimeExt() 4134 throws Exception { 4135 final NotificationRecord notif = generateNotificationRecord( 4136 mTestNotificationChannel, 3, null, false); 4137 notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 4138 mService.addNotification(notif); 4139 String[] keys = {notif.getSbn().getKey()}; 4140 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4141 waitForIdle(); 4142 StatusBarNotification[] notifs = 4143 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 4144 assertEquals(1, notifs.length); 4145 4146 // Checks that a post update is sent. 4147 verify(mWorkerHandler, times(1)) 4148 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 4149 ArgumentCaptor<NotificationRecord> captor = 4150 ArgumentCaptor.forClass(NotificationRecord.class); 4151 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 4152 anyBoolean()); 4153 assertThat(captor.getValue().getNotification().flags 4154 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 4155 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 4156 } 4157 4158 @Test testGroupInstanceIds()4159 public void testGroupInstanceIds() throws Exception { 4160 final NotificationRecord group1 = generateNotificationRecord( 4161 mTestNotificationChannel, 1, "group1", true); 4162 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds", 4163 group1.getSbn().getId(), group1.getSbn().getNotification(), 4164 group1.getSbn().getUserId()); 4165 waitForIdle(); 4166 4167 // same group, child, should be returned 4168 final NotificationRecord group1Child = generateNotificationRecord( 4169 mTestNotificationChannel, 2, "group1", false); 4170 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds", 4171 group1Child.getSbn().getId(), 4172 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); 4173 waitForIdle(); 4174 4175 assertEquals(2, mNotificationRecordLogger.numCalls()); 4176 assertEquals(mNotificationRecordLogger.get(0).getInstanceId(), 4177 mNotificationRecordLogger.get(1).groupInstanceId.getId()); 4178 } 4179 4180 @Test testFindGroupNotificationsLocked()4181 public void testFindGroupNotificationsLocked() throws Exception { 4182 // make sure the same notification can be found in both lists and returned 4183 final NotificationRecord group1 = generateNotificationRecord( 4184 mTestNotificationChannel, 1, "group1", true); 4185 mService.addEnqueuedNotification(group1); 4186 mService.addNotification(group1); 4187 4188 // should not be returned 4189 final NotificationRecord group2 = generateNotificationRecord( 4190 mTestNotificationChannel, 2, "group2", true); 4191 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 4192 group2.getSbn().getId(), group2.getSbn().getNotification(), 4193 group2.getSbn().getUserId()); 4194 waitForIdle(); 4195 4196 // should not be returned 4197 final NotificationRecord nonGroup = generateNotificationRecord( 4198 mTestNotificationChannel, 3, null, false); 4199 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 4200 nonGroup.getSbn().getId(), nonGroup.getSbn().getNotification(), 4201 nonGroup.getSbn().getUserId()); 4202 waitForIdle(); 4203 4204 // same group, child, should be returned 4205 final NotificationRecord group1Child = generateNotificationRecord( 4206 mTestNotificationChannel, 4, "group1", false); 4207 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 4208 group1Child.getSbn().getId(), 4209 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); 4210 waitForIdle(); 4211 4212 List<NotificationRecord> inGroup1 = 4213 mService.findGroupNotificationsLocked(mPkg, group1.getGroupKey(), 4214 group1.getSbn().getUserId()); 4215 assertEquals(3, inGroup1.size()); 4216 for (NotificationRecord record : inGroup1) { 4217 assertTrue(record.getGroupKey().equals(group1.getGroupKey())); 4218 assertTrue(record.getSbn().getId() == 1 || record.getSbn().getId() == 4); 4219 } 4220 } 4221 4222 @Test testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing()4223 public void testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing() throws Exception { 4224 final NotificationRecord notif = generateNotificationRecord( 4225 mTestNotificationChannel, 1, "group", true); 4226 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 4227 mService.addNotification(notif); 4228 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 4229 Notification.FLAG_ONGOING_EVENT, notif.getUserId(), REASON_CANCEL); 4230 waitForIdle(); 4231 StatusBarNotification[] notifs = 4232 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 4233 assertEquals(0, notifs.length); 4234 } 4235 4236 @Test testAppInitiatedCancelAllNotifications_CancelsOngoingFlag()4237 public void testAppInitiatedCancelAllNotifications_CancelsOngoingFlag() throws Exception { 4238 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 4239 sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 4240 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 4241 "testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag", 4242 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 4243 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 4244 waitForIdle(); 4245 StatusBarNotification[] notifs = 4246 mBinderService.getActiveNotifications(sbn.getPackageName()); 4247 assertEquals(0, notifs.length); 4248 } 4249 4250 @Test testCancelAllNotificationsInt_CancelsOngoingFlag()4251 public void testCancelAllNotificationsInt_CancelsOngoingFlag() throws Exception { 4252 final NotificationRecord notif = generateNotificationRecord( 4253 mTestNotificationChannel, 1, "group", true); 4254 notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 4255 mService.addNotification(notif); 4256 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 4257 notif.getUserId(), REASON_CANCEL); 4258 waitForIdle(); 4259 StatusBarNotification[] notifs = 4260 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 4261 assertEquals(0, notifs.length); 4262 } 4263 4264 @Test testUserInitiatedCancelAllWithGroup_OngoingFlag()4265 public void testUserInitiatedCancelAllWithGroup_OngoingFlag() throws Exception { 4266 final NotificationRecord parent = generateNotificationRecord( 4267 mTestNotificationChannel, 1, "group", true); 4268 final NotificationRecord child = generateNotificationRecord( 4269 mTestNotificationChannel, 2, "group", false); 4270 final NotificationRecord child2 = generateNotificationRecord( 4271 mTestNotificationChannel, 3, "group", false); 4272 child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 4273 final NotificationRecord newGroup = generateNotificationRecord( 4274 mTestNotificationChannel, 4, "group2", false); 4275 mService.addNotification(parent); 4276 mService.addNotification(child); 4277 mService.addNotification(child2); 4278 mService.addNotification(newGroup); 4279 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 4280 parent.getUserId()); 4281 waitForIdle(); 4282 StatusBarNotification[] notifs = 4283 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4284 assertEquals(1, notifs.length); 4285 } 4286 4287 @Test testUserInitiatedCancelAllWithGroup_NoClearFlag()4288 public void testUserInitiatedCancelAllWithGroup_NoClearFlag() throws Exception { 4289 final NotificationRecord parent = generateNotificationRecord( 4290 mTestNotificationChannel, 1, "group", true); 4291 final NotificationRecord child = generateNotificationRecord( 4292 mTestNotificationChannel, 2, "group", false); 4293 final NotificationRecord child2 = generateNotificationRecord( 4294 mTestNotificationChannel, 3, "group", false); 4295 child2.getNotification().flags |= Notification.FLAG_NO_CLEAR; 4296 final NotificationRecord newGroup = generateNotificationRecord( 4297 mTestNotificationChannel, 4, "group2", false); 4298 mService.addNotification(parent); 4299 mService.addNotification(child); 4300 mService.addNotification(child2); 4301 mService.addNotification(newGroup); 4302 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 4303 parent.getUserId()); 4304 waitForIdle(); 4305 StatusBarNotification[] notifs = 4306 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4307 assertEquals(1, notifs.length); 4308 } 4309 4310 @Test testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag()4311 public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception { 4312 when(mAmi.applyForegroundServiceNotification( 4313 any(), anyString(), anyInt(), anyString(), anyInt())) 4314 .thenReturn(SHOW_IMMEDIATELY); 4315 final NotificationRecord parent = generateNotificationRecord( 4316 mTestNotificationChannel, 1, "group", true); 4317 final NotificationRecord child = generateNotificationRecord( 4318 mTestNotificationChannel, 2, "group", false); 4319 final NotificationRecord child2 = generateNotificationRecord( 4320 mTestNotificationChannel, 3, "group", false); 4321 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 4322 final NotificationRecord newGroup = generateNotificationRecord( 4323 mTestNotificationChannel, 4, "group2", false); 4324 mService.addNotification(parent); 4325 mService.addNotification(child); 4326 mService.addNotification(child2); 4327 mService.addNotification(newGroup); 4328 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 4329 parent.getUserId()); 4330 waitForIdle(); 4331 StatusBarNotification[] notifs = 4332 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4333 assertEquals(0, notifs.length); 4334 } 4335 4336 @Test testDefaultChannelUpdatesApp_postMigrationToPermissions()4337 public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception { 4338 final NotificationChannel defaultChannel = mBinderService.getNotificationChannel( 4339 PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1, 4340 NotificationChannel.DEFAULT_CHANNEL_ID); 4341 defaultChannel.setImportance(IMPORTANCE_NONE); 4342 4343 mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel); 4344 4345 verify(mPermissionHelper).setNotificationPermission( 4346 PKG_N_MR1, ActivityManager.getCurrentUser(), false, true); 4347 } 4348 4349 @Test testPostNotification_appPermissionFixed()4350 public void testPostNotification_appPermissionFixed() throws Exception { 4351 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 4352 when(mPermissionHelper.isPermissionFixed(mPkg, mUserId)).thenReturn(true); 4353 4354 NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel); 4355 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 4356 "testPostNotification_appPermissionFixed", 0, 4357 temp.getNotification(), mUserId); 4358 waitForIdle(); 4359 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 4360 StatusBarNotification[] notifs = 4361 mBinderService.getActiveNotifications(mPkg); 4362 assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue(); 4363 } 4364 4365 @Test testSummaryNotification_appPermissionFixed()4366 public void testSummaryNotification_appPermissionFixed() { 4367 NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel); 4368 mService.addNotification(temp); 4369 4370 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 4371 when(mPermissionHelper.isPermissionFixed(mPkg, temp.getUserId())).thenReturn(true); 4372 4373 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 4374 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 4375 4376 NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(), 4377 temp.getSbn().getPackageName(), temp.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr); 4378 4379 assertThat(r.isImportanceFixed()).isTrue(); 4380 } 4381 4382 @Test testTvExtenderChannelOverride_onTv()4383 public void testTvExtenderChannelOverride_onTv() throws Exception { 4384 mService.setIsTelevision(true); 4385 mService.setPreferencesHelper(mPreferencesHelper); 4386 when(mPreferencesHelper.getNotificationChannel( 4387 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn( 4388 new NotificationChannel("foo", "foo", IMPORTANCE_HIGH)); 4389 4390 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); 4391 mBinderService.enqueueNotificationWithTag( 4392 mPkg, 4393 mPkg, 4394 "testTvExtenderChannelOverride_onTv", 4395 0, 4396 generateNotificationRecord(null, tv).getNotification(), 4397 mUserId); 4398 verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( 4399 anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean()); 4400 } 4401 4402 @Test testTvExtenderChannelOverride_notOnTv()4403 public void testTvExtenderChannelOverride_notOnTv() throws Exception { 4404 mService.setIsTelevision(false); 4405 mService.setPreferencesHelper(mPreferencesHelper); 4406 when(mPreferencesHelper.getNotificationChannel( 4407 anyString(), anyInt(), anyString(), anyBoolean())).thenReturn( 4408 mTestNotificationChannel); 4409 4410 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); 4411 mBinderService.enqueueNotificationWithTag( 4412 mPkg, 4413 mPkg, 4414 "testTvExtenderChannelOverride_notOnTv", 4415 0, 4416 generateNotificationRecord(null, tv).getNotification(), 4417 mUserId); 4418 verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( 4419 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null), 4420 anyBoolean(), anyBoolean()); 4421 } 4422 4423 @Test onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()4424 public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage() 4425 throws RemoteException { 4426 // Have preexisting posted notifications from revoked package and other packages. 4427 mService.addNotification(new NotificationRecord(mContext, 4428 generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel)); 4429 mService.addNotification(new NotificationRecord(mContext, 4430 generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); 4431 // Have preexisting enqueued notifications from revoked package and other packages. 4432 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4433 generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel)); 4434 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4435 generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); 4436 assertThat(mService.mNotificationList).hasSize(2); 4437 assertThat(mService.mEnqueuedNotifications).hasSize(2); 4438 4439 when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001); 4440 when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false); 4441 4442 mOnPermissionChangeListener.onOpChanged( 4443 AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0); 4444 waitForIdle(); 4445 4446 assertThat(mService.mNotificationList).hasSize(1); 4447 assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other"); 4448 assertThat(mService.mEnqueuedNotifications).hasSize(1); 4449 assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo( 4450 "other"); 4451 } 4452 4453 @Test onOpChanged_permissionStillGranted_notificationsAreNotAffected()4454 public void onOpChanged_permissionStillGranted_notificationsAreNotAffected() 4455 throws RemoteException { 4456 // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission 4457 // being now granted, AND having previously posted notifications from said package) should 4458 // never happen (if we trust the broadcasts are correct). So this test is for a what-if 4459 // scenario, to verify we still handle it reasonably. 4460 4461 // Have preexisting posted notifications from specific package and other packages. 4462 mService.addNotification(new NotificationRecord(mContext, 4463 generateSbn("granted", 1001, 1, 0), mTestNotificationChannel)); 4464 mService.addNotification(new NotificationRecord(mContext, 4465 generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); 4466 // Have preexisting enqueued notifications from specific package and other packages. 4467 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4468 generateSbn("granted", 1001, 3, 0), mTestNotificationChannel)); 4469 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4470 generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); 4471 assertThat(mService.mNotificationList).hasSize(2); 4472 assertThat(mService.mEnqueuedNotifications).hasSize(2); 4473 4474 when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001); 4475 when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true); 4476 4477 mOnPermissionChangeListener.onOpChanged( 4478 AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0); 4479 waitForIdle(); 4480 4481 assertThat(mService.mNotificationList).hasSize(2); 4482 assertThat(mService.mEnqueuedNotifications).hasSize(2); 4483 } 4484 4485 @Test onOpChanged_notInitializedUser_ignored()4486 public void onOpChanged_notInitializedUser_ignored() throws RemoteException { 4487 when(mUmInternal.isUserInitialized(eq(0))).thenReturn(false); 4488 4489 mOnPermissionChangeListener.onOpChanged( 4490 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0); 4491 waitForIdle(); 4492 4493 // We early-exited and didn't even query PM for package details. 4494 verify(mPackageManagerInternal, never()).getPackageUid(any(), anyLong(), anyInt()); 4495 } 4496 4497 @Test setNotificationsEnabledForPackage_disabling_clearsNotifications()4498 public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception { 4499 mService.addNotification(new NotificationRecord(mContext, 4500 generateSbn("package", 1001, 1, 0), mTestNotificationChannel)); 4501 assertThat(mService.mNotificationList).hasSize(1); 4502 when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001); 4503 when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn( 4504 true); 4505 4506 // Start with granted permission and simulate effect of revoking it. 4507 when(mPermissionHelper.hasPermission(1001)).thenReturn(true); 4508 doAnswer(invocation -> { 4509 when(mPermissionHelper.hasPermission(1001)).thenReturn(false); 4510 mOnPermissionChangeListener.onOpChanged( 4511 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0); 4512 return null; 4513 }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true); 4514 4515 mBinderService.setNotificationsEnabledForPackage("package", 1001, false); 4516 waitForIdle(); 4517 4518 assertThat(mService.mNotificationList).hasSize(0); 4519 4520 mTestableLooper.moveTimeForward(500); 4521 waitForIdle(); 4522 verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null)); 4523 } 4524 4525 @Test testUpdateAppNotifyCreatorBlock()4526 public void testUpdateAppNotifyCreatorBlock() throws Exception { 4527 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 4528 4529 mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, false); 4530 Thread.sleep(500); 4531 waitForIdle(); 4532 4533 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4534 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4535 4536 assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, 4537 captor.getValue().getAction()); 4538 assertEquals(mPkg, captor.getValue().getPackage()); 4539 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); 4540 } 4541 4542 @Test testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting()4543 public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception { 4544 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 4545 4546 mBinderService.setNotificationsEnabledForPackage(mPkg, 0, false); 4547 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 4548 } 4549 4550 @Test testUpdateAppNotifyCreatorUnblock()4551 public void testUpdateAppNotifyCreatorUnblock() throws Exception { 4552 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 4553 4554 mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, true); 4555 Thread.sleep(500); 4556 waitForIdle(); 4557 4558 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4559 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4560 4561 assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, 4562 captor.getValue().getAction()); 4563 assertEquals(mPkg, captor.getValue().getPackage()); 4564 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); 4565 } 4566 4567 @Test testUpdateChannelNotifyCreatorBlock()4568 public void testUpdateChannelNotifyCreatorBlock() throws Exception { 4569 mService.setPreferencesHelper(mPreferencesHelper); 4570 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4571 eq(mTestNotificationChannel.getId()), anyBoolean())) 4572 .thenReturn(mTestNotificationChannel); 4573 4574 NotificationChannel updatedChannel = 4575 new NotificationChannel(mTestNotificationChannel.getId(), 4576 mTestNotificationChannel.getName(), IMPORTANCE_NONE); 4577 4578 mBinderService.updateNotificationChannelForPackage(mPkg, 0, updatedChannel); 4579 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4580 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4581 4582 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED, 4583 captor.getValue().getAction()); 4584 assertEquals(mPkg, captor.getValue().getPackage()); 4585 assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra( 4586 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID)); 4587 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4588 } 4589 4590 @Test testUpdateChannelNotifyCreatorUnblock()4591 public void testUpdateChannelNotifyCreatorUnblock() throws Exception { 4592 NotificationChannel existingChannel = 4593 new NotificationChannel(mTestNotificationChannel.getId(), 4594 mTestNotificationChannel.getName(), IMPORTANCE_NONE); 4595 mService.setPreferencesHelper(mPreferencesHelper); 4596 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4597 eq(mTestNotificationChannel.getId()), anyBoolean())) 4598 .thenReturn(existingChannel); 4599 4600 mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel); 4601 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4602 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4603 4604 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED, 4605 captor.getValue().getAction()); 4606 assertEquals(mPkg, captor.getValue().getPackage()); 4607 assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra( 4608 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID)); 4609 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4610 } 4611 4612 @Test testUpdateChannelNoNotifyCreatorOtherChanges()4613 public void testUpdateChannelNoNotifyCreatorOtherChanges() throws Exception { 4614 NotificationChannel existingChannel = 4615 new NotificationChannel(mTestNotificationChannel.getId(), 4616 mTestNotificationChannel.getName(), IMPORTANCE_MAX); 4617 mService.setPreferencesHelper(mPreferencesHelper); 4618 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4619 eq(mTestNotificationChannel.getId()), anyBoolean())) 4620 .thenReturn(existingChannel); 4621 4622 mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel); 4623 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 4624 } 4625 4626 @Test testUpdateGroupNotifyCreatorBlock()4627 public void testUpdateGroupNotifyCreatorBlock() throws Exception { 4628 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 4629 mService.setPreferencesHelper(mPreferencesHelper); 4630 when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()), 4631 eq(mPkg), anyInt())) 4632 .thenReturn(existing); 4633 4634 NotificationChannelGroup updated = new NotificationChannelGroup("id", "name"); 4635 updated.setBlocked(true); 4636 4637 mBinderService.updateNotificationChannelGroupForPackage(mPkg, 0, updated); 4638 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4639 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4640 4641 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED, 4642 captor.getValue().getAction()); 4643 assertEquals(mPkg, captor.getValue().getPackage()); 4644 assertEquals(existing.getId(), captor.getValue().getStringExtra( 4645 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID)); 4646 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4647 } 4648 4649 @Test testUpdateGroupNotifyCreatorUnblock()4650 public void testUpdateGroupNotifyCreatorUnblock() throws Exception { 4651 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 4652 existing.setBlocked(true); 4653 mService.setPreferencesHelper(mPreferencesHelper); 4654 when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()), 4655 eq(mPkg), anyInt())) 4656 .thenReturn(existing); 4657 4658 mBinderService.updateNotificationChannelGroupForPackage( 4659 mPkg, 0, new NotificationChannelGroup("id", "name")); 4660 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4661 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4662 4663 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED, 4664 captor.getValue().getAction()); 4665 assertEquals(mPkg, captor.getValue().getPackage()); 4666 assertEquals(existing.getId(), captor.getValue().getStringExtra( 4667 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID)); 4668 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4669 } 4670 4671 @Test testUpdateGroupNoNotifyCreatorOtherChanges()4672 public void testUpdateGroupNoNotifyCreatorOtherChanges() throws Exception { 4673 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 4674 mService.setPreferencesHelper(mPreferencesHelper); 4675 when(mPreferencesHelper.getNotificationChannelGroup( 4676 eq(existing.getId()), eq(mPkg), anyInt())) 4677 .thenReturn(existing); 4678 4679 mBinderService.updateNotificationChannelGroupForPackage( 4680 mPkg, 0, new NotificationChannelGroup("id", "new name")); 4681 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 4682 } 4683 4684 @Test testCreateChannelNotifyListener()4685 public void testCreateChannelNotifyListener() throws Exception { 4686 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4687 .thenReturn(singletonList(mock(AssociationInfo.class))); 4688 mService.setPreferencesHelper(mPreferencesHelper); 4689 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4690 eq(mTestNotificationChannel.getId()), anyBoolean())) 4691 .thenReturn(mTestNotificationChannel); 4692 NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW); 4693 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4694 eq(channel2.getId()), anyBoolean())) 4695 .thenReturn(channel2); 4696 when(mPreferencesHelper.createNotificationChannel(eq(mPkg), anyInt(), 4697 eq(channel2), anyBoolean(), anyBoolean(), anyInt(), anyBoolean())) 4698 .thenReturn(true); 4699 4700 reset(mListeners); 4701 mBinderService.createNotificationChannels(mPkg, 4702 new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2))); 4703 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4704 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4705 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4706 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4707 eq(Process.myUserHandle()), eq(channel2), 4708 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4709 } 4710 4711 @Test testCreateChannelGroupNotifyListener()4712 public void testCreateChannelGroupNotifyListener() throws Exception { 4713 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4714 .thenReturn(singletonList(mock(AssociationInfo.class))); 4715 mService.setPreferencesHelper(mPreferencesHelper); 4716 NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b"); 4717 NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m"); 4718 4719 reset(mListeners); 4720 mBinderService.createNotificationChannelGroups(mPkg, 4721 new ParceledListSlice(Arrays.asList(group1, group2))); 4722 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 4723 eq(Process.myUserHandle()), eq(group1), 4724 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4725 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 4726 eq(Process.myUserHandle()), eq(group2), 4727 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4728 } 4729 4730 @Test testUpdateChannelNotifyListener()4731 public void testUpdateChannelNotifyListener() throws Exception { 4732 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4733 .thenReturn(singletonList(mock(AssociationInfo.class))); 4734 mService.setPreferencesHelper(mPreferencesHelper); 4735 mTestNotificationChannel.setLightColor(Color.CYAN); 4736 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4737 eq(mTestNotificationChannel.getId()), anyBoolean())) 4738 .thenReturn(mTestNotificationChannel); 4739 4740 reset(mListeners); 4741 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel); 4742 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4743 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4744 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4745 } 4746 4747 @Test testDeleteChannelNotifyListener()4748 public void testDeleteChannelNotifyListener() throws Exception { 4749 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4750 .thenReturn(singletonList(mock(AssociationInfo.class))); 4751 mService.setPreferencesHelper(mPreferencesHelper); 4752 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4753 eq(mTestNotificationChannel.getId()), anyBoolean())) 4754 .thenReturn(mTestNotificationChannel); 4755 when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(), 4756 eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true); 4757 reset(mListeners); 4758 mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId()); 4759 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4760 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4761 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4762 } 4763 4764 @Test 4765 @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) testAppsCannotDeleteBundleChannel()4766 public void testAppsCannotDeleteBundleChannel() throws Exception { 4767 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4768 .thenReturn(singletonList(mock(AssociationInfo.class))); 4769 mService.setPreferencesHelper(mPreferencesHelper); 4770 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4771 eq(NEWS_ID), anyBoolean())) 4772 .thenReturn(mTestNotificationChannel); 4773 when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(), 4774 eq(NEWS_ID), anyInt(), anyBoolean())).thenReturn(true); 4775 reset(mListeners); 4776 mBinderService.deleteNotificationChannel(mPkg, NEWS_ID); 4777 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4778 eq(Process.myUserHandle()), any(), 4779 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4780 } 4781 4782 @Test testDeleteChannelOnlyDoExtraWorkIfExisted()4783 public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception { 4784 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4785 .thenReturn(singletonList(mock(AssociationInfo.class))); 4786 mService.setPreferencesHelper(mPreferencesHelper); 4787 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4788 eq(mTestNotificationChannel.getId()), anyBoolean())) 4789 .thenReturn(null); 4790 reset(mListeners); 4791 mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId()); 4792 verifyNoMoreInteractions(mListeners); 4793 verifyNoMoreInteractions(mHistoryManager); 4794 } 4795 4796 @Test testDeleteChannelGroupNotifyListener()4797 public void testDeleteChannelGroupNotifyListener() throws Exception { 4798 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4799 .thenReturn(singletonList(mock(AssociationInfo.class))); 4800 NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c"); 4801 mService.setPreferencesHelper(mPreferencesHelper); 4802 when(mPreferencesHelper.getNotificationChannelGroupWithChannels( 4803 eq(mPkg), anyInt(), eq(ncg.getId()), anyBoolean())) 4804 .thenReturn(ncg); 4805 reset(mListeners); 4806 mBinderService.deleteNotificationChannelGroup(mPkg, ncg.getId()); 4807 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 4808 eq(Process.myUserHandle()), eq(ncg), 4809 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4810 } 4811 4812 @Test testDeleteChannelGroupChecksForFgses()4813 public void testDeleteChannelGroupChecksForFgses() throws Exception { 4814 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4815 .thenReturn(singletonList(mock(AssociationInfo.class))); 4816 CountDownLatch latch = new CountDownLatch(2); 4817 mService.createNotificationChannelGroup( 4818 mPkg, mUid, new NotificationChannelGroup("group", "group"), true, false); 4819 new Thread(() -> { 4820 NotificationChannel notificationChannel = new NotificationChannel("id", "id", 4821 NotificationManager.IMPORTANCE_HIGH); 4822 notificationChannel.setGroup("group"); 4823 ParceledListSlice<NotificationChannel> pls = 4824 new ParceledListSlice(ImmutableList.of(notificationChannel)); 4825 try { 4826 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 4827 } catch (RemoteException e) { 4828 throw new RuntimeException(e); 4829 } 4830 latch.countDown(); 4831 }).start(); 4832 new Thread(() -> { 4833 try { 4834 synchronized (this) { 4835 wait(5000); 4836 } 4837 mService.createNotificationChannelGroup(mPkg, mUid, 4838 new NotificationChannelGroup("new", "new group"), true, false); 4839 NotificationChannel notificationChannel = 4840 new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH); 4841 notificationChannel.setGroup("new"); 4842 ParceledListSlice<NotificationChannel> pls = 4843 new ParceledListSlice(ImmutableList.of(notificationChannel)); 4844 try { 4845 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 4846 mBinderService.deleteNotificationChannelGroup(mPkg, "group"); 4847 } catch (RemoteException e) { 4848 throw new RuntimeException(e); 4849 } 4850 } catch (Exception e) { 4851 e.printStackTrace(); 4852 } 4853 latch.countDown(); 4854 }).start(); 4855 4856 latch.await(); 4857 verify(mAmi).hasForegroundServiceNotification(anyString(), anyInt(), anyString()); 4858 } 4859 setUpChannelsForConversationChannelTest()4860 private void setUpChannelsForConversationChannelTest() throws RemoteException { 4861 when(mPreferencesHelper.getNotificationChannel( 4862 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(false))) 4863 .thenReturn(mParentChannel); 4864 when(mPreferencesHelper.getConversationNotificationChannel( 4865 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(CONVERSATION_ID), eq(false), eq(false))) 4866 .thenReturn(mConversationChannel); 4867 when(mPackageManager.getPackageUid(mPkg, 0, mUserId)).thenReturn(mUid); 4868 } 4869 4870 @Test 4871 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_cdm_success()4872 public void createConversationChannelForPkgFromPrivilegedListener_cdm_success() throws Exception { 4873 // Set up cdm 4874 mService.setPreferencesHelper(mPreferencesHelper); 4875 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4876 .thenReturn(singletonList(mock(AssociationInfo.class))); 4877 4878 // Set up parent channel 4879 setUpChannelsForConversationChannelTest(); 4880 final NotificationChannel parentChannelCopy = mParentChannel.copy(); 4881 4882 NotificationChannel createdChannel = 4883 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 4884 null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID); 4885 4886 // Verify that a channel is created and a copied channel is returned. 4887 verify(mPreferencesHelper, times(1)).createNotificationChannel( 4888 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(), 4889 eq(mUid), anyBoolean()); 4890 assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel); 4891 assertThat(createdChannel).isEqualTo(mConversationChannel); 4892 4893 // Verify that the channel creation is not directly use the parent channel. 4894 verify(mPreferencesHelper, never()).createNotificationChannel( 4895 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(), 4896 anyInt(), anyBoolean()); 4897 4898 // Verify that the content of parent channel is not changed. 4899 assertThat(parentChannelCopy).isEqualTo(mParentChannel); 4900 } 4901 4902 @Test 4903 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess()4904 public void createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess() throws Exception { 4905 // Set up cdm without access 4906 mService.setPreferencesHelper(mPreferencesHelper); 4907 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4908 .thenReturn(emptyList()); 4909 4910 // Set up parent channel 4911 setUpChannelsForConversationChannelTest(); 4912 4913 try { 4914 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 4915 null, mPkg, mUser, "parentId", "conversationId"); 4916 fail("listeners that don't have a companion device shouldn't be able to call this"); 4917 } catch (SecurityException e) { 4918 // pass 4919 } 4920 4921 verify(mPreferencesHelper, never()).createNotificationChannel( 4922 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(), 4923 anyInt(), anyBoolean()); 4924 } 4925 4926 @Test 4927 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_assistant_success()4928 public void createConversationChannelForPkgFromPrivilegedListener_assistant_success() throws Exception { 4929 // Set up assistant 4930 mService.setPreferencesHelper(mPreferencesHelper); 4931 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4932 .thenReturn(emptyList()); 4933 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 4934 4935 // Set up parent channel 4936 setUpChannelsForConversationChannelTest(); 4937 final NotificationChannel parentChannelCopy = mParentChannel.copy(); 4938 4939 NotificationChannel createdChannel = 4940 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 4941 null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID); 4942 4943 // Verify that a channel is created and a copied channel is returned. 4944 verify(mPreferencesHelper, times(1)).createNotificationChannel( 4945 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(), 4946 eq(mUid), anyBoolean()); 4947 assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel); 4948 assertThat(createdChannel).isEqualTo(mConversationChannel); 4949 4950 // Verify that the channel creation is not directly use the parent channel. 4951 verify(mPreferencesHelper, never()).createNotificationChannel( 4952 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(), 4953 anyInt(), anyBoolean()); 4954 4955 // Verify that the content of parent channel is not changed. 4956 assertThat(parentChannelCopy).isEqualTo(mParentChannel); 4957 } 4958 4959 @Test 4960 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess()4961 public void createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess() throws Exception { 4962 // Set up assistant without access 4963 mService.setPreferencesHelper(mPreferencesHelper); 4964 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4965 .thenReturn(emptyList()); 4966 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); 4967 4968 // Set up parent channel 4969 setUpChannelsForConversationChannelTest(); 4970 4971 try { 4972 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 4973 null, mPkg, mUser, "parentId", "conversationId"); 4974 fail("listeners that don't have a companion device shouldn't be able to call this"); 4975 } catch (SecurityException e) { 4976 // pass 4977 } 4978 4979 verify(mPreferencesHelper, never()).createNotificationChannel( 4980 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(), 4981 anyInt(), anyBoolean()); 4982 } 4983 4984 @Test 4985 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_badUser()4986 public void createConversationChannelForPkgFromPrivilegedListener_badUser() throws Exception { 4987 // Set up bad user 4988 mService.setPreferencesHelper(mPreferencesHelper); 4989 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4990 .thenReturn(singletonList(mock(AssociationInfo.class))); 4991 mListener = mock(ManagedServices.ManagedServiceInfo.class); 4992 mListener.component = new ComponentName(mPkg, mPkg); 4993 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 4994 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 4995 4996 // Set up parent channel 4997 setUpChannelsForConversationChannelTest(); 4998 4999 try { 5000 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 5001 null, mPkg, mUser, "parentId", "conversationId"); 5002 fail("listener getting channels from a user they cannot see"); 5003 } catch (SecurityException e) { 5004 // pass 5005 } 5006 5007 verify(mPreferencesHelper, never()).createNotificationChannel( 5008 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(), 5009 anyInt(), anyBoolean()); 5010 } 5011 5012 @Test updateNotificationChannelFromPrivilegedListener_cdm_success()5013 public void updateNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { 5014 5015 mService.setPreferencesHelper(mPreferencesHelper); 5016 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5017 .thenReturn(singletonList(mock(AssociationInfo.class))); 5018 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5019 eq(mTestNotificationChannel.getId()), anyBoolean())) 5020 .thenReturn(mTestNotificationChannel); 5021 5022 mBinderService.updateNotificationChannelFromPrivilegedListener( 5023 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5024 5025 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 5026 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5027 5028 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5029 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5030 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5031 } 5032 5033 @Test updateNotificationChannelFromPrivilegedListener_cdm_noAccess()5034 public void updateNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { 5035 mService.setPreferencesHelper(mPreferencesHelper); 5036 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5037 .thenReturn(emptyList()); 5038 5039 try { 5040 mBinderService.updateNotificationChannelFromPrivilegedListener( 5041 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5042 fail("listeners that don't have a companion device shouldn't be able to call this"); 5043 } catch (SecurityException e) { 5044 // pass 5045 } 5046 5047 verify(mPreferencesHelper, never()).updateNotificationChannel( 5048 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5049 5050 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5051 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5052 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5053 } 5054 5055 @Test updateNotificationChannelFromPrivilegedListener_assistant_success()5056 public void updateNotificationChannelFromPrivilegedListener_assistant_success() throws Exception { 5057 mService.setPreferencesHelper(mPreferencesHelper); 5058 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5059 .thenReturn(emptyList()); 5060 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 5061 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5062 eq(mTestNotificationChannel.getId()), anyBoolean())) 5063 .thenReturn(mTestNotificationChannel); 5064 5065 mBinderService.updateNotificationChannelFromPrivilegedListener( 5066 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5067 5068 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 5069 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5070 5071 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5072 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5073 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5074 } 5075 5076 @Test updateNotificationChannelFromPrivilegedListener_assistant_noAccess()5077 public void updateNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception { 5078 mService.setPreferencesHelper(mPreferencesHelper); 5079 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5080 .thenReturn(emptyList()); 5081 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); 5082 5083 try { 5084 mBinderService.updateNotificationChannelFromPrivilegedListener( 5085 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5086 fail("listeners that don't have a companion device shouldn't be able to call this"); 5087 } catch (SecurityException e) { 5088 // pass 5089 } 5090 5091 verify(mPreferencesHelper, never()).updateNotificationChannel( 5092 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5093 5094 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5095 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5096 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5097 } 5098 5099 @Test updateNotificationChannelFromPrivilegedListener_badUser()5100 public void updateNotificationChannelFromPrivilegedListener_badUser() throws Exception { 5101 mService.setPreferencesHelper(mPreferencesHelper); 5102 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5103 .thenReturn(singletonList(mock(AssociationInfo.class))); 5104 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5105 mListener.component = new ComponentName(mPkg, mPkg); 5106 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5107 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5108 5109 try { 5110 mBinderService.updateNotificationChannelFromPrivilegedListener( 5111 null, mPkg, UserHandle.ALL, mTestNotificationChannel); 5112 fail("incorrectly allowed a change to a user listener cannot see"); 5113 } catch (SecurityException e) { 5114 // pass 5115 } 5116 5117 verify(mPreferencesHelper, never()).updateNotificationChannel( 5118 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5119 5120 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5121 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5122 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5123 } 5124 5125 @Test updateNotificationChannelFromPrivilegedListener_noSoundUriPermission()5126 public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission() 5127 throws Exception { 5128 mService.setPreferencesHelper(mPreferencesHelper); 5129 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5130 .thenReturn(singletonList(mock(AssociationInfo.class))); 5131 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5132 eq(mTestNotificationChannel.getId()), anyBoolean())) 5133 .thenReturn(mTestNotificationChannel); 5134 5135 final Uri soundUri = Uri.parse("content://media/test/sound/uri"); 5136 final NotificationChannel updatedNotificationChannel = new NotificationChannel( 5137 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 5138 updatedNotificationChannel.setSound(soundUri, 5139 updatedNotificationChannel.getAudioAttributes()); 5140 5141 doThrow(new SecurityException("no access")).when(mUgmInternal) 5142 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), 5143 anyInt(), eq(Process.myUserHandle().getIdentifier())); 5144 5145 assertThrows(SecurityException.class, 5146 () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, mPkg, 5147 Process.myUserHandle(), updatedNotificationChannel)); 5148 5149 verify(mPreferencesHelper, never()).updateNotificationChannel( 5150 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5151 5152 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5153 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5154 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5155 } 5156 5157 @Test updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()5158 public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound() 5159 throws Exception { 5160 mService.setPreferencesHelper(mPreferencesHelper); 5161 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5162 .thenReturn(singletonList(mock(AssociationInfo.class))); 5163 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5164 eq(mTestNotificationChannel.getId()), anyBoolean())) 5165 .thenReturn(mTestNotificationChannel); 5166 5167 final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 5168 final NotificationChannel updatedNotificationChannel = new NotificationChannel( 5169 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 5170 updatedNotificationChannel.setSound(soundUri, 5171 updatedNotificationChannel.getAudioAttributes()); 5172 5173 doThrow(new SecurityException("no access")).when(mUgmInternal) 5174 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), 5175 anyInt(), eq(Process.myUserHandle().getIdentifier())); 5176 5177 mBinderService.updateNotificationChannelFromPrivilegedListener( 5178 null, mPkg, Process.myUserHandle(), updatedNotificationChannel); 5179 5180 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 5181 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5182 5183 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5184 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5185 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5186 } 5187 5188 @Test 5189 public void updateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm()5190 updateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm() 5191 throws Exception { 5192 mService.setPreferencesHelper(mPreferencesHelper); 5193 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5194 .thenReturn(singletonList(mock(AssociationInfo.class))); 5195 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5196 eq(mTestNotificationChannel.getId()), anyBoolean())) 5197 .thenReturn(mTestNotificationChannel); 5198 5199 // Missing Uri permissions for the old channel sound 5200 final Uri oldSoundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 5201 doThrow(new SecurityException("no access")).when(mUgmInternal) 5202 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(oldSoundUri), 5203 anyInt(), eq(Process.myUserHandle().getIdentifier())); 5204 5205 // Has Uri permissions for the old channel sound 5206 final Uri newSoundUri = Uri.parse("content://media/test/sound/uri"); 5207 final NotificationChannel updatedNotificationChannel = new NotificationChannel( 5208 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 5209 updatedNotificationChannel.setSound(newSoundUri, 5210 updatedNotificationChannel.getAudioAttributes()); 5211 5212 mBinderService.updateNotificationChannelFromPrivilegedListener( 5213 null, mPkg, Process.myUserHandle(), updatedNotificationChannel); 5214 5215 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 5216 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5217 5218 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5219 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5220 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5221 } 5222 5223 @Test testGetNotificationChannelFromPrivilegedListener_cdm_success()5224 public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { 5225 mService.setPreferencesHelper(mPreferencesHelper); 5226 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5227 .thenReturn(singletonList(mock(AssociationInfo.class))); 5228 5229 mBinderService.getNotificationChannelsFromPrivilegedListener( 5230 null, mPkg, Process.myUserHandle()); 5231 5232 verify(mPreferencesHelper, times(1)).getNotificationChannels( 5233 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5234 } 5235 5236 @Test testGetNotificationChannelFromPrivilegedListener_cdm_noAccess()5237 public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { 5238 mService.setPreferencesHelper(mPreferencesHelper); 5239 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5240 .thenReturn(emptyList()); 5241 5242 try { 5243 mBinderService.getNotificationChannelsFromPrivilegedListener( 5244 null, mPkg, Process.myUserHandle()); 5245 fail("listeners that don't have a companion device shouldn't be able to call this"); 5246 } catch (SecurityException e) { 5247 // pass 5248 } 5249 5250 verify(mPreferencesHelper, never()).getNotificationChannels( 5251 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5252 } 5253 5254 @Test testGetNotificationChannelFromPrivilegedListener_assistant_success()5255 public void testGetNotificationChannelFromPrivilegedListener_assistant_success() 5256 throws Exception { 5257 mService.setPreferencesHelper(mPreferencesHelper); 5258 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5259 .thenReturn(emptyList()); 5260 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 5261 5262 mBinderService.getNotificationChannelsFromPrivilegedListener( 5263 null, mPkg, Process.myUserHandle()); 5264 5265 verify(mPreferencesHelper, times(1)).getNotificationChannels( 5266 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5267 } 5268 5269 @Test testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()5270 public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() 5271 throws Exception { 5272 mService.setPreferencesHelper(mPreferencesHelper); 5273 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5274 .thenReturn(emptyList()); 5275 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); 5276 5277 try { 5278 mBinderService.getNotificationChannelsFromPrivilegedListener( 5279 null, mPkg, Process.myUserHandle()); 5280 fail("listeners that don't have a companion device shouldn't be able to call this"); 5281 } catch (SecurityException e) { 5282 // pass 5283 } 5284 5285 verify(mPreferencesHelper, never()).getNotificationChannels( 5286 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5287 } 5288 5289 @Test testGetNotificationChannelFromPrivilegedListener_badUser()5290 public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { 5291 mService.setPreferencesHelper(mPreferencesHelper); 5292 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5293 .thenReturn(singletonList(mock(AssociationInfo.class))); 5294 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5295 mListener.component = new ComponentName(mPkg, mPkg); 5296 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5297 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5298 5299 try { 5300 mBinderService.getNotificationChannelsFromPrivilegedListener( 5301 null, mPkg, Process.myUserHandle()); 5302 fail("listener getting channels from a user they cannot see"); 5303 } catch (SecurityException e) { 5304 // pass 5305 } 5306 5307 verify(mPreferencesHelper, never()).getNotificationChannels( 5308 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5309 } 5310 5311 @Test testGetNotificationChannelGroupsFromPrivilegedListener_success()5312 public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception { 5313 mService.setPreferencesHelper(mPreferencesHelper); 5314 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5315 .thenReturn(singletonList(mock(AssociationInfo.class))); 5316 5317 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 5318 null, mPkg, Process.myUserHandle()); 5319 5320 verify(mPreferencesHelper, times(1)).getNotificationChannelGroups(anyString(), anyInt()); 5321 } 5322 5323 @Test testGetNotificationChannelGroupsFromPrivilegedListener_noAccess()5324 public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception { 5325 mService.setPreferencesHelper(mPreferencesHelper); 5326 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5327 .thenReturn(emptyList()); 5328 5329 try { 5330 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 5331 null, mPkg, Process.myUserHandle()); 5332 fail("listeners that don't have a companion device shouldn't be able to call this"); 5333 } catch (SecurityException e) { 5334 // pass 5335 } 5336 5337 verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt()); 5338 } 5339 5340 @Test testGetNotificationChannelGroupsFromPrivilegedListener_badUser()5341 public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { 5342 mService.setPreferencesHelper(mPreferencesHelper); 5343 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5344 .thenReturn(emptyList()); 5345 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5346 mListener.component = new ComponentName(mPkg, mPkg); 5347 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5348 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5349 try { 5350 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 5351 null, mPkg, Process.myUserHandle()); 5352 fail("listeners that don't have a companion device shouldn't be able to call this"); 5353 } catch (SecurityException e) { 5354 // pass 5355 } 5356 5357 verify(mPreferencesHelper, never()).getNotificationChannelGroups(anyString(), anyInt()); 5358 } 5359 5360 @Test testHasCompanionDevice_failure()5361 public void testHasCompanionDevice_failure() throws Exception { 5362 when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow( 5363 new IllegalArgumentException()); 5364 mService.hasCompanionDevice(mListener); 5365 } 5366 5367 @Test testHasCompanionDevice_noService()5368 public void testHasCompanionDevice_noService() { 5369 NotificationManagerService noManService = 5370 new TestableNotificationManagerService(mContext, mNotificationRecordLogger, 5371 mNotificationInstanceIdSequence); 5372 5373 assertFalse(noManService.hasCompanionDevice(mListener)); 5374 } 5375 5376 @Test testCrossUserSnooze()5377 public void testCrossUserSnooze() { 5378 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); 5379 mService.addNotification(r); 5380 NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); 5381 mService.addNotification(r2); 5382 5383 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5384 mListener.component = new ComponentName(mPkg, mPkg); 5385 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5386 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5387 5388 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5389 r.getKey(), 1000, null); 5390 5391 verify(mWorkerHandler, never()).post( 5392 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5393 } 5394 5395 @Test testSameUserSnooze()5396 public void testSameUserSnooze() { 5397 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); 5398 mService.addNotification(r); 5399 NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); 5400 mService.addNotification(r2); 5401 5402 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5403 mListener.component = new ComponentName(mPkg, mPkg); 5404 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5405 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5406 5407 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5408 r2.getKey(), 1000, null); 5409 5410 verify(mWorkerHandler).post( 5411 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5412 } 5413 5414 @Test snoozeNotificationInt_rapidSnooze_new()5415 public void snoozeNotificationInt_rapidSnooze_new() { 5416 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 5417 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5418 5419 // Create recent notification. 5420 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5421 System.currentTimeMillis()); 5422 mService.addNotification(nr1); 5423 5424 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5425 mListener.component = new ComponentName(mPkg, mPkg); 5426 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5427 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5428 5429 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5430 nr1.getKey(), 1000, null); 5431 5432 verify(mWorkerHandler).post( 5433 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5434 // Ensure cancel event is logged. 5435 verify(mAppOpsManager).noteOpNoThrow( 5436 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, 5437 null); 5438 } 5439 5440 @Test snoozeNotificationInt_rapidSnooze_old()5441 public void snoozeNotificationInt_rapidSnooze_old() { 5442 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 5443 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5444 5445 // Create old notification. 5446 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5447 System.currentTimeMillis() - 60000); 5448 mService.addNotification(nr1); 5449 5450 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5451 mListener.component = new ComponentName(mPkg, mPkg); 5452 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5453 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5454 5455 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5456 nr1.getKey(), 1000, null); 5457 5458 verify(mWorkerHandler).post( 5459 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5460 // Ensure cancel event is not logged. 5461 verify(mAppOpsManager, never()).noteOpNoThrow( 5462 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 5463 any(), any()); 5464 } 5465 5466 @Test snoozeNotificationInt_rapidSnooze_new_flagDisabled()5467 public void snoozeNotificationInt_rapidSnooze_new_flagDisabled() { 5468 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 5469 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5470 5471 // Create recent notification. 5472 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5473 System.currentTimeMillis()); 5474 mService.addNotification(nr1); 5475 5476 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5477 mListener.component = new ComponentName(mPkg, mPkg); 5478 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5479 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5480 5481 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5482 nr1.getKey(), 1000, null); 5483 5484 verify(mWorkerHandler).post( 5485 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5486 // Ensure cancel event is not logged. 5487 verify(mAppOpsManager, never()).noteOpNoThrow( 5488 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 5489 any(), any()); 5490 } 5491 5492 @Test snoozeNotificationInt_rapidSnooze_old_flagDisabled()5493 public void snoozeNotificationInt_rapidSnooze_old_flagDisabled() { 5494 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 5495 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5496 5497 // Create old notification. 5498 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5499 System.currentTimeMillis() - 60000); 5500 mService.addNotification(nr1); 5501 5502 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5503 mListener.component = new ComponentName(mPkg, mPkg); 5504 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5505 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5506 5507 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5508 nr1.getKey(), 1000, null); 5509 5510 verify(mWorkerHandler).post( 5511 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5512 // Ensure cancel event is not logged. 5513 verify(mAppOpsManager, never()).noteOpNoThrow( 5514 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 5515 any(), any()); 5516 } 5517 5518 @Test testSnoozeRunnable_tooManySnoozed_singleNotification()5519 public void testSnoozeRunnable_tooManySnoozed_singleNotification() { 5520 final NotificationRecord notification = generateNotificationRecord( 5521 mTestNotificationChannel, 1, null, true); 5522 mService.addNotification(notification); 5523 5524 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5525 when(mSnoozeHelper.canSnooze(1)).thenReturn(false); 5526 5527 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5528 mService.new SnoozeNotificationRunnable( 5529 notification.getKey(), 100, null); 5530 snoozeNotificationRunnable.run(); 5531 5532 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 5533 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 5534 } 5535 5536 @Test testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification()5537 public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() { 5538 final NotificationRecord notification = generateNotificationRecord( 5539 mTestNotificationChannel, 1, "group", true); 5540 final NotificationRecord notificationChild = generateNotificationRecord( 5541 mTestNotificationChannel, 1, "group", false); 5542 mService.addNotification(notification); 5543 mService.addNotification(notificationChild); 5544 5545 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5546 when(mSnoozeHelper.canSnooze(2)).thenReturn(false); 5547 5548 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5549 mService.new SnoozeNotificationRunnable( 5550 notificationChild.getKey(), 100, null); 5551 snoozeNotificationRunnable.run(); 5552 5553 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 5554 assertThat(mService.getNotificationRecordCount()).isEqualTo(2); 5555 } 5556 5557 @Test testSnoozeRunnable_tooManySnoozed_summaryNotification()5558 public void testSnoozeRunnable_tooManySnoozed_summaryNotification() { 5559 final NotificationRecord notification = generateNotificationRecord( 5560 mTestNotificationChannel, 1, "group", true); 5561 final NotificationRecord notificationChild = generateNotificationRecord( 5562 mTestNotificationChannel, 12, "group", false); 5563 final NotificationRecord notificationChild2 = generateNotificationRecord( 5564 mTestNotificationChannel, 13, "group", false); 5565 mService.addNotification(notification); 5566 mService.addNotification(notificationChild); 5567 mService.addNotification(notificationChild2); 5568 5569 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5570 when(mSnoozeHelper.canSnooze(3)).thenReturn(false); 5571 5572 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5573 mService.new SnoozeNotificationRunnable( 5574 notification.getKey(), 100, null); 5575 snoozeNotificationRunnable.run(); 5576 5577 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 5578 assertThat(mService.getNotificationRecordCount()).isEqualTo(3); 5579 } 5580 5581 @Test testSnoozeRunnable_reSnoozeASingleSnoozedNotification()5582 public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() { 5583 final NotificationRecord notification = generateNotificationRecord( 5584 mTestNotificationChannel, 1, null, true); 5585 mService.addNotification(notification); 5586 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 5587 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5588 5589 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5590 mService.new SnoozeNotificationRunnable( 5591 notification.getKey(), 100, null); 5592 snoozeNotificationRunnable.run(); 5593 snoozeNotificationRunnable.run(); 5594 5595 // snooze twice 5596 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 5597 } 5598 5599 @Test testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey()5600 public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() { 5601 final NotificationRecord notification = generateNotificationRecord( 5602 mTestNotificationChannel, 1, "group", true); 5603 mService.addNotification(notification); 5604 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 5605 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5606 5607 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5608 mService.new SnoozeNotificationRunnable( 5609 notification.getKey(), 100, null); 5610 snoozeNotificationRunnable.run(); 5611 snoozeNotificationRunnable.run(); 5612 5613 // snooze twice 5614 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 5615 } 5616 5617 @Test testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey()5618 public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception { 5619 final NotificationRecord notification = generateNotificationRecord( 5620 mTestNotificationChannel, 1, "group", true); 5621 final NotificationRecord notification2 = generateNotificationRecord( 5622 mTestNotificationChannel, 2, "group", true); 5623 mService.addNotification(notification); 5624 mService.addNotification(notification2); 5625 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 5626 when(mSnoozeHelper.getNotifications( 5627 anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>()); 5628 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5629 5630 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5631 mService.new SnoozeNotificationRunnable( 5632 notification.getKey(), 100, null); 5633 snoozeNotificationRunnable.run(); 5634 when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt())) 5635 .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2))); 5636 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = 5637 mService.new SnoozeNotificationRunnable( 5638 notification2.getKey(), 100, null); 5639 snoozeNotificationRunnable2.run(); 5640 5641 // snooze twice 5642 verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong()); 5643 } 5644 5645 @Test testSnoozeRunnable_snoozeNonGrouped()5646 public void testSnoozeRunnable_snoozeNonGrouped() throws Exception { 5647 final NotificationRecord nonGrouped = generateNotificationRecord( 5648 mTestNotificationChannel, 1, null, false); 5649 final NotificationRecord grouped = generateNotificationRecord( 5650 mTestNotificationChannel, 2, "group", false); 5651 mService.addNotification(grouped); 5652 mService.addNotification(nonGrouped); 5653 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5654 5655 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5656 mService.new SnoozeNotificationRunnable( 5657 nonGrouped.getKey(), 100, null); 5658 snoozeNotificationRunnable.run(); 5659 5660 // only snooze the one notification 5661 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5662 assertTrue(nonGrouped.getStats().hasSnoozed()); 5663 5664 assertEquals(2, mNotificationRecordLogger.numCalls()); 5665 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5666 mNotificationRecordLogger.event(0)); 5667 assertEquals( 5668 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5669 mNotificationRecordLogger.event(1)); 5670 } 5671 5672 @Test testSnoozeRunnable_snoozeSummary_withChildren()5673 public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception { 5674 final NotificationRecord parent = generateNotificationRecord( 5675 mTestNotificationChannel, 1, "group", true); 5676 final NotificationRecord child = generateNotificationRecord( 5677 mTestNotificationChannel, 2, "group", false); 5678 final NotificationRecord child2 = generateNotificationRecord( 5679 mTestNotificationChannel, 3, "group", false); 5680 mService.addNotification(parent); 5681 mService.addNotification(child); 5682 mService.addNotification(child2); 5683 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5684 5685 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5686 mService.new SnoozeNotificationRunnable( 5687 parent.getKey(), 100, null); 5688 snoozeNotificationRunnable.run(); 5689 5690 // snooze parent and children 5691 verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong()); 5692 } 5693 5694 @Test testSnoozeRunnable_snoozeGroupChild_fellowChildren()5695 public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception { 5696 final NotificationRecord parent = generateNotificationRecord( 5697 mTestNotificationChannel, 1, "group", true); 5698 final NotificationRecord child = generateNotificationRecord( 5699 mTestNotificationChannel, 2, "group", false); 5700 final NotificationRecord child2 = generateNotificationRecord( 5701 mTestNotificationChannel, 3, "group", false); 5702 mService.addNotification(parent); 5703 mService.addNotification(child); 5704 mService.addNotification(child2); 5705 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5706 5707 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5708 mService.new SnoozeNotificationRunnable( 5709 child2.getKey(), 100, null); 5710 snoozeNotificationRunnable.run(); 5711 5712 // only snooze the one child 5713 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5714 5715 assertEquals(2, mNotificationRecordLogger.numCalls()); 5716 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5717 mNotificationRecordLogger.event(0)); 5718 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 5719 .NOTIFICATION_CANCEL_SNOOZED, mNotificationRecordLogger.event(1)); 5720 } 5721 5722 @Test testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary()5723 public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception { 5724 final NotificationRecord parent = generateNotificationRecord( 5725 mTestNotificationChannel, 1, "group", true); 5726 assertTrue(parent.getSbn().getNotification().isGroupSummary()); 5727 final NotificationRecord child = generateNotificationRecord( 5728 mTestNotificationChannel, 2, "group", false); 5729 mService.addNotification(parent); 5730 mService.addNotification(child); 5731 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5732 5733 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5734 mService.new SnoozeNotificationRunnable( 5735 child.getKey(), 100, null); 5736 snoozeNotificationRunnable.run(); 5737 5738 // snooze child and summary 5739 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 5740 5741 assertEquals(4, mNotificationRecordLogger.numCalls()); 5742 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5743 mNotificationRecordLogger.event(0)); 5744 assertEquals( 5745 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5746 mNotificationRecordLogger.event(1)); 5747 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5748 mNotificationRecordLogger.event(2)); 5749 assertEquals( 5750 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5751 mNotificationRecordLogger.event(3)); 5752 } 5753 5754 @Test testSnoozeRunnable_snoozeGroupChild_noOthersInGroup()5755 public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception { 5756 final NotificationRecord child = generateNotificationRecord( 5757 mTestNotificationChannel, 2, "group", false); 5758 mService.addNotification(child); 5759 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5760 5761 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5762 mService.new SnoozeNotificationRunnable( 5763 child.getKey(), 100, null); 5764 snoozeNotificationRunnable.run(); 5765 5766 // snooze child only 5767 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5768 5769 assertEquals(2, mNotificationRecordLogger.numCalls()); 5770 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5771 mNotificationRecordLogger.event(0)); 5772 assertEquals( 5773 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5774 mNotificationRecordLogger.event(1)); 5775 } 5776 5777 @Test 5778 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed()5779 public void testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed() throws Exception { 5780 final NotificationRecord parent = generateNotificationRecord( 5781 mTestNotificationChannel, 1, GroupHelper.AUTOGROUP_KEY, true); 5782 final NotificationRecord child = generateNotificationRecord( 5783 mTestNotificationChannel, 2, GroupHelper.AUTOGROUP_KEY, false); 5784 mService.addNotification(parent); 5785 mService.addNotification(child); 5786 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5787 5788 // snooze child only 5789 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5790 mService.new SnoozeNotificationRunnable( 5791 child.getKey(), 100, null); 5792 snoozeNotificationRunnable.run(); 5793 5794 // only child should be snoozed 5795 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5796 5797 // both group summary and child should be cancelled 5798 assertNull(mService.getNotificationRecord(parent.getKey())); 5799 assertNull(mService.getNotificationRecord(child.getKey())); 5800 5801 assertEquals(4, mNotificationRecordLogger.numCalls()); 5802 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5803 mNotificationRecordLogger.event(0)); 5804 assertEquals( 5805 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5806 mNotificationRecordLogger.event(1)); 5807 } 5808 5809 @Test testPostGroupChild_unsnoozeParent()5810 public void testPostGroupChild_unsnoozeParent() throws Exception { 5811 final NotificationRecord child = generateNotificationRecord( 5812 mTestNotificationChannel, 2, "group", false); 5813 5814 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing", 5815 child.getSbn().getId(), child.getSbn().getNotification(), 5816 child.getSbn().getUserId()); 5817 waitForIdle(); 5818 5819 verify(mSnoozeHelper, times(1)).repostGroupSummary( 5820 anyString(), anyInt(), eq(child.getGroupKey())); 5821 } 5822 5823 @Test testPostNonGroup_noUnsnoozing()5824 public void testPostNonGroup_noUnsnoozing() throws Exception { 5825 final NotificationRecord record = generateNotificationRecord( 5826 mTestNotificationChannel, 2, null, false); 5827 5828 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing", 5829 record.getSbn().getId(), record.getSbn().getNotification(), 5830 record.getSbn().getUserId()); 5831 waitForIdle(); 5832 5833 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString()); 5834 } 5835 5836 @Test testPostGroupSummary_noUnsnoozing()5837 public void testPostGroupSummary_noUnsnoozing() throws Exception { 5838 final NotificationRecord parent = generateNotificationRecord( 5839 mTestNotificationChannel, 2, "group", true); 5840 5841 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostGroupSummary_noUnsnoozing", 5842 parent.getSbn().getId(), parent.getSbn().getNotification(), 5843 parent.getSbn().getUserId()); 5844 waitForIdle(); 5845 5846 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString()); 5847 } 5848 5849 @Test testSystemNotificationListenerCanUnsnooze()5850 public void testSystemNotificationListenerCanUnsnooze() throws Exception { 5851 final NotificationRecord nr = generateNotificationRecord( 5852 mTestNotificationChannel, 2, "group", false); 5853 5854 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 5855 "testSystemNotificationListenerCanUnsnooze", 5856 nr.getSbn().getId(), nr.getSbn().getNotification(), 5857 nr.getSbn().getUserId()); 5858 waitForIdle(); 5859 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5860 mService.new SnoozeNotificationRunnable( 5861 nr.getKey(), 100, null); 5862 snoozeNotificationRunnable.run(); 5863 5864 ManagedServices.ManagedServiceInfo listener = mListeners.new ManagedServiceInfo( 5865 null, new ComponentName(mPkg, "test_class"), mUid, true, null, 0, 234); 5866 listener.isSystem = true; 5867 when(mListeners.checkServiceTokenLocked(any())).thenReturn(listener); 5868 5869 mBinderService.unsnoozeNotificationFromSystemListener(null, nr.getKey()); 5870 waitForIdle(); 5871 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 5872 assertEquals(1, notifs.length); 5873 assertNotNull(notifs[0].getKey());//mService.getNotificationRecord(nr.getSbn().getKey())); 5874 } 5875 5876 @Test testSetListenerAccessForUser()5877 public void testSetListenerAccessForUser() throws Exception { 5878 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5879 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5880 mBinderService.setNotificationListenerAccessGrantedForUser( 5881 c, user.getIdentifier(), true, true); 5882 5883 5884 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 5885 verify(mListeners, times(1)).setPackageOrComponentEnabled( 5886 c.flattenToString(), user.getIdentifier(), true, true, true); 5887 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5888 c.flattenToString(), user.getIdentifier(), false, true, true); 5889 verify(mAssistants, never()).setPackageOrComponentEnabled( 5890 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5891 } 5892 5893 @Test testSetListenerAccessForUser_grantWithNameTooLong_throws()5894 public void testSetListenerAccessForUser_grantWithNameTooLong_throws() { 5895 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5896 ComponentName c = new ComponentName("com.example.package", 5897 com.google.common.base.Strings.repeat("Blah", 150)); 5898 5899 assertThrows(IllegalArgumentException.class, 5900 () -> mBinderService.setNotificationListenerAccessGrantedForUser( 5901 c, user.getIdentifier(), /* enabled= */ true, true)); 5902 } 5903 5904 @Test testSetListenerAccessForUser_revokeWithNameTooLong_okay()5905 public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception { 5906 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5907 ComponentName c = new ComponentName("com.example.package", 5908 com.google.common.base.Strings.repeat("Blah", 150)); 5909 5910 mBinderService.setNotificationListenerAccessGrantedForUser( 5911 c, user.getIdentifier(), /* enabled= */ false, true); 5912 5913 verify(mListeners).setPackageOrComponentEnabled( 5914 c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true); 5915 } 5916 5917 @Test testSetAssistantAccessForUser()5918 public void testSetAssistantAccessForUser() throws Exception { 5919 UserInfo ui = new UserInfo(); 5920 ui.id = mContext.getUserId() + 10; 5921 UserHandle user = UserHandle.of(ui.id); 5922 List<UserInfo> uis = new ArrayList<>(); 5923 uis.add(ui); 5924 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5925 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5926 5927 mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true); 5928 5929 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 5930 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5931 c.flattenToString(), user.getIdentifier(), true, true, true); 5932 verify(mAssistants).setUserSet(ui.id, true); 5933 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5934 c.flattenToString(), user.getIdentifier(), false, true); 5935 verify(mListeners, never()).setPackageOrComponentEnabled( 5936 any(), anyInt(), anyBoolean(), anyBoolean()); 5937 } 5938 5939 @Test testGetAssistantAllowedForUser()5940 public void testGetAssistantAllowedForUser() throws Exception { 5941 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5942 try { 5943 mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier()); 5944 } catch (IllegalStateException e) { 5945 if (!e.getMessage().contains("At most one NotificationAssistant")) { 5946 throw e; 5947 } 5948 } 5949 verify(mAssistants, times(1)).getAllowedComponents(user.getIdentifier()); 5950 } 5951 5952 @Test testGetAssistantAllowed()5953 public void testGetAssistantAllowed() throws Exception { 5954 try { 5955 mBinderService.getAllowedNotificationAssistant(); 5956 } catch (IllegalStateException e) { 5957 if (!e.getMessage().contains("At most one NotificationAssistant")) { 5958 throw e; 5959 } 5960 } 5961 verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId()); 5962 } 5963 5964 @Test testSetNASMigrationDoneAndResetDefault_enableNAS()5965 public void testSetNASMigrationDoneAndResetDefault_enableNAS() throws Exception { 5966 int userId = 10; 5967 setNASMigrationDone(false, userId); 5968 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 5969 5970 mBinderService.setNASMigrationDoneAndResetDefault(userId, true); 5971 5972 assertTrue(mService.isNASMigrationDone(userId)); 5973 verify(mAssistants, times(1)).resetDefaultFromConfig(); 5974 } 5975 5976 @Test testSetNASMigrationDoneAndResetDefault_disableNAS()5977 public void testSetNASMigrationDoneAndResetDefault_disableNAS() throws Exception { 5978 int userId = 10; 5979 setNASMigrationDone(false, userId); 5980 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 5981 5982 mBinderService.setNASMigrationDoneAndResetDefault(userId, false); 5983 5984 assertTrue(mService.isNASMigrationDone(userId)); 5985 verify(mAssistants, times(1)).clearDefaults(); 5986 } 5987 5988 @Test testSetNASMigrationDoneAndResetDefault_multiProfile()5989 public void testSetNASMigrationDoneAndResetDefault_multiProfile() throws Exception { 5990 int userId1 = 11; 5991 int userId2 = 12; //work profile 5992 setNASMigrationDone(false, userId1); 5993 setNASMigrationDone(false, userId2); 5994 setUsers(new int[]{userId1, userId2}); 5995 when(mUm.isManagedProfile(userId2)).thenReturn(true); 5996 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2}); 5997 5998 mBinderService.setNASMigrationDoneAndResetDefault(userId1, true); 5999 assertTrue(mService.isNASMigrationDone(userId1)); 6000 assertTrue(mService.isNASMigrationDone(userId2)); 6001 } 6002 6003 @Test testSetNASMigrationDoneAndResetDefault_multiUser()6004 public void testSetNASMigrationDoneAndResetDefault_multiUser() throws Exception { 6005 int userId1 = 11; 6006 int userId2 = 12; 6007 setNASMigrationDone(false, userId1); 6008 setNASMigrationDone(false, userId2); 6009 setUsers(new int[]{userId1, userId2}); 6010 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1}); 6011 when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2}); 6012 6013 mBinderService.setNASMigrationDoneAndResetDefault(userId1, true); 6014 assertTrue(mService.isNASMigrationDone(userId1)); 6015 assertFalse(mService.isNASMigrationDone(userId2)); 6016 } 6017 6018 @Test testSetDndAccessForUser()6019 public void testSetDndAccessForUser() throws Exception { 6020 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 6021 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6022 mBinderService.setNotificationPolicyAccessGrantedForUser( 6023 c.getPackageName(), user.getIdentifier(), true); 6024 6025 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 6026 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6027 c.getPackageName(), user.getIdentifier(), true, true); 6028 verify(mAssistants, never()).setPackageOrComponentEnabled( 6029 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6030 verify(mListeners, never()).setPackageOrComponentEnabled( 6031 any(), anyInt(), anyBoolean(), anyBoolean()); 6032 } 6033 6034 @Test testSetListenerAccess()6035 public void testSetListenerAccess() throws Exception { 6036 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6037 mBinderService.setNotificationListenerAccessGranted(c, true, true); 6038 6039 verify(mListeners, times(1)).setPackageOrComponentEnabled( 6040 c.flattenToString(), mContext.getUserId(), true, true, true); 6041 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6042 c.flattenToString(), mContext.getUserId(), false, true, true); 6043 verify(mAssistants, never()).setPackageOrComponentEnabled( 6044 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6045 } 6046 6047 @Test testSetAssistantAccess()6048 public void testSetAssistantAccess() throws Exception { 6049 List<UserInfo> uis = new ArrayList<>(); 6050 UserInfo ui = new UserInfo(); 6051 ui.id = mContext.getUserId(); 6052 uis.add(ui); 6053 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6054 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6055 6056 mBinderService.setNotificationAssistantAccessGranted(c, true); 6057 6058 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6059 c.flattenToString(), ui.id, true, true, true); 6060 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6061 c.flattenToString(), ui.id, false, true); 6062 verify(mListeners, never()).setPackageOrComponentEnabled( 6063 any(), anyInt(), anyBoolean(), anyBoolean()); 6064 } 6065 6066 @Test testSetAssistantAccess_multiProfile()6067 public void testSetAssistantAccess_multiProfile() throws Exception { 6068 List<UserInfo> uis = new ArrayList<>(); 6069 UserInfo ui = new UserInfo(); 6070 ui.id = mContext.getUserId(); 6071 uis.add(ui); 6072 UserInfo ui10 = new UserInfo(); 6073 ui10.id = mContext.getUserId() + 10; 6074 uis.add(ui10); 6075 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6076 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6077 6078 mBinderService.setNotificationAssistantAccessGranted(c, true); 6079 6080 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6081 c.flattenToString(), ui.id, true, true, true); 6082 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6083 c.flattenToString(), ui10.id, true, true, true); 6084 6085 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6086 c.flattenToString(), ui.id, false, true); 6087 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6088 c.flattenToString(), ui10.id, false, true); 6089 verify(mListeners, never()).setPackageOrComponentEnabled( 6090 any(), anyInt(), anyBoolean(), anyBoolean()); 6091 } 6092 6093 @Test testSetAssistantAccess_nullWithAllowedAssistant()6094 public void testSetAssistantAccess_nullWithAllowedAssistant() throws Exception { 6095 ArrayList<ComponentName> componentList = new ArrayList<>(); 6096 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6097 componentList.add(c); 6098 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 6099 List<UserInfo> uis = new ArrayList<>(); 6100 UserInfo ui = new UserInfo(); 6101 ui.id = mContext.getUserId(); 6102 uis.add(ui); 6103 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6104 6105 mBinderService.setNotificationAssistantAccessGranted(null, true); 6106 6107 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6108 c.flattenToString(), ui.id, true, false, true); 6109 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6110 c.flattenToString(), ui.id, false, false); 6111 verify(mListeners, never()).setPackageOrComponentEnabled( 6112 any(), anyInt(), anyBoolean(), anyBoolean()); 6113 } 6114 6115 @Test testSetAssistantAccessForUser_nullWithAllowedAssistant()6116 public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception { 6117 List<UserInfo> uis = new ArrayList<>(); 6118 UserInfo ui = new UserInfo(); 6119 ui.id = mContext.getUserId() + 10; 6120 uis.add(ui); 6121 UserHandle user = ui.getUserHandle(); 6122 ArrayList<ComponentName> componentList = new ArrayList<>(); 6123 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6124 componentList.add(c); 6125 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 6126 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6127 6128 mBinderService.setNotificationAssistantAccessGrantedForUser( 6129 null, user.getIdentifier(), true); 6130 6131 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6132 c.flattenToString(), user.getIdentifier(), true, false, true); 6133 verify(mAssistants).setUserSet(ui.id, true); 6134 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6135 c.flattenToString(), user.getIdentifier(), false, false); 6136 verify(mListeners, never()).setPackageOrComponentEnabled( 6137 any(), anyInt(), anyBoolean(), anyBoolean()); 6138 } 6139 6140 @Test testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()6141 public void testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant() 6142 throws Exception { 6143 List<UserInfo> uis = new ArrayList<>(); 6144 UserInfo ui = new UserInfo(); 6145 ui.id = mContext.getUserId(); 6146 uis.add(ui); 6147 UserInfo ui10 = new UserInfo(); 6148 ui10.id = mContext.getUserId() + 10; 6149 uis.add(ui10); 6150 UserHandle user = ui.getUserHandle(); 6151 ArrayList<ComponentName> componentList = new ArrayList<>(); 6152 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6153 componentList.add(c); 6154 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 6155 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6156 6157 mBinderService.setNotificationAssistantAccessGrantedForUser( 6158 null, user.getIdentifier(), true); 6159 6160 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6161 c.flattenToString(), user.getIdentifier(), true, false, true); 6162 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6163 c.flattenToString(), ui10.id, true, false, true); 6164 verify(mAssistants).setUserSet(ui.id, true); 6165 verify(mAssistants).setUserSet(ui10.id, true); 6166 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6167 c.flattenToString(), user.getIdentifier(), false, false); 6168 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6169 c.flattenToString(), ui10.id, false, false); 6170 verify(mListeners, never()).setPackageOrComponentEnabled( 6171 any(), anyInt(), anyBoolean(), anyBoolean()); 6172 } 6173 6174 @Test testSetDndAccess()6175 public void testSetDndAccess() throws Exception { 6176 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6177 6178 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 6179 6180 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6181 c.getPackageName(), mContext.getUserId(), true, true); 6182 verify(mAssistants, never()).setPackageOrComponentEnabled( 6183 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6184 verify(mListeners, never()).setPackageOrComponentEnabled( 6185 any(), anyInt(), anyBoolean(), anyBoolean()); 6186 } 6187 6188 @Test testSetListenerAccess_onLowRam()6189 public void testSetListenerAccess_onLowRam() throws Exception { 6190 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6191 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6192 mBinderService.setNotificationListenerAccessGranted(c, true, true); 6193 6194 verify(mListeners).setPackageOrComponentEnabled( 6195 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6196 verify(mConditionProviders).setPackageOrComponentEnabled( 6197 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6198 verify(mAssistants).migrateToXml(); 6199 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 6200 } 6201 6202 @Test testSetAssistantAccess_onLowRam()6203 public void testSetAssistantAccess_onLowRam() throws Exception { 6204 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6205 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6206 List<UserInfo> uis = new ArrayList<>(); 6207 UserInfo ui = new UserInfo(); 6208 ui.id = mContext.getUserId(); 6209 uis.add(ui); 6210 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6211 6212 mBinderService.setNotificationAssistantAccessGranted(c, true); 6213 6214 verify(mListeners).migrateToXml(); 6215 verify(mConditionProviders).setPackageOrComponentEnabled( 6216 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6217 verify(mAssistants).migrateToXml(); 6218 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 6219 } 6220 6221 @Test testSetDndAccess_onLowRam()6222 public void testSetDndAccess_onLowRam() throws Exception { 6223 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6224 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6225 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 6226 6227 verify(mListeners).migrateToXml(); 6228 verify(mConditionProviders).setPackageOrComponentEnabled( 6229 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6230 verify(mAssistants).migrateToXml(); 6231 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 6232 } 6233 6234 @Test testSetListenerAccess_doesNothingOnLowRam_exceptWatch()6235 public void testSetListenerAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 6236 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 6237 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6238 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6239 6240 mBinderService.setNotificationListenerAccessGranted(c, true, true); 6241 6242 verify(mListeners, times(1)).setPackageOrComponentEnabled( 6243 c.flattenToString(), mContext.getUserId(), true, true, true); 6244 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6245 c.flattenToString(), mContext.getUserId(), false, true, true); 6246 verify(mAssistants, never()).setPackageOrComponentEnabled( 6247 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6248 } 6249 6250 @Test testSetAssistantAccess_doesNothingOnLowRam_exceptWatch()6251 public void testSetAssistantAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 6252 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 6253 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6254 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6255 List<UserInfo> uis = new ArrayList<>(); 6256 UserInfo ui = new UserInfo(); 6257 ui.id = mContext.getUserId(); 6258 uis.add(ui); 6259 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6260 6261 mBinderService.setNotificationAssistantAccessGranted(c, true); 6262 6263 verify(mListeners, never()).setPackageOrComponentEnabled( 6264 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6265 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6266 c.flattenToString(), ui.id, false, true); 6267 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6268 c.flattenToString(), ui.id, true, true, true); 6269 } 6270 6271 @Test testSetDndAccess_doesNothingOnLowRam_exceptWatch()6272 public void testSetDndAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 6273 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 6274 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6275 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6276 6277 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 6278 6279 verify(mListeners, never()).setPackageOrComponentEnabled( 6280 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6281 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6282 c.getPackageName(), mContext.getUserId(), true, true); 6283 verify(mAssistants, never()).setPackageOrComponentEnabled( 6284 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6285 } 6286 6287 @Test testOnlyAutogroupIfNeeded_newNotification_ghUpdate()6288 public void testOnlyAutogroupIfNeeded_newNotification_ghUpdate() { 6289 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 6290 mService.addEnqueuedNotification(r); 6291 NotificationManagerService.PostNotificationRunnable runnable = 6292 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 6293 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6294 runnable.run(); 6295 waitForIdle(); 6296 6297 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 6298 } 6299 6300 @Test testOnlyAutogroupIfNeeded_groupChanged_ghUpdate()6301 public void testOnlyAutogroupIfNeeded_groupChanged_ghUpdate() { 6302 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 6303 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", "group", false); 6304 mService.addNotification(r); 6305 6306 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 6307 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", null, false); 6308 mService.addEnqueuedNotification(update); 6309 NotificationManagerService.PostNotificationRunnable runnable = 6310 mService.new PostNotificationRunnable(update.getKey(), 6311 update.getSbn().getPackageName(), update.getUid(), 6312 mPostNotificationTrackerFactory.newTracker(null)); 6313 runnable.run(); 6314 waitForIdle(); 6315 6316 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 6317 } 6318 6319 @Test testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate()6320 public void testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate() { 6321 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 6322 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", "group", false); 6323 mService.addNotification(r); 6324 6325 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 6326 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", null, false); 6327 update.getNotification().flags = FLAG_AUTO_CANCEL; 6328 mService.addEnqueuedNotification(update); 6329 NotificationManagerService.PostNotificationRunnable runnable = 6330 mService.new PostNotificationRunnable(update.getKey(), 6331 update.getSbn().getPackageName(), update.getUid(), 6332 mPostNotificationTrackerFactory.newTracker(null)); 6333 runnable.run(); 6334 waitForIdle(); 6335 6336 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 6337 } 6338 6339 @Test testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate()6340 public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() { 6341 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 6342 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); 6343 mService.addNotification(r); 6344 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 6345 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); 6346 update.getNotification().color = Color.BLACK; 6347 mService.addEnqueuedNotification(update); 6348 6349 NotificationManagerService.PostNotificationRunnable runnable = 6350 mService.new PostNotificationRunnable(update.getKey(), 6351 update.getSbn().getPackageName(), 6352 update.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6353 runnable.run(); 6354 waitForIdle(); 6355 6356 verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean()); 6357 } 6358 6359 @Test testDontAutogroupIfCritical()6360 public void testDontAutogroupIfCritical() throws Exception { 6361 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 6362 r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW); 6363 mService.addEnqueuedNotification(r); 6364 NotificationManagerService.PostNotificationRunnable runnable = 6365 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 6366 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6367 runnable.run(); 6368 6369 r = generateNotificationRecord(mTestNotificationChannel, 1, null, false); 6370 r.setCriticality(CriticalNotificationExtractor.CRITICAL); 6371 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 6372 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6373 mService.addEnqueuedNotification(r); 6374 6375 runnable.run(); 6376 waitForIdle(); 6377 6378 verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean()); 6379 } 6380 6381 @Test testNoNotificationDuringSetupPermission()6382 public void testNoNotificationDuringSetupPermission() throws Exception { 6383 mContext.getTestablePermissions().setPermission( 6384 android.Manifest.permission.NOTIFICATION_DURING_SETUP, PERMISSION_GRANTED); 6385 Bundle extras = new Bundle(); 6386 extras.putBoolean(EXTRA_ALLOW_DURING_SETUP, true); 6387 Notification.Builder nb = new Notification.Builder(mContext, 6388 mTestNotificationChannel.getId()) 6389 .setContentTitle("foo") 6390 .addExtras(extras) 6391 .setSmallIcon(android.R.drawable.sym_def_app_icon); 6392 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 6393 "testNoNotificationDuringSetupPermission", mUid, 0, 6394 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 6395 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6396 6397 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 6398 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 6399 waitForIdle(); 6400 6401 NotificationRecord posted = mService.findNotificationLocked( 6402 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 6403 6404 assertTrue(posted.getNotification().extras.containsKey(EXTRA_ALLOW_DURING_SETUP)); 6405 } 6406 6407 @Test testNoFakeColorizedPermission()6408 public void testNoFakeColorizedPermission() throws Exception { 6409 mContext.getTestablePermissions().setPermission( 6410 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_DENIED); 6411 Notification.Builder nb = new Notification.Builder(mContext, 6412 mTestNotificationChannel.getId()) 6413 .setContentTitle("foo") 6414 .setColorized(true).setColor(Color.WHITE) 6415 .setFlag(FLAG_CAN_COLORIZE, true) 6416 .setSmallIcon(android.R.drawable.sym_def_app_icon); 6417 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 6418 "testNoFakeColorizedPermission", mUid, 0, 6419 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 6420 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6421 6422 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 6423 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 6424 waitForIdle(); 6425 6426 NotificationRecord posted = mService.findNotificationLocked( 6427 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 6428 6429 assertFalse(posted.getNotification().isColorized()); 6430 } 6431 6432 @Test 6433 @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION}) testMediaStyle_enforceNoClearFlagEnabled()6434 public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException { 6435 Notification.MediaStyle style = new Notification.MediaStyle(); 6436 Notification.Builder nb = new Notification.Builder(mContext, 6437 mTestNotificationChannel.getId()) 6438 .setStyle(style); 6439 6440 NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag"); 6441 6442 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR); 6443 } 6444 6445 @Test 6446 @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION}) testCustomMediaStyle_enforceNoClearFlagEnabled()6447 public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException { 6448 Notification.DecoratedMediaCustomViewStyle style = 6449 new Notification.DecoratedMediaCustomViewStyle(); 6450 Notification.Builder nb = new Notification.Builder(mContext, 6451 mTestNotificationChannel.getId()) 6452 .setStyle(style); 6453 6454 NotificationRecord posted = createAndPostNotification(nb, 6455 "testCustomMediaStyleSetNoClearFlag"); 6456 6457 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR); 6458 } 6459 6460 @Test 6461 @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION) testMediaStyle_enforceNoClearFlagDisabled()6462 public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException { 6463 Notification.MediaStyle style = new Notification.MediaStyle(); 6464 Notification.Builder nb = new Notification.Builder(mContext, 6465 mTestNotificationChannel.getId()) 6466 .setStyle(style); 6467 6468 NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag"); 6469 6470 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR); 6471 } 6472 6473 @Test 6474 @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION) testCustomMediaStyle_enforceNoClearFlagDisabled()6475 public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException { 6476 Notification.DecoratedMediaCustomViewStyle style = 6477 new Notification.DecoratedMediaCustomViewStyle(); 6478 Notification.Builder nb = new Notification.Builder(mContext, 6479 mTestNotificationChannel.getId()) 6480 .setStyle(style); 6481 6482 NotificationRecord posted = createAndPostNotification(nb, 6483 "testCustomMediaStyleSetNoClearFlag"); 6484 6485 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR); 6486 } 6487 6488 @Test testMediaStyleRemote_hasPermission()6489 public void testMediaStyleRemote_hasPermission() throws RemoteException { 6490 String deviceName = "device"; 6491 mContext.getTestablePermissions().setPermission( 6492 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_GRANTED); 6493 Notification.MediaStyle style = new Notification.MediaStyle(); 6494 style.setRemotePlaybackInfo(deviceName, 0, null); 6495 Notification.Builder nb = new Notification.Builder(mContext, 6496 mTestNotificationChannel.getId()) 6497 .setStyle(style); 6498 6499 NotificationRecord posted = createAndPostNotification(nb, 6500 "testMediaStyleRemoteHasPermission"); 6501 Bundle extras = posted.getNotification().extras; 6502 6503 assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6504 assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6505 } 6506 6507 @Test testMediaStyleRemote_noPermission()6508 public void testMediaStyleRemote_noPermission() throws RemoteException { 6509 String deviceName = "device"; 6510 mContext.getTestablePermissions().setPermission( 6511 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_DENIED); 6512 Notification.MediaStyle style = new Notification.MediaStyle(); 6513 style.setRemotePlaybackInfo(deviceName, 0, null); 6514 Notification.Builder nb = new Notification.Builder(mContext, 6515 mTestNotificationChannel.getId()) 6516 .setStyle(style); 6517 6518 NotificationRecord posted = createAndPostNotification(nb, 6519 "testMediaStyleRemoteNoPermission"); 6520 6521 assertFalse(posted.getNotification().extras 6522 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6523 assertFalse(posted.getNotification().extras 6524 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); 6525 assertFalse(posted.getNotification().extras 6526 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); 6527 } 6528 6529 @Test testCustomMediaStyleRemote_noPermission()6530 public void testCustomMediaStyleRemote_noPermission() throws RemoteException { 6531 String deviceName = "device"; 6532 when(mPackageManager.checkPermission( 6533 eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt())) 6534 .thenReturn(PERMISSION_DENIED); 6535 Notification.DecoratedMediaCustomViewStyle style = 6536 new Notification.DecoratedMediaCustomViewStyle(); 6537 style.setRemotePlaybackInfo(deviceName, 0, null); 6538 Notification.Builder nb = new Notification.Builder(mContext, 6539 mTestNotificationChannel.getId()) 6540 .setStyle(style); 6541 6542 NotificationRecord posted = createAndPostNotification(nb, 6543 "testCustomMediaStyleRemoteNoPermission"); 6544 6545 assertFalse(posted.getNotification().extras 6546 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6547 assertFalse(posted.getNotification().extras 6548 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); 6549 assertFalse(posted.getNotification().extras 6550 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); 6551 } 6552 6553 @Test testSubstituteAppName_hasPermission()6554 public void testSubstituteAppName_hasPermission() throws RemoteException { 6555 String subName = "Substitute Name"; 6556 mContext.getTestablePermissions().setPermission( 6557 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_GRANTED); 6558 Bundle extras = new Bundle(); 6559 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName); 6560 Notification.Builder nb = new Notification.Builder(mContext, 6561 mTestNotificationChannel.getId()) 6562 .addExtras(extras); 6563 6564 NotificationRecord posted = createAndPostNotification(nb, 6565 "testSubstituteAppNameHasPermission"); 6566 6567 assertTrue(posted.getNotification().extras 6568 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)); 6569 assertEquals(posted.getNotification().extras 6570 .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName); 6571 } 6572 6573 @Test testSubstituteAppName_noPermission()6574 public void testSubstituteAppName_noPermission() throws RemoteException { 6575 mContext.getTestablePermissions().setPermission( 6576 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_DENIED); 6577 Bundle extras = new Bundle(); 6578 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name"); 6579 Notification.Builder nb = new Notification.Builder(mContext, 6580 mTestNotificationChannel.getId()) 6581 .addExtras(extras); 6582 6583 NotificationRecord posted = createAndPostNotification(nb, 6584 "testSubstituteAppNameNoPermission"); 6585 6586 assertFalse(posted.getNotification().extras 6587 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)); 6588 } 6589 6590 @Test testGetNotificationCountLocked()6591 public void testGetNotificationCountLocked() { 6592 String sampleTagToExclude = null; 6593 int sampleIdToExclude = 0; 6594 for (int i = 0; i < 20; i++) { 6595 NotificationRecord r = 6596 generateNotificationRecord(mTestNotificationChannel, i, null, false); 6597 mService.addEnqueuedNotification(r); 6598 6599 } 6600 for (int i = 0; i < 20; i++) { 6601 NotificationRecord r = 6602 generateNotificationRecord(mTestNotificationChannel, i, null, false); 6603 mService.addNotification(r); 6604 sampleTagToExclude = r.getSbn().getTag(); 6605 sampleIdToExclude = i; 6606 } 6607 6608 // another package 6609 Notification n = 6610 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 6611 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6612 .build(); 6613 6614 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0, 6615 n, UserHandle.getUserHandleForUid(mUid), null, 0); 6616 NotificationRecord otherPackage = 6617 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6618 mService.addEnqueuedNotification(otherPackage); 6619 mService.addNotification(otherPackage); 6620 6621 // Same notifications are enqueued as posted, everything counts b/c id and tag don't match 6622 // anything that's currently enqueued or posted 6623 int userId = mUserId; 6624 assertEquals(40, 6625 mService.getNotificationCount(mPkg, userId, 0, null)); 6626 assertEquals(40, 6627 mService.getNotificationCount(mPkg, userId, 0, "tag2")); 6628 6629 // return all for package "a" - "banana" tag isn't used 6630 assertEquals(2, 6631 mService.getNotificationCount("a", userId, 0, "banana")); 6632 6633 // exclude a known notification - it's excluded from only the posted list, not enqueued 6634 assertEquals(39, mService.getNotificationCount( 6635 mPkg, userId, sampleIdToExclude, sampleTagToExclude)); 6636 } 6637 6638 @Test testAddAutogroup_requestsSort()6639 public void testAddAutogroup_requestsSort() throws Exception { 6640 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6641 mService.addNotification(r); 6642 mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true); 6643 6644 verify(mRankingHandler, times(1)).requestSort(); 6645 } 6646 6647 @Test testRemoveAutogroup_requestsSort()6648 public void testRemoveAutogroup_requestsSort() throws Exception { 6649 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6650 r.setOverrideGroupKey("TEST"); 6651 mService.addNotification(r); 6652 mService.removeAutogroupKeyLocked(r.getKey()); 6653 6654 verify(mRankingHandler, times(1)).requestSort(); 6655 } 6656 6657 @Test testReaddAutogroup_noSort()6658 public void testReaddAutogroup_noSort() throws Exception { 6659 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6660 r.setOverrideGroupKey("TEST"); 6661 mService.addNotification(r); 6662 mService.addAutogroupKeyLocked(r.getKey(), "grpName", true); 6663 6664 verify(mRankingHandler, never()).requestSort(); 6665 } 6666 6667 @Test 6668 @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST) testAutogroupSuppressSort_noSort()6669 public void testAutogroupSuppressSort_noSort() throws Exception { 6670 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6671 mService.addNotification(r); 6672 mService.addAutogroupKeyLocked(r.getKey(), "grpName", false); 6673 6674 verify(mRankingHandler, never()).requestSort(); 6675 } 6676 6677 @Test 6678 @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST) testAutogroupOnPost_skipManualSort()6679 public void testAutogroupOnPost_skipManualSort() throws Exception { 6680 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6681 mService.addNotification(r); 6682 verify(mRankingHandler, never()).requestSort(); 6683 } 6684 6685 @Test testHandleRankingSort_sendsUpdateOnSignalExtractorChange()6686 public void testHandleRankingSort_sendsUpdateOnSignalExtractorChange() throws Exception { 6687 mService.setPreferencesHelper(mPreferencesHelper); 6688 NotificationManagerService.WorkerHandler handler = mock( 6689 NotificationManagerService.WorkerHandler.class); 6690 mService.setHandler(handler); 6691 6692 Map<String, Answer> answers = getSignalExtractorSideEffects(); 6693 for (String message : answers.keySet()) { 6694 mService.clearNotifications(); 6695 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6696 mService.addNotification(r); 6697 6698 doAnswer(answers.get(message)).when(mRankingHelper).extractSignals(r); 6699 6700 mService.handleRankingSort(); 6701 } 6702 verify(handler, times(answers.size())).scheduleSendRankingUpdate(); 6703 } 6704 6705 @Test testHandleRankingSort_noUpdateWhenNoSignalChange()6706 public void testHandleRankingSort_noUpdateWhenNoSignalChange() throws Exception { 6707 mService.setRankingHelper(mRankingHelper); 6708 NotificationManagerService.WorkerHandler handler = mock( 6709 NotificationManagerService.WorkerHandler.class); 6710 mService.setHandler(handler); 6711 6712 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6713 mService.addNotification(r); 6714 6715 mService.handleRankingSort(); 6716 verify(handler, never()).scheduleSendRankingUpdate(); 6717 } 6718 6719 @Test testReadPolicyXml_readApprovedServicesFromXml()6720 public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception { 6721 final String upgradeXml = "<notification-policy version=\"1\">" 6722 + "<ranking></ranking>" 6723 + "<enabled_listeners>" 6724 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 6725 + "</enabled_listeners>" 6726 + "<enabled_assistants>" 6727 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 6728 + "</enabled_assistants>" 6729 + "<dnd_apps>" 6730 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 6731 + "</dnd_apps>" 6732 + "</notification-policy>"; 6733 mService.readPolicyXml( 6734 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), 6735 false, 6736 UserHandle.USER_ALL, null); 6737 verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 6738 verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 6739 verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 6740 6741 // numbers are inflated for setup 6742 verify(mListeners, times(1)).migrateToXml(); 6743 verify(mConditionProviders, times(1)).migrateToXml(); 6744 verify(mAssistants, times(1)).migrateToXml(); 6745 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 6746 } 6747 6748 @Test testReadPolicyXml_readSnoozedNotificationsFromXml()6749 public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception { 6750 final String upgradeXml = "<notification-policy version=\"1\">" 6751 + "<snoozed-notifications>></snoozed-notifications>" 6752 + "</notification-policy>"; 6753 mService.readPolicyXml( 6754 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), 6755 false, 6756 UserHandle.USER_ALL, null); 6757 verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong()); 6758 } 6759 6760 @Test testReadPolicyXml_readApprovedServicesFromSettings()6761 public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception { 6762 final String preupgradeXml = "<notification-policy version=\"1\">" 6763 + "<ranking></ranking>" 6764 + "</notification-policy>"; 6765 mService.readPolicyXml( 6766 new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), 6767 false, 6768 UserHandle.USER_ALL, null); 6769 verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt()); 6770 verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt()); 6771 verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt()); 6772 6773 // numbers are inflated for setup 6774 verify(mListeners, times(2)).migrateToXml(); 6775 verify(mConditionProviders, times(2)).migrateToXml(); 6776 verify(mAssistants, times(2)).migrateToXml(); 6777 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 6778 } 6779 6780 @Test testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser()6781 public void testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser() throws Exception { 6782 final String policyXml = "<notification-policy version=\"1\">" 6783 + "<ranking></ranking>" 6784 + "<enabled_listeners>" 6785 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6786 + "</enabled_listeners>" 6787 + "<enabled_assistants>" 6788 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6789 + "</enabled_assistants>" 6790 + "<dnd_apps>" 6791 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6792 + "</dnd_apps>" 6793 + "</notification-policy>"; 6794 UserInfo ui = new UserInfo(10, "Clone", UserInfo.FLAG_PROFILE); 6795 ui.userType = USER_TYPE_PROFILE_CLONE; 6796 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6797 mService.readPolicyXml( 6798 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6799 true, 6800 10, null); 6801 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 6802 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 6803 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 6804 } 6805 6806 @Test testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser()6807 public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception { 6808 final String policyXml = "<notification-policy version=\"1\">" 6809 + "<ranking></ranking>" 6810 + "<enabled_listeners>" 6811 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6812 + "</enabled_listeners>" 6813 + "<enabled_assistants>" 6814 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6815 + "</enabled_assistants>" 6816 + "<dnd_apps>" 6817 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6818 + "</dnd_apps>" 6819 + "</notification-policy>"; 6820 UserInfo ui = new UserInfo(10, "Work", UserInfo.FLAG_PROFILE); 6821 ui.userType = USER_TYPE_PROFILE_MANAGED; 6822 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6823 mService.readPolicyXml( 6824 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6825 true, 6826 10, null); 6827 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 6828 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 6829 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 6830 } 6831 6832 @Test testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser()6833 public void testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser() throws Exception { 6834 mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, 6835 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 6836 final String policyXml = "<notification-policy version=\"1\">" 6837 + "<ranking></ranking>" 6838 + "<enabled_listeners>" 6839 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6840 + "</enabled_listeners>" 6841 + "<enabled_assistants>" 6842 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6843 + "</enabled_assistants>" 6844 + "<dnd_apps>" 6845 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6846 + "</dnd_apps>" 6847 + "</notification-policy>"; 6848 UserInfo ui = new UserInfo(10, "Private", UserInfo.FLAG_PROFILE); 6849 ui.userType = USER_TYPE_PROFILE_PRIVATE; 6850 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6851 mService.readPolicyXml( 6852 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6853 true, 6854 10, null); 6855 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 6856 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 6857 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 6858 } 6859 6860 @Test testReadPolicyXml_restoresManagedServicesForNonManagedUser()6861 public void testReadPolicyXml_restoresManagedServicesForNonManagedUser() throws Exception { 6862 final String policyXml = "<notification-policy version=\"1\">" 6863 + "<ranking></ranking>" 6864 + "<enabled_listeners>" 6865 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6866 + "</enabled_listeners>" 6867 + "<enabled_assistants>" 6868 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6869 + "</enabled_assistants>" 6870 + "<dnd_apps>" 6871 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6872 + "</dnd_apps>" 6873 + "</notification-policy>"; 6874 UserInfo ui = new UserInfo(); 6875 ui.id = 10; 6876 ui.userType = USER_TYPE_FULL_SECONDARY; 6877 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6878 mService.readPolicyXml( 6879 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6880 true, 6881 10, null); 6882 verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10)); 6883 verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10)); 6884 verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10)); 6885 } 6886 6887 @Test 6888 @EnableFlags(android.app.Flags.FLAG_BACKUP_RESTORE_LOGGING) testReadPolicyXml_backupRestoreLogging()6889 public void testReadPolicyXml_backupRestoreLogging() throws Exception { 6890 BackupRestoreEventLogger logger = mock(BackupRestoreEventLogger.class); 6891 6892 if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) { 6893 // By default, the ZenModeHelper only has a configuration for the system user. 6894 // If the current user is not the system user, the user must be updated. 6895 mService.mZenModeHelper.onUserSwitched(ActivityManager.getCurrentUser()); 6896 } 6897 UserInfo ui = new UserInfo(ActivityManager.getCurrentUser(), "Clone", UserInfo.FLAG_FULL); 6898 ui.userType = USER_TYPE_FULL_SYSTEM; 6899 when(mUmInternal.getUserInfo(ActivityManager.getCurrentUser())).thenReturn(ui); 6900 when(mPermissionHelper.getNotificationPermissionValues(ActivityManager.getCurrentUser())) 6901 .thenReturn(new ArrayMap<>()); 6902 TypedXmlSerializer serializer = Xml.newFastSerializer(); 6903 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 6904 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 6905 serializer.startDocument(null, true); 6906 mService.writePolicyXml(baos, true, ActivityManager.getCurrentUser(), logger); 6907 serializer.flush(); 6908 6909 mService.readPolicyXml( 6910 new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 6911 true, ActivityManager.getCurrentUser(), logger); 6912 6913 verify(logger).logItemsBackedUp(DATA_TYPE_ZEN_CONFIG, 1); 6914 verify(logger, never()) 6915 .logItemsBackupFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString()); 6916 6917 verify(logger).logItemsRestored(DATA_TYPE_ZEN_CONFIG, 1); 6918 verify(logger, never()) 6919 .logItemsRestoreFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString()); 6920 } 6921 6922 @Test testLocaleChangedCallsUpdateDefaultZenModeRules()6923 public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception { 6924 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 6925 mService.mZenModeHelper = mZenModeHelper; 6926 mService.mLocaleChangeReceiver.onReceive(mContext, 6927 new Intent(Intent.ACTION_LOCALE_CHANGED)); 6928 6929 verify(mZenModeHelper).updateZenRulesOnLocaleChange(); 6930 } 6931 simulateNotificationTimeout(String notificationKey)6932 private void simulateNotificationTimeout(String notificationKey) { 6933 if (Flags.allNotifsNeedTtl()) { 6934 mService.mNotificationManagerPrivate.timeoutNotification(notificationKey); 6935 } else { 6936 final Bundle extras = new Bundle(); 6937 extras.putString(EXTRA_KEY, notificationKey); 6938 final Intent intent = new Intent(ACTION_NOTIFICATION_TIMEOUT); 6939 intent.putExtras(extras); 6940 mNotificationTimeoutReceiver.onReceive(getContext(), intent); 6941 } 6942 } 6943 6944 @Test testTimeout_CancelsNotification()6945 public void testTimeout_CancelsNotification() throws Exception { 6946 final NotificationRecord notif = generateNotificationRecord( 6947 mTestNotificationChannel, 1, null, false); 6948 mService.addNotification(notif); 6949 6950 simulateNotificationTimeout(notif.getKey()); 6951 waitForIdle(); 6952 6953 // Check that the notification was cancelled. 6954 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 6955 assertThat(notifsAfter.length).isEqualTo(0); 6956 assertThat(mService.getNotificationRecord(notif.getKey())).isNull(); 6957 } 6958 6959 @Test testTimeout_NoCancelForegroundServiceNotification()6960 public void testTimeout_NoCancelForegroundServiceNotification() throws Exception { 6961 // Creates a notification with FLAG_FOREGROUND_SERVICE 6962 final NotificationRecord notif = generateNotificationRecord(null); 6963 notif.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; 6964 mService.addNotification(notif); 6965 6966 simulateNotificationTimeout(notif.getKey()); 6967 waitForIdle(); 6968 6969 // Check that the notification was not cancelled. 6970 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 6971 assertThat(notifsAfter.length).isEqualTo(1); 6972 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 6973 } 6974 6975 @Test testTimeout_NoCancelUserInitJobNotification()6976 public void testTimeout_NoCancelUserInitJobNotification() throws Exception { 6977 // Create a notification with FLAG_USER_INITIATED_JOB 6978 final NotificationRecord notif = generateNotificationRecord(null); 6979 notif.getSbn().getNotification().flags = Notification.FLAG_USER_INITIATED_JOB; 6980 mService.addNotification(notif); 6981 6982 simulateNotificationTimeout(notif.getKey()); 6983 waitForIdle(); 6984 6985 // Check that the notification was not cancelled. 6986 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 6987 assertThat(notifsAfter.length).isEqualTo(1); 6988 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 6989 } 6990 6991 @Test 6992 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testTimeout_NoCancelLifetimeExtensionNotification()6993 public void testTimeout_NoCancelLifetimeExtensionNotification() throws Exception { 6994 // Create a notification with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY 6995 final NotificationRecord notif = generateNotificationRecord(null); 6996 notif.getSbn().getNotification().flags = 6997 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 6998 mService.addNotification(notif); 6999 7000 simulateNotificationTimeout(notif.getKey()); 7001 waitForIdle(); 7002 7003 // Check that the notification was not cancelled. 7004 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 7005 assertThat(notifsAfter.length).isEqualTo(1); 7006 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 7007 7008 // Checks that a post update is sent. 7009 verify(mWorkerHandler, times(1)) 7010 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 7011 ArgumentCaptor<NotificationRecord> captor = 7012 ArgumentCaptor.forClass(NotificationRecord.class); 7013 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 7014 anyBoolean()); 7015 assertThat(captor.getValue().getNotification().flags 7016 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 7017 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 7018 } 7019 7020 @Test testBumpFGImportance_channelChangePreOApp()7021 public void testBumpFGImportance_channelChangePreOApp() throws Exception { 7022 Notification.Builder nb = new Notification.Builder(mContext, 7023 NotificationChannel.DEFAULT_CHANNEL_ID) 7024 .setContentTitle("foo") 7025 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7026 .setFlag(FLAG_FOREGROUND_SERVICE, true) 7027 .setPriority(Notification.PRIORITY_MIN); 7028 7029 StatusBarNotification sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, 7030 "testBumpFGImportance_channelChangePreOApp", 7031 Binder.getCallingUid(), 0, nb.build(), 7032 UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); 7033 7034 mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(), 7035 sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId()); 7036 waitForIdle(); 7037 7038 assertEquals(IMPORTANCE_LOW, 7039 mService.getNotificationRecord(sbn.getKey()).getImportance()); 7040 assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance( 7041 sbn.getPackageName())); 7042 7043 nb = new Notification.Builder(mContext) 7044 .setContentTitle("foo") 7045 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7046 .setFlag(FLAG_FOREGROUND_SERVICE, true) 7047 .setPriority(Notification.PRIORITY_MIN); 7048 7049 sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, 7050 "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(), 7051 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); 7052 7053 mBinderService.enqueueNotificationWithTag(PKG_N_MR1, PKG_N_MR1, 7054 "testBumpFGImportance_channelChangePreOApp", 7055 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 7056 waitForIdle(); 7057 assertEquals(IMPORTANCE_LOW, 7058 mService.getNotificationRecord(sbn.getKey()).getImportance()); 7059 7060 NotificationChannel defaultChannel = mBinderService.getNotificationChannel( 7061 PKG_N_MR1, mContext.getUserId(), PKG_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID); 7062 assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance()); 7063 } 7064 7065 @Test testStats_updatedOnDirectReply()7066 public void testStats_updatedOnDirectReply() throws Exception { 7067 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7068 mService.addNotification(r); 7069 7070 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7071 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied()); 7072 verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r)); 7073 7074 assertEquals(1, mNotificationRecordLogger.numCalls()); 7075 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED, 7076 mNotificationRecordLogger.event(0)); 7077 } 7078 7079 @Test 7080 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_DirectReplyLifetimeExtendedPostsUpdate()7081 public void testStats_DirectReplyLifetimeExtendedPostsUpdate() throws Exception { 7082 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7083 // Marks the notification as having already been lifetime extended and canceled. 7084 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7085 r.setCanceledAfterLifetimeExtension(true); 7086 r.setPostSilently(true); 7087 mService.addNotification(r); 7088 7089 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7090 waitForIdle(); 7091 7092 // At the moment prepareNotifyPostedLocked is called on the listeners, 7093 // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial 7094 // values. 7095 doAnswer( 7096 invocation -> { 7097 int flags = ((NotificationRecord) invocation.getArgument(0)) 7098 .getSbn().getNotification().flags; 7099 assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 7100 boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0)) 7101 .shouldPostSilently(); 7102 assertThat(shouldPostSilently).isTrue(); 7103 return null; 7104 } 7105 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 7106 7107 // Checks that the record gets marked as a direct reply having occurred. 7108 assertThat(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied()) 7109 .isTrue(); 7110 // Checks that a post update is sent. 7111 verify(mWorkerHandler, times(1)) 7112 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 7113 ArgumentCaptor<NotificationRecord> captor = 7114 ArgumentCaptor.forClass(NotificationRecord.class); 7115 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 7116 anyBoolean()); 7117 assertThat(captor.getValue().getNotification().flags 7118 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 7119 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 7120 // FLAG_ONLY_ALERT_ONCE was not present on the original notification, so it's not here. 7121 assertThat(captor.getValue().getNotification().flags 7122 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0); 7123 assertThat(captor.getValue().shouldPostSilently()).isTrue(); 7124 assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isTrue(); 7125 } 7126 7127 @Test 7128 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently()7129 public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently() 7130 throws Exception { 7131 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7132 // Marks the notification as having already been lifetime extended and canceled. 7133 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7134 r.setPostSilently(false); 7135 mService.addNotification(r); 7136 7137 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7138 waitForIdle(); 7139 7140 // Checks that a post update is sent with shouldPostSilently set to true. 7141 doAnswer( 7142 invocation -> { 7143 boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0)) 7144 .shouldPostSilently(); 7145 assertThat(shouldPostSilently).isTrue(); 7146 return null; 7147 } 7148 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 7149 7150 // Checks that shouldPostSilently is restored to its false state afterward. 7151 assertThat(mService.getNotificationRecord(r.getKey()).shouldPostSilently()).isFalse(); 7152 } 7153 7154 @Test 7155 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag()7156 public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag() 7157 throws Exception { 7158 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7159 // Marks the notification as having already been lifetime extended and canceled. 7160 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7161 mService.addNotification(r); 7162 7163 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7164 waitForIdle(); 7165 7166 // Checks that a post update is sent with FLAG_ONLY_ALERT_ONCE set to true. 7167 doAnswer( 7168 invocation -> { 7169 int flags = ((NotificationRecord) invocation.getArgument(0)) 7170 .getSbn().getNotification().flags; 7171 assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 7172 return null; 7173 } 7174 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 7175 7176 // Checks that the flag is removed afterward. 7177 assertThat(mService.getNotificationRecord(r.getKey()).getSbn().getNotification().flags 7178 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0); 7179 } 7180 7181 @Test 7182 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds()7183 public void testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds() throws Exception { 7184 // Creates a lifetime extended notification. 7185 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 7186 original.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7187 mService.addNotification(original); 7188 7189 // Post an update for that notification. 7190 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(), 7191 original.getSbn().getTag(), mUid, 0, 7192 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 7193 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7194 .setContentTitle("new title").build(), 7195 UserHandle.getUserHandleForUid(mUid), null, 0); 7196 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7197 mService.addEnqueuedNotification(update); 7198 7199 NotificationManagerService.PostNotificationRunnable runnable = 7200 mService.new PostNotificationRunnable(update.getKey(), 7201 update.getSbn().getPackageName(), 7202 update.getUid(), 7203 mPostNotificationTrackerFactory.newTracker(null)); 7204 runnable.run(); 7205 waitForIdle(); 7206 7207 // Checks the update was sent, and that update contains the new title, and does not contain 7208 // the lifetime extension flag. 7209 ArgumentCaptor<NotificationRecord> captor = 7210 ArgumentCaptor.forClass(NotificationRecord.class); 7211 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 7212 anyBoolean()); 7213 assertThat(captor.getValue().getNotification().flags 7214 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0); 7215 assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isFalse(); 7216 assertThat(captor.getValue() 7217 .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString()) 7218 .isEqualTo("new title"); 7219 } 7220 7221 @Test testStats_updatedOnUserExpansion()7222 public void testStats_updatedOnUserExpansion() throws Exception { 7223 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7224 mService.addNotification(r); 7225 7226 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true, 7227 NOTIFICATION_LOCATION_UNKNOWN); 7228 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 7229 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((true))); 7230 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7231 7232 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false, 7233 NOTIFICATION_LOCATION_UNKNOWN); 7234 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 7235 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((false))); 7236 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7237 7238 assertEquals(2, mNotificationRecordLogger.numCalls()); 7239 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_OPEN_USER, 7240 mNotificationRecordLogger.event(0)); 7241 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_CLOSE_USER, 7242 mNotificationRecordLogger.event(1)); 7243 } 7244 7245 @Test testStats_notUpdatedOnAutoExpansion()7246 public void testStats_notUpdatedOnAutoExpansion() throws Exception { 7247 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7248 mService.addNotification(r); 7249 7250 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 7251 NOTIFICATION_LOCATION_UNKNOWN); 7252 assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7253 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 7254 eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((true))); 7255 7256 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false, 7257 NOTIFICATION_LOCATION_UNKNOWN); 7258 assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7259 verify(mAssistants).notifyAssistantExpansionChangedLocked( 7260 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((false))); 7261 } 7262 7263 @Test testStats_updatedOnViewSettings()7264 public void testStats_updatedOnViewSettings() throws Exception { 7265 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7266 mService.addNotification(r); 7267 7268 mService.mNotificationDelegate.onNotificationSettingsViewed(r.getKey()); 7269 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasViewedSettings()); 7270 } 7271 7272 @Test testStats_updatedOnVisibilityChanged()7273 public void testStats_updatedOnVisibilityChanged() throws Exception { 7274 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7275 mService.addNotification(r); 7276 7277 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true); 7278 mService.mNotificationDelegate.onNotificationVisibilityChanged( 7279 new NotificationVisibility[] {nv}, new NotificationVisibility[]{}); 7280 verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(true)); 7281 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen()); 7282 mService.mNotificationDelegate.onNotificationVisibilityChanged( 7283 new NotificationVisibility[] {}, new NotificationVisibility[]{nv}); 7284 verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(false)); 7285 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen()); 7286 } 7287 7288 @Test testStats_dismissalSurface()7289 public void testStats_dismissalSurface() throws Exception { 7290 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7291 r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7292 mService.addNotification(r); 7293 7294 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); 7295 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(), 7296 r.getKey(), NotificationStats.DISMISSAL_AOD, 7297 NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv); 7298 waitForIdle(); 7299 7300 assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface()); 7301 7302 // Using mService.addNotification() does not generate a NotificationRecordLogger log, 7303 // so we only get the cancel notification. 7304 assertEquals(1, mNotificationRecordLogger.numCalls()); 7305 7306 assertEquals( 7307 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD, 7308 mNotificationRecordLogger.event(0)); 7309 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 7310 } 7311 7312 @Test testStats_dismissalSentiment()7313 public void testStats_dismissalSentiment() throws Exception { 7314 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7315 mService.addNotification(r); 7316 7317 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); 7318 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(), 7319 r.getKey(), NotificationStats.DISMISSAL_AOD, 7320 NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv); 7321 waitForIdle(); 7322 7323 assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE, 7324 r.getStats().getDismissalSentiment()); 7325 } 7326 7327 @Test testTextChangedSet_forNewNotifs()7328 public void testTextChangedSet_forNewNotifs() throws Exception { 7329 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 7330 mService.addEnqueuedNotification(original); 7331 7332 NotificationManagerService.PostNotificationRunnable runnable = 7333 mService.new PostNotificationRunnable(original.getKey(), 7334 original.getSbn().getPackageName(), 7335 original.getUid(), 7336 mPostNotificationTrackerFactory.newTracker(null)); 7337 runnable.run(); 7338 waitForIdle(); 7339 7340 assertTrue(original.isTextChanged()); 7341 } 7342 7343 @Test testVisuallyInterruptive_notSeen()7344 public void testVisuallyInterruptive_notSeen() throws Exception { 7345 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 7346 mService.addNotification(original); 7347 7348 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(), 7349 original.getSbn().getTag(), mUid, 0, 7350 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 7351 .setContentTitle("new title").build(), 7352 UserHandle.getUserHandleForUid(mUid), null, 0); 7353 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7354 mService.addEnqueuedNotification(update); 7355 7356 NotificationManagerService.PostNotificationRunnable runnable = 7357 mService.new PostNotificationRunnable(update.getKey(), 7358 update.getSbn().getPackageName(), 7359 update.getUid(), 7360 mPostNotificationTrackerFactory.newTracker(null)); 7361 runnable.run(); 7362 waitForIdle(); 7363 7364 assertFalse(update.isInterruptive()); 7365 } 7366 7367 @Test testApplyAdjustmentMultiUser()7368 public void testApplyAdjustmentMultiUser() throws Exception { 7369 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7370 mService.addNotification(r); 7371 NotificationManagerService.WorkerHandler handler = mock( 7372 NotificationManagerService.WorkerHandler.class); 7373 mService.setHandler(handler); 7374 7375 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false); 7376 7377 Bundle signals = new Bundle(); 7378 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7379 USER_SENTIMENT_NEGATIVE); 7380 Adjustment adjustment = new Adjustment( 7381 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7382 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 7383 7384 waitForIdle(); 7385 7386 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 7387 } 7388 7389 @Test testAssistantBlockingTriggersCancel()7390 public void testAssistantBlockingTriggersCancel() throws Exception { 7391 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7392 mService.addNotification(r); 7393 NotificationManagerService.WorkerHandler handler = mock( 7394 NotificationManagerService.WorkerHandler.class); 7395 mService.setHandler(handler); 7396 7397 Bundle signals = new Bundle(); 7398 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE); 7399 Adjustment adjustment = new Adjustment( 7400 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7401 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 7402 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 7403 7404 waitForIdle(); 7405 7406 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 7407 verify(handler, times(1)).scheduleCancelNotification(any(), eq(0)); 7408 } 7409 7410 @Test testApplyEnqueuedAdjustmentFromAssistant_singleUser()7411 public void testApplyEnqueuedAdjustmentFromAssistant_singleUser() throws Exception { 7412 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7413 mService.addEnqueuedNotification(r); 7414 NotificationManagerService.WorkerHandler handler = mock( 7415 NotificationManagerService.WorkerHandler.class); 7416 mService.setHandler(handler); 7417 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7418 7419 Bundle signals = new Bundle(); 7420 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7421 USER_SENTIMENT_NEGATIVE); 7422 Adjustment adjustment = new Adjustment( 7423 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7424 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7425 7426 assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment()); 7427 } 7428 7429 @Test testApplyEnqueuedAdjustmentFromAssistant_importance()7430 public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception { 7431 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7432 mService.addEnqueuedNotification(r); 7433 NotificationManagerService.WorkerHandler handler = mock( 7434 NotificationManagerService.WorkerHandler.class); 7435 mService.setHandler(handler); 7436 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7437 7438 Bundle signals = new Bundle(); 7439 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); 7440 Adjustment adjustment = new Adjustment( 7441 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7442 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7443 7444 assertEquals(IMPORTANCE_LOW, r.getImportance()); 7445 } 7446 7447 @Test testApplyEnqueuedAdjustmentFromAssistant_crossUser()7448 public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception { 7449 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7450 mService.addEnqueuedNotification(r); 7451 NotificationManagerService.WorkerHandler handler = mock( 7452 NotificationManagerService.WorkerHandler.class); 7453 mService.setHandler(handler); 7454 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false); 7455 7456 Bundle signals = new Bundle(); 7457 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7458 USER_SENTIMENT_NEGATIVE); 7459 Adjustment adjustment = new Adjustment( 7460 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7461 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7462 7463 assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment()); 7464 7465 waitForIdle(); 7466 7467 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 7468 } 7469 7470 @Test testUserSentimentChangeTriggersUpdate()7471 public void testUserSentimentChangeTriggersUpdate() throws Exception { 7472 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7473 mService.addNotification(r); 7474 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7475 7476 Bundle signals = new Bundle(); 7477 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7478 USER_SENTIMENT_NEGATIVE); 7479 Adjustment adjustment = new Adjustment( 7480 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7481 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 7482 7483 waitForIdle(); 7484 7485 verify(mRankingHandler, timeout(300).times(1)).requestSort(); 7486 } 7487 7488 @Test testTooLateAdjustmentTriggersUpdate()7489 public void testTooLateAdjustmentTriggersUpdate() throws Exception { 7490 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7491 mService.addNotification(r); 7492 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7493 7494 Bundle signals = new Bundle(); 7495 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7496 USER_SENTIMENT_NEGATIVE); 7497 Adjustment adjustment = new Adjustment( 7498 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7499 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7500 7501 waitForIdle(); 7502 7503 verify(mRankingHandler, times(1)).requestSort(); 7504 } 7505 7506 @Test testApplyAdjustmentsLogged()7507 public void testApplyAdjustmentsLogged() throws Exception { 7508 NotificationManagerService.WorkerHandler handler = mock( 7509 NotificationManagerService.WorkerHandler.class); 7510 mService.setHandler(handler); 7511 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7512 7513 // Set up notifications that will be adjusted 7514 final NotificationRecord r1 = generateNotificationRecord( 7515 mTestNotificationChannel, 1, null, true); 7516 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7517 mService.addNotification(r1); 7518 final NotificationRecord r2 = generateNotificationRecord( 7519 mTestNotificationChannel, 2, null, true); 7520 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7521 mService.addNotification(r2); 7522 7523 // Third notification that's NOT adjusted, just to make sure that doesn't get spuriously 7524 // logged. 7525 final NotificationRecord r3 = generateNotificationRecord( 7526 mTestNotificationChannel, 3, null, true); 7527 r3.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7528 mService.addNotification(r3); 7529 7530 List<Adjustment> adjustments = new ArrayList<>(); 7531 7532 // Test an adjustment that's associated with a ranking change and one that's not 7533 Bundle signals1 = new Bundle(); 7534 signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_HIGH); 7535 Adjustment adjustment1 = new Adjustment( 7536 r1.getSbn().getPackageName(), r1.getKey(), signals1, "", 7537 r1.getUser().getIdentifier()); 7538 adjustments.add(adjustment1); 7539 7540 // This one wouldn't trigger a ranking change, but should still trigger a log. 7541 Bundle signals2 = new Bundle(); 7542 signals2.putFloat(Adjustment.KEY_RANKING_SCORE, -0.5f); 7543 Adjustment adjustment2 = new Adjustment( 7544 r2.getSbn().getPackageName(), r2.getKey(), signals2, "", 7545 r2.getUser().getIdentifier()); 7546 adjustments.add(adjustment2); 7547 7548 mBinderService.applyAdjustmentsFromAssistant(null, adjustments); 7549 verify(mRankingHandler, times(1)).requestSort(); 7550 7551 // Actually apply the adjustments & recalculate importance when run 7552 doAnswer(invocationOnMock -> { 7553 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7554 .applyAdjustments(); 7555 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7556 .calculateImportance(); 7557 return null; 7558 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 7559 7560 // Now make sure that when the sort happens, we actually log the changes. 7561 mService.handleRankingSort(); 7562 7563 // Even though the ranking score change is not meant to trigger a ranking update, 7564 // during this process the package visibility & canShowBadge values are changing 7565 // in all notifications, so all 3 seem to trigger a ranking change. Here we check instead 7566 // that scheduleSendRankingUpdate is sent and that the relevant fields have been changed 7567 // accordingly to confirm the adjustments happened to the 2 relevant notifications. 7568 verify(handler, times(3)).scheduleSendRankingUpdate(); 7569 assertEquals(IMPORTANCE_HIGH, r1.getImportance()); 7570 assertTrue(r2.rankingScoreMatches(-0.5f)); 7571 assertEquals(2, mNotificationRecordLogger.numCalls()); 7572 assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(0)); 7573 assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(1)); 7574 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 7575 assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId()); 7576 } 7577 7578 @Test testSensitiveAdjustmentsLogged()7579 public void testSensitiveAdjustmentsLogged() throws Exception { 7580 NotificationManagerService.WorkerHandler handler = mock( 7581 NotificationManagerService.WorkerHandler.class); 7582 mService.setHandler(handler); 7583 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 7584 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 7585 7586 // Set up notifications that will be adjusted 7587 final NotificationRecord r1 = spy(generateNotificationRecord( 7588 mTestNotificationChannel, 1, null, true)); 7589 when(r1.getLifespanMs(anyLong())).thenReturn(1); 7590 7591 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7592 mService.addEnqueuedNotification(r1); 7593 7594 // Test an adjustment for an enqueued notification 7595 Bundle signals = new Bundle(); 7596 signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true); 7597 Adjustment adjustment1 = new Adjustment( 7598 r1.getSbn().getPackageName(), r1.getKey(), signals, "", 7599 r1.getUser().getIdentifier()); 7600 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); 7601 assertTrue(mService.checkLastSensitiveLog(false, true, 1)); 7602 7603 // Set up notifications that will be adjusted 7604 final NotificationRecord r2 = spy(generateNotificationRecord( 7605 mTestNotificationChannel, 1, null, true)); 7606 when(r2.getLifespanMs(anyLong())).thenReturn(2); 7607 7608 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7609 mService.addNotification(r2); 7610 Adjustment adjustment2 = new Adjustment( 7611 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7612 r2.getUser().getIdentifier()); 7613 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); 7614 assertTrue(mService.checkLastSensitiveLog(true, true, 2)); 7615 7616 signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, false); 7617 Adjustment adjustment3 = new Adjustment( 7618 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7619 r2.getUser().getIdentifier()); 7620 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); 7621 assertTrue(mService.checkLastSensitiveLog(true, false, 2)); 7622 } 7623 7624 @Test 7625 @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) testClassificationChannelAdjustmentsLogged()7626 public void testClassificationChannelAdjustmentsLogged() throws Exception { 7627 NotificationManagerService.WorkerHandler handler = mock( 7628 NotificationManagerService.WorkerHandler.class); 7629 mService.setHandler(handler); 7630 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 7631 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 7632 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 7633 when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); 7634 7635 // Set up notifications that will be adjusted 7636 final NotificationRecord r1 = spy(generateNotificationRecord( 7637 mTestNotificationChannel, 1, null, true)); 7638 when(r1.getLifespanMs(anyLong())).thenReturn(234); 7639 7640 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7641 // Enqueues the notification to be posted, so hasPosted will be false. 7642 mService.addEnqueuedNotification(r1); 7643 7644 // Test an adjustment for an enqueued notification 7645 Bundle signals = new Bundle(); 7646 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 7647 Adjustment adjustment1 = new Adjustment( 7648 r1.getSbn().getPackageName(), r1.getKey(), signals, "", 7649 r1.getUser().getIdentifier()); 7650 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); 7651 assertTrue(mService.checkLastClassificationChannelLog(false /*hasPosted*/, 7652 true /*isAlerting*/, 3 /*TYPE_NEWS*/, 234)); 7653 7654 // Set up notifications that will be adjusted 7655 // This notification starts on a low importance channel, so isAlerting is false. 7656 NotificationChannel mLowImportanceNotificationChannel = new NotificationChannel( 7657 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_LOW); 7658 final NotificationRecord r2 = spy(generateNotificationRecord( 7659 mLowImportanceNotificationChannel, 1, null, true)); 7660 when(r2.getLifespanMs(anyLong())).thenReturn(345); 7661 7662 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7663 // Adds the notification as already posted, so hasPosted will be true. 7664 mService.addNotification(r2); 7665 // The signal is removed when used so it has to be readded. 7666 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 7667 Adjustment adjustment2 = new Adjustment( 7668 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7669 r2.getUser().getIdentifier()); 7670 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); 7671 assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, 7672 false /*isAlerting*/, 3 /*TYPE_NEWS*/, 345)); // currently failing 7673 7674 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_PROMOTION); 7675 Adjustment adjustment3 = new Adjustment( 7676 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7677 r2.getUser().getIdentifier()); 7678 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); 7679 assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, 7680 false /*isAlerting*/, 1 /*TYPE_PROMOTION*/, 345)); 7681 } 7682 7683 @Test testAdjustmentToImportanceNone_cancelsNotification()7684 public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception { 7685 NotificationManagerService.WorkerHandler handler = mock( 7686 NotificationManagerService.WorkerHandler.class); 7687 mService.setHandler(handler); 7688 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7689 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 7690 7691 // Set up notifications: r1 is adjusted, r2 is not 7692 final NotificationRecord r1 = generateNotificationRecord( 7693 mTestNotificationChannel, 1, null, true); 7694 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7695 mService.addNotification(r1); 7696 final NotificationRecord r2 = generateNotificationRecord( 7697 mTestNotificationChannel, 2, null, true); 7698 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7699 mService.addNotification(r2); 7700 7701 // Test an adjustment that sets importance to none (meaning it's cancelling) 7702 Bundle signals1 = new Bundle(); 7703 signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE); 7704 Adjustment adjustment1 = new Adjustment( 7705 r1.getSbn().getPackageName(), r1.getKey(), signals1, "", 7706 r1.getUser().getIdentifier()); 7707 7708 mBinderService.applyAdjustmentFromAssistant(null, adjustment1); 7709 7710 // Actually apply the adjustments & recalculate importance when run 7711 doAnswer(invocationOnMock -> { 7712 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7713 .applyAdjustments(); 7714 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7715 .calculateImportance(); 7716 return null; 7717 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 7718 7719 // run the CancelNotificationRunnable when it happens 7720 ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor = 7721 ArgumentCaptor.forClass( 7722 NotificationManagerService.CancelNotificationRunnable.class); 7723 7724 verify(handler, times(1)).scheduleCancelNotification( 7725 captor.capture(), eq(0)); 7726 7727 // Run the runnable given to the cancel notification, and see if it logs properly 7728 NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue(); 7729 runnable.run(); 7730 assertEquals(1, mNotificationRecordLogger.numCalls()); 7731 assertEquals( 7732 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT, 7733 mNotificationRecordLogger.event(0)); 7734 } 7735 7736 @Test testEnqueuedAdjustmentAppliesAdjustments()7737 public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception { 7738 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7739 mService.addEnqueuedNotification(r); 7740 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7741 7742 Bundle signals = new Bundle(); 7743 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7744 USER_SENTIMENT_NEGATIVE); 7745 Adjustment adjustment = new Adjustment( 7746 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7747 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7748 7749 assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment()); 7750 } 7751 7752 @Test testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications()7753 public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception { 7754 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel); 7755 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel); 7756 mService.addEnqueuedNotification(r1); 7757 mService.addEnqueuedNotification(r2); 7758 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7759 7760 Bundle signals = new Bundle(); 7761 signals.putInt(Adjustment.KEY_IMPORTANCE, 7762 IMPORTANCE_HIGH); 7763 Adjustment adjustment = new Adjustment( 7764 r1.getSbn().getPackageName(), r1.getKey(), signals, 7765 "", r1.getUser().getIdentifier()); 7766 7767 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7768 7769 assertEquals(IMPORTANCE_HIGH, r1.getImportance()); 7770 assertEquals(IMPORTANCE_HIGH, r2.getImportance()); 7771 } 7772 7773 @Test testRestore()7774 public void testRestore() throws Exception { 7775 int systemChecks = mService.countSystemChecks; 7776 mBinderService.applyRestore(null, USER_SYSTEM); 7777 assertEquals(1, mService.countSystemChecks - systemChecks); 7778 } 7779 7780 @Test testBackupEmptySound()7781 public void testBackupEmptySound() throws Exception { 7782 NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 7783 channel.setSound(Uri.EMPTY, null); 7784 7785 TypedXmlSerializer serializer = Xml.newFastSerializer(); 7786 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 7787 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 7788 channel.writeXmlForBackup(serializer, getContext()); 7789 7790 TypedXmlPullParser parser = Xml.newFastPullParser(); 7791 parser.setInput(new BufferedInputStream( 7792 new ByteArrayInputStream(baos.toByteArray())), null); 7793 NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 7794 restored.populateFromXmlForRestore(parser, true, getContext()); 7795 7796 assertNull(restored.getSound()); 7797 } 7798 7799 @Test testBackup()7800 public void testBackup() throws Exception { 7801 mService.setPreferencesHelper(mPreferencesHelper); 7802 int systemChecks = mService.countSystemChecks; 7803 when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt())) 7804 .thenReturn(new ArraySet<>()); 7805 mBinderService.getBackupPayload(1); 7806 assertEquals(1, mService.countSystemChecks - systemChecks); 7807 } 7808 7809 @Test testEmptyVibration_noException()7810 public void testEmptyVibration_noException() throws Exception { 7811 NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 7812 channel.setVibrationPattern(new long[0]); 7813 7814 TypedXmlSerializer serializer = Xml.newFastSerializer(); 7815 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 7816 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 7817 channel.writeXml(serializer); 7818 } 7819 7820 @Test updateUriPermissions_update()7821 public void updateUriPermissions_update() throws Exception { 7822 NotificationChannel c = new NotificationChannel( 7823 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 7824 c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT); 7825 Message message1 = new Message("", 0, ""); 7826 message1.setData("", 7827 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1)); 7828 Message message2 = new Message("", 1, ""); 7829 message2.setData("", 7830 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2)); 7831 7832 Notification.Builder nbA = new Notification.Builder(mContext, c.getId()) 7833 .setContentTitle("foo") 7834 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7835 .setStyle(new Notification.MessagingStyle("") 7836 .addMessage(message1) 7837 .addMessage(message2)); 7838 NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification( 7839 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid), 7840 null, 0), c); 7841 7842 // First post means we grant access to both 7843 reset(mUgm); 7844 reset(mUgmInternal); 7845 when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder()); 7846 mService.updateUriPermissions(recordA, null, mContext.getPackageName(), 7847 USER_SYSTEM); 7848 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 7849 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt()); 7850 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 7851 eq(message2.getDataUri()), anyInt(), anyInt(), anyInt()); 7852 7853 Notification.Builder nbB = new Notification.Builder(mContext, c.getId()) 7854 .setContentTitle("foo") 7855 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7856 .setStyle(new Notification.MessagingStyle("").addMessage(message2)); 7857 NotificationRecord recordB = 7858 new NotificationRecord( 7859 mContext, 7860 new StatusBarNotification( 7861 mPkg, 7862 mPkg, 7863 0, 7864 "tag", 7865 mUid, 7866 0, 7867 nbB.build(), 7868 UserHandle.getUserHandleForUid(mUid), 7869 null, 7870 0), 7871 c); 7872 7873 // Update means we drop access to first 7874 reset(mUgmInternal); 7875 mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(), 7876 USER_SYSTEM); 7877 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), 7878 eq(message1.getDataUri()), anyInt(), anyInt(), eq(null), eq(-1)); 7879 7880 // Update back means we grant access to first again 7881 reset(mUgm); 7882 mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(), 7883 USER_SYSTEM); 7884 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 7885 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt()); 7886 7887 // And update to empty means we drop everything 7888 reset(mUgmInternal); 7889 mService.updateUriPermissions(null, recordB, mContext.getPackageName(), 7890 USER_SYSTEM); 7891 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null), 7892 anyInt(), anyInt()); 7893 } 7894 7895 @Test updateUriPermissions_posterDoesNotOwnUri()7896 public void updateUriPermissions_posterDoesNotOwnUri() throws Exception { 7897 NotificationChannel c = new NotificationChannel( 7898 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 7899 c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT); 7900 Message message1 = new Message("", 0, ""); 7901 message1.setData("", 7902 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1)); 7903 7904 Notification.Builder nbA = new Notification.Builder(mContext, c.getId()) 7905 .setContentTitle("foo") 7906 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7907 .setStyle(new Notification.MessagingStyle("") 7908 .addMessage(message1)); 7909 NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification( 7910 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid), 7911 null, 0), c); 7912 7913 doThrow(new SecurityException("no access")).when(mUgm) 7914 .grantUriPermissionFromOwner( 7915 any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt()); 7916 7917 when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder()); 7918 mService.updateUriPermissions(recordA, null, mContext.getPackageName(), USER_SYSTEM); 7919 7920 // yay, no crash 7921 } 7922 7923 @Test testVisitUris()7924 public void testVisitUris() throws Exception { 7925 final Uri audioContents = Uri.parse("content://com.example/audio"); 7926 final Uri backgroundImage = Uri.parse("content://com.example/background"); 7927 final Icon smallIcon = Icon.createWithContentUri("content://media/small/icon"); 7928 final Icon largeIcon = Icon.createWithContentUri("content://media/large/icon"); 7929 final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); 7930 final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); 7931 final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); 7932 final Person person1 = new Person.Builder() 7933 .setName("Messaging Person") 7934 .setIcon(personIcon1) 7935 .build(); 7936 final Person person2 = new Person.Builder() 7937 .setName("People List Person 1") 7938 .setIcon(personIcon2) 7939 .build(); 7940 final Person person3 = new Person.Builder() 7941 .setName("People List Person 2") 7942 .setIcon(personIcon3) 7943 .build(); 7944 final Uri historyUri1 = Uri.parse("content://com.example/history1"); 7945 final Uri historyUri2 = Uri.parse("content://com.example/history2"); 7946 final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1, 7947 "a"); 7948 final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2, 7949 "b"); 7950 7951 Bundle extras = new Bundle(); 7952 extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents); 7953 extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString()); 7954 extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1); 7955 extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, 7956 new ArrayList<>(Arrays.asList(person2, person3))); 7957 extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, 7958 new RemoteInputHistoryItem[]{historyItem1, historyItem2}); 7959 7960 Notification n = new Notification.Builder(mContext, "a") 7961 .setContentTitle("notification with uris") 7962 .setSmallIcon(smallIcon) 7963 .setLargeIcon(largeIcon) 7964 .addExtras(extras) 7965 .build(); 7966 7967 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 7968 n.visitUris(visitor); 7969 verify(visitor, times(1)).accept(eq(audioContents)); 7970 verify(visitor, times(1)).accept(eq(backgroundImage)); 7971 verify(visitor, times(1)).accept(eq(smallIcon.getUri())); 7972 verify(visitor, times(1)).accept(eq(largeIcon.getUri())); 7973 verify(visitor, times(1)).accept(eq(personIcon1.getUri())); 7974 verify(visitor, times(1)).accept(eq(personIcon2.getUri())); 7975 verify(visitor, times(1)).accept(eq(personIcon3.getUri())); 7976 verify(visitor, times(1)).accept(eq(historyUri1)); 7977 verify(visitor, times(1)).accept(eq(historyUri2)); 7978 } 7979 7980 @Test testVisitUris_publicVersion()7981 public void testVisitUris_publicVersion() throws Exception { 7982 final Icon smallIconPublic = Icon.createWithContentUri("content://media/small/icon"); 7983 final Icon largeIconPrivate = Icon.createWithContentUri("content://media/large/icon"); 7984 7985 Notification publicVersion = new Notification.Builder(mContext, "a") 7986 .setContentTitle("notification with uris") 7987 .setSmallIcon(smallIconPublic) 7988 .build(); 7989 Notification n = new Notification.Builder(mContext, "a") 7990 .setLargeIcon(largeIconPrivate) 7991 .setPublicVersion(publicVersion) 7992 .build(); 7993 7994 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 7995 n.visitUris(visitor); 7996 verify(visitor, times(1)).accept(eq(smallIconPublic.getUri())); 7997 verify(visitor, times(1)).accept(eq(largeIconPrivate.getUri())); 7998 } 7999 8000 @Test testVisitUris_audioContentsString()8001 public void testVisitUris_audioContentsString() throws Exception { 8002 final Uri audioContents = Uri.parse("content://com.example/audio"); 8003 8004 Bundle extras = new Bundle(); 8005 extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString()); 8006 8007 Notification n = new Notification.Builder(mContext, "a") 8008 .setContentTitle("notification with uris") 8009 .setSmallIcon(android.R.drawable.sym_def_app_icon) 8010 .addExtras(extras) 8011 .build(); 8012 8013 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8014 n.visitUris(visitor); 8015 verify(visitor, times(1)).accept(eq(audioContents)); 8016 } 8017 8018 @Test testVisitUris_messagingStyle()8019 public void testVisitUris_messagingStyle() { 8020 final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); 8021 final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); 8022 final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); 8023 final Person person1 = new Person.Builder() 8024 .setName("Messaging Person 1") 8025 .setIcon(personIcon1) 8026 .build(); 8027 final Person person2 = new Person.Builder() 8028 .setName("Messaging Person 2") 8029 .setIcon(personIcon2) 8030 .build(); 8031 final Person person3 = new Person.Builder() 8032 .setName("Messaging Person 3") 8033 .setIcon(personIcon3) 8034 .build(); 8035 Icon shortcutIcon = Icon.createWithContentUri("content://media/shortcut"); 8036 8037 Notification.Builder builder = new Notification.Builder(mContext, "a") 8038 .setCategory(Notification.CATEGORY_MESSAGE) 8039 .setContentTitle("new message!") 8040 .setContentText("Conversation Notification") 8041 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8042 Notification.MessagingStyle.Message message1 = new Notification.MessagingStyle.Message( 8043 "Marco?", System.currentTimeMillis(), person2); 8044 Notification.MessagingStyle.Message message2 = new Notification.MessagingStyle.Message( 8045 "Polo!", System.currentTimeMillis(), person3); 8046 Notification.MessagingStyle style = new Notification.MessagingStyle(person1) 8047 .addMessage(message1) 8048 .addMessage(message2) 8049 .setShortcutIcon(shortcutIcon); 8050 builder.setStyle(style); 8051 Notification n = builder.build(); 8052 8053 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8054 n.visitUris(visitor); 8055 8056 verify(visitor, times(1)).accept(eq(shortcutIcon.getUri())); 8057 verify(visitor, times(1)).accept(eq(personIcon1.getUri())); 8058 verify(visitor, times(1)).accept(eq(personIcon2.getUri())); 8059 verify(visitor, times(1)).accept(eq(personIcon3.getUri())); 8060 } 8061 8062 @Test testVisitUris_callStyle()8063 public void testVisitUris_callStyle() { 8064 Icon personIcon = Icon.createWithContentUri("content://media/person"); 8065 Icon verificationIcon = Icon.createWithContentUri("content://media/verification"); 8066 Person callingPerson = new Person.Builder().setName("Someone") 8067 .setIcon(personIcon) 8068 .build(); 8069 PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 8070 PendingIntent.FLAG_IMMUTABLE); 8071 Notification n = new Notification.Builder(mContext, "a") 8072 .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent) 8073 .setVerificationIcon(verificationIcon)) 8074 .setContentTitle("Calling...") 8075 .setSmallIcon(android.R.drawable.sym_def_app_icon) 8076 .build(); 8077 8078 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8079 n.visitUris(visitor); 8080 8081 verify(visitor, times(1)).accept(eq(personIcon.getUri())); 8082 verify(visitor, times(1)).accept(eq(verificationIcon.getUri())); 8083 hangUpIntent.cancel(); 8084 } 8085 8086 @Test testVisitUris_styleExtrasWithoutStyle()8087 public void testVisitUris_styleExtrasWithoutStyle() { 8088 Notification.Builder notification = new Notification.Builder(mContext, "a") 8089 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8090 8091 Bundle messagingExtras = new Bundle(); 8092 messagingExtras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, 8093 personWithIcon("content://user")); 8094 messagingExtras.putParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES, 8095 new Bundle[] { new Notification.MessagingStyle.Message("Heyhey!", 8096 System.currentTimeMillis() - 100, 8097 personWithIcon("content://historicalMessenger")).toBundle()}); 8098 messagingExtras.putParcelableArray(Notification.EXTRA_MESSAGES, 8099 new Bundle[] { new Notification.MessagingStyle.Message("Are you there?", 8100 System.currentTimeMillis(), 8101 personWithIcon("content://messenger")).toBundle()}); 8102 messagingExtras.putParcelable(Notification.EXTRA_CONVERSATION_ICON, 8103 Icon.createWithContentUri("content://conversationShortcut")); 8104 notification.addExtras(messagingExtras); 8105 8106 Bundle callExtras = new Bundle(); 8107 callExtras.putParcelable(Notification.EXTRA_CALL_PERSON, 8108 personWithIcon("content://caller")); 8109 callExtras.putParcelable(Notification.EXTRA_VERIFICATION_ICON, 8110 Icon.createWithContentUri("content://callVerification")); 8111 notification.addExtras(callExtras); 8112 8113 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8114 notification.build().visitUris(visitor); 8115 8116 verify(visitor).accept(eq(Uri.parse("content://user"))); 8117 verify(visitor).accept(eq(Uri.parse("content://historicalMessenger"))); 8118 verify(visitor).accept(eq(Uri.parse("content://messenger"))); 8119 verify(visitor).accept(eq(Uri.parse("content://conversationShortcut"))); 8120 verify(visitor).accept(eq(Uri.parse("content://caller"))); 8121 verify(visitor).accept(eq(Uri.parse("content://callVerification"))); 8122 } 8123 personWithIcon(String iconUri)8124 private static Person personWithIcon(String iconUri) { 8125 return new Person.Builder() 8126 .setName("Mr " + iconUri) 8127 .setIcon(Icon.createWithContentUri(iconUri)) 8128 .build(); 8129 } 8130 8131 @Test testVisitUris_wearableExtender()8132 public void testVisitUris_wearableExtender() { 8133 Icon actionIcon = Icon.createWithContentUri("content://media/action"); 8134 Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction"); 8135 PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(), 8136 PendingIntent.FLAG_IMMUTABLE); 8137 Notification n = new Notification.Builder(mContext, "a") 8138 .setSmallIcon(android.R.drawable.sym_def_app_icon) 8139 .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build()) 8140 .extend(new Notification.WearableExtender().addAction( 8141 new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build())) 8142 .build(); 8143 8144 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8145 n.visitUris(visitor); 8146 8147 verify(visitor).accept(eq(actionIcon.getUri())); 8148 verify(visitor).accept(eq(wearActionIcon.getUri())); 8149 } 8150 8151 @Test testSetNotificationPolicy_preP_setOldFields()8152 public void testSetNotificationPolicy_preP_setOldFields() { 8153 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8154 mService.mZenModeHelper = mZenModeHelper; 8155 NotificationManager.Policy userPolicy = 8156 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8157 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8158 8159 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8160 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); 8161 8162 int expected = SUPPRESSED_EFFECT_BADGE 8163 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF 8164 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS 8165 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8166 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 8167 8168 assertEquals(expected, actual); 8169 } 8170 8171 @Test testSetNotificationPolicy_preP_setNewFields()8172 public void testSetNotificationPolicy_preP_setNewFields() { 8173 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8174 mService.mZenModeHelper = mZenModeHelper; 8175 NotificationManager.Policy userPolicy = 8176 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8177 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8178 8179 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8180 SUPPRESSED_EFFECT_NOTIFICATION_LIST); 8181 8182 int expected = SUPPRESSED_EFFECT_BADGE; 8183 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 8184 8185 assertEquals(expected, actual); 8186 } 8187 8188 @Test testSetNotificationPolicy_preP_setOldNewFields()8189 public void testSetNotificationPolicy_preP_setOldNewFields() { 8190 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8191 mService.mZenModeHelper = mZenModeHelper; 8192 NotificationManager.Policy userPolicy = 8193 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8194 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8195 8196 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8197 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR); 8198 8199 int expected = 8200 SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK; 8201 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 8202 8203 assertEquals(expected, actual); 8204 } 8205 8206 @Test testSetNotificationPolicy_P_setOldFields()8207 public void testSetNotificationPolicy_P_setOldFields() { 8208 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8209 mService.mZenModeHelper = mZenModeHelper; 8210 NotificationManager.Policy userPolicy = 8211 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8212 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8213 8214 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8215 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); 8216 8217 int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF 8218 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT 8219 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8220 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8221 8222 assertEquals(expected, actual); 8223 } 8224 8225 @Test testSetNotificationPolicy_P_setNewFields()8226 public void testSetNotificationPolicy_P_setNewFields() { 8227 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8228 mService.mZenModeHelper = mZenModeHelper; 8229 NotificationManager.Policy userPolicy = 8230 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8231 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8232 8233 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8234 SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT 8235 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 8236 8237 int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF 8238 | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS 8239 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8240 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8241 8242 assertEquals(expected, actual); 8243 } 8244 8245 @Test testSetNotificationPolicy_P_setOldNewFields()8246 public void testSetNotificationPolicy_P_setOldNewFields() { 8247 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8248 mService.mZenModeHelper = mZenModeHelper; 8249 NotificationManager.Policy userPolicy = 8250 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8251 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8252 8253 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8254 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR); 8255 8256 int expected = SUPPRESSED_EFFECT_STATUS_BAR; 8257 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8258 8259 assertEquals(expected, actual); 8260 8261 appPolicy = new NotificationManager.Policy(0, 0, 0, 8262 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT 8263 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 8264 8265 expected = SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT 8266 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8267 actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8268 8269 assertEquals(expected, actual); 8270 } 8271 8272 @Test testVisualDifference_foreground()8273 public void testVisualDifference_foreground() { 8274 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8275 .setContentTitle("foo"); 8276 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8277 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8278 NotificationRecord r1 = 8279 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8280 8281 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8282 .setFlag(FLAG_FOREGROUND_SERVICE, true) 8283 .setContentTitle("bar"); 8284 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8285 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8286 NotificationRecord r2 = 8287 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8288 8289 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8290 } 8291 8292 @Test testVisualDifference_diffTitle()8293 public void testVisualDifference_diffTitle() { 8294 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8295 .setContentTitle("foo"); 8296 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8297 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8298 NotificationRecord r1 = 8299 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8300 8301 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8302 .setContentTitle("bar"); 8303 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8304 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8305 NotificationRecord r2 = 8306 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8307 8308 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8309 } 8310 8311 @Test testVisualDifference_inboxStyle()8312 public void testVisualDifference_inboxStyle() { 8313 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8314 .setStyle(new Notification.InboxStyle() 8315 .addLine("line1").addLine("line2")); 8316 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8317 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8318 NotificationRecord r1 = 8319 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8320 8321 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8322 .setStyle(new Notification.InboxStyle() 8323 .addLine("line1").addLine("line2_changed")); 8324 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8325 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8326 NotificationRecord r2 = 8327 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8328 8329 assertTrue(mService.isVisuallyInterruptive(r1, r2)); // line 2 changed unnoticed 8330 8331 Notification.Builder nb3 = new Notification.Builder(mContext, "") 8332 .setStyle(new Notification.InboxStyle() 8333 .addLine("line1")); 8334 StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8335 nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8336 NotificationRecord r3 = 8337 new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class)); 8338 8339 assertTrue(mService.isVisuallyInterruptive(r1, r3)); // line 2 removed unnoticed 8340 8341 Notification.Builder nb4 = new Notification.Builder(mContext, "") 8342 .setStyle(new Notification.InboxStyle() 8343 .addLine("line1").addLine("line2").addLine("line3")); 8344 StatusBarNotification sbn4 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8345 nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8346 NotificationRecord r4 = 8347 new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class)); 8348 8349 assertTrue(mService.isVisuallyInterruptive(r1, r4)); // line 3 added unnoticed 8350 8351 Notification.Builder nb5 = new Notification.Builder(mContext, "") 8352 .setContentText("not an inbox"); 8353 StatusBarNotification sbn5 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8354 nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8355 NotificationRecord r5 = 8356 new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class)); 8357 8358 assertTrue(mService.isVisuallyInterruptive(r1, r5)); // changed Styles, went unnoticed 8359 } 8360 8361 @Test testVisualDifference_diffText()8362 public void testVisualDifference_diffText() { 8363 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8364 .setContentText("foo"); 8365 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8366 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8367 NotificationRecord r1 = 8368 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8369 8370 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8371 .setContentText("bar"); 8372 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8373 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8374 NotificationRecord r2 = 8375 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8376 8377 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8378 } 8379 8380 @Test testVisualDifference_sameText()8381 public void testVisualDifference_sameText() { 8382 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8383 .setContentText("foo"); 8384 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8385 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8386 NotificationRecord r1 = 8387 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8388 8389 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8390 .setContentText("foo"); 8391 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8392 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8393 NotificationRecord r2 = 8394 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8395 8396 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8397 } 8398 8399 @Test testVisualDifference_sameTextButStyled()8400 public void testVisualDifference_sameTextButStyled() { 8401 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8402 .setContentText(Html.fromHtml("<b>foo</b>")); 8403 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8404 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8405 NotificationRecord r1 = 8406 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8407 8408 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8409 .setContentText(Html.fromHtml("<b>foo</b>")); 8410 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8411 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8412 NotificationRecord r2 = 8413 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8414 8415 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8416 } 8417 8418 @Test testVisualDifference_diffTextButStyled()8419 public void testVisualDifference_diffTextButStyled() { 8420 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8421 .setContentText(Html.fromHtml("<b>foo</b>")); 8422 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8423 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8424 NotificationRecord r1 = 8425 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8426 8427 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8428 .setContentText(Html.fromHtml("<b>bar</b>")); 8429 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8430 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8431 NotificationRecord r2 = 8432 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8433 8434 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8435 } 8436 8437 @Test testVisualDifference_diffProgress()8438 public void testVisualDifference_diffProgress() { 8439 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8440 .setProgress(100, 90, false); 8441 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8442 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8443 NotificationRecord r1 = 8444 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8445 8446 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8447 .setProgress(100, 100, false); 8448 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8449 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8450 NotificationRecord r2 = 8451 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8452 8453 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8454 } 8455 8456 @Test testVisualDifference_diffProgressNotDone()8457 public void testVisualDifference_diffProgressNotDone() { 8458 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8459 .setProgress(100, 90, false); 8460 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8461 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8462 NotificationRecord r1 = 8463 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8464 8465 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8466 .setProgress(100, 91, false); 8467 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8468 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8469 NotificationRecord r2 = 8470 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8471 8472 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8473 } 8474 8475 @Test testVisualDifference_sameProgressStillDone()8476 public void testVisualDifference_sameProgressStillDone() { 8477 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8478 .setProgress(100, 100, false); 8479 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8480 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8481 NotificationRecord r1 = 8482 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8483 8484 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8485 .setProgress(100, 100, false); 8486 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8487 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8488 NotificationRecord r2 = 8489 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8490 8491 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8492 } 8493 8494 @Test testVisualDifference_summary()8495 public void testVisualDifference_summary() { 8496 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8497 .setGroup("bananas") 8498 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 8499 .setContentText("foo"); 8500 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8501 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8502 NotificationRecord r1 = 8503 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8504 8505 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8506 .setGroup("bananas") 8507 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 8508 .setContentText("bar"); 8509 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8510 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8511 NotificationRecord r2 = 8512 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8513 8514 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8515 } 8516 8517 @Test testVisualDifference_summaryNewNotification()8518 public void testVisualDifference_summaryNewNotification() { 8519 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8520 .setGroup("bananas") 8521 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 8522 .setContentText("bar"); 8523 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8524 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8525 NotificationRecord r2 = 8526 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8527 8528 assertFalse(mService.isVisuallyInterruptive(null, r2)); 8529 } 8530 8531 @Test testVisualDifference_sameImages()8532 public void testVisualDifference_sameImages() { 8533 Icon large = Icon.createWithResource(mContext, 1); 8534 Notification n1 = new Notification.Builder(mContext, "channel") 8535 .setSmallIcon(1).setLargeIcon(large).build(); 8536 Notification n2 = new Notification.Builder(mContext, "channel") 8537 .setSmallIcon(1).setLargeIcon(large).build(); 8538 8539 NotificationRecord r1 = notificationToRecord(n1); 8540 NotificationRecord r2 = notificationToRecord(n2); 8541 8542 assertThat(mService.isVisuallyInterruptive(r1, r2)).isFalse(); 8543 } 8544 8545 @Test testVisualDifference_differentSmallImage()8546 public void testVisualDifference_differentSmallImage() { 8547 Icon large = Icon.createWithResource(mContext, 1); 8548 Notification n1 = new Notification.Builder(mContext, "channel") 8549 .setSmallIcon(1).setLargeIcon(large).build(); 8550 Notification n2 = new Notification.Builder(mContext, "channel") 8551 .setSmallIcon(2).setLargeIcon(large).build(); 8552 8553 NotificationRecord r1 = notificationToRecord(n1); 8554 NotificationRecord r2 = notificationToRecord(n2); 8555 8556 assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue(); 8557 } 8558 8559 @Test testVisualDifference_differentLargeImage()8560 public void testVisualDifference_differentLargeImage() { 8561 Icon large1 = Icon.createWithResource(mContext, 1); 8562 Icon large2 = Icon.createWithResource(mContext, 2); 8563 Notification n1 = new Notification.Builder(mContext, "channel") 8564 .setSmallIcon(1).setLargeIcon(large1).build(); 8565 Notification n2 = new Notification.Builder(mContext, "channel") 8566 .setSmallIcon(1).setLargeIcon(large2).build(); 8567 8568 NotificationRecord r1 = notificationToRecord(n1); 8569 NotificationRecord r2 = notificationToRecord(n2); 8570 8571 assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue(); 8572 } 8573 8574 @Test 8575 @EnableFlags({android.app.Flags.FLAG_SORT_SECTION_BY_TIME}) testVisualDifference_userInitiatedJob()8576 public void testVisualDifference_userInitiatedJob() { 8577 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8578 .setContentTitle("foo"); 8579 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8580 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8581 NotificationRecord r1 = 8582 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8583 8584 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8585 .setFlag(FLAG_USER_INITIATED_JOB, true) 8586 .setContentTitle("bar"); 8587 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8588 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8589 NotificationRecord r2 = 8590 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8591 8592 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8593 } 8594 notificationToRecord(Notification n)8595 private NotificationRecord notificationToRecord(Notification n) { 8596 return new NotificationRecord( 8597 mContext, 8598 new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, n, 8599 UserHandle.getUserHandleForUid(mUid), null, 0), 8600 mock(NotificationChannel.class)); 8601 } 8602 8603 @Test testHideAndUnhideNotificationsOnSuspendedPackageBroadcast()8604 public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() { 8605 // post 2 notification from this package 8606 final NotificationRecord notif1 = generateNotificationRecord( 8607 mTestNotificationChannel, 1, null, true); 8608 final NotificationRecord notif2 = generateNotificationRecord( 8609 mTestNotificationChannel, 2, null, false); 8610 mService.addNotification(notif1); 8611 mService.addNotification(notif2); 8612 8613 // on broadcast, hide the 2 notifications 8614 simulatePackageSuspendBroadcast(true, mPkg, notif1.getUid()); 8615 ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class); 8616 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 8617 assertEquals(2, captorHide.getValue().size()); 8618 8619 // on broadcast, unhide the 2 notifications 8620 simulatePackageSuspendBroadcast(false, mPkg, notif1.getUid()); 8621 ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class); 8622 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 8623 assertEquals(2, captorUnhide.getValue().size()); 8624 } 8625 8626 @Test testNoNotificationsHiddenOnSuspendedPackageBroadcast()8627 public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() { 8628 // post 2 notification from this package 8629 final NotificationRecord notif1 = generateNotificationRecord( 8630 mTestNotificationChannel, 1, null, true); 8631 final NotificationRecord notif2 = generateNotificationRecord( 8632 mTestNotificationChannel, 2, null, false); 8633 mService.addNotification(notif1); 8634 mService.addNotification(notif2); 8635 8636 // on broadcast, nothing is hidden since no notifications are of package "test_package" 8637 simulatePackageSuspendBroadcast(true, "test_package", notif1.getUid()); 8638 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 8639 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 8640 assertEquals(0, captor.getValue().size()); 8641 } 8642 8643 @Test testNotificationFromDifferentUserHidden()8644 public void testNotificationFromDifferentUserHidden() { 8645 // post 2 notification from this package 8646 final NotificationRecord notif1 = generateNotificationRecord( 8647 mTestNotificationChannel, 1, null, true); 8648 final NotificationRecord notif2 = generateNotificationRecord( 8649 mTestNotificationChannel, 2, null, false); 8650 mService.addNotification(notif1); 8651 mService.addNotification(notif2); 8652 8653 // on broadcast, nothing is hidden since no notifications are of user 10 with package PKG 8654 simulatePackageSuspendBroadcast(true, mPkg, 10); 8655 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 8656 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 8657 assertEquals(0, captor.getValue().size()); 8658 } 8659 8660 @Test testHideAndUnhideNotificationsOnDistractingPackageBroadcast()8661 public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() { 8662 // Post 2 notifications from 2 packages 8663 NotificationRecord pkgA = new NotificationRecord(mContext, 8664 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 8665 mService.addNotification(pkgA); 8666 NotificationRecord pkgB = new NotificationRecord(mContext, 8667 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 8668 mService.addNotification(pkgB); 8669 8670 // on broadcast, hide one of the packages 8671 simulatePackageDistractionBroadcast( 8672 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"}, 8673 new int[] {1000}); 8674 ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class); 8675 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 8676 assertEquals(1, captorHide.getValue().size()); 8677 assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName()); 8678 8679 // on broadcast, unhide the package 8680 simulatePackageDistractionBroadcast( 8681 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"}, 8682 new int[] {1000}); 8683 ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class); 8684 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 8685 assertEquals(1, captorUnhide.getValue().size()); 8686 assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName()); 8687 } 8688 8689 @Test testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg()8690 public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() { 8691 // Post 2 notifications from 2 packages 8692 NotificationRecord pkgA = new NotificationRecord(mContext, 8693 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 8694 mService.addNotification(pkgA); 8695 NotificationRecord pkgB = new NotificationRecord(mContext, 8696 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 8697 mService.addNotification(pkgB); 8698 8699 // on broadcast, hide one of the packages 8700 simulatePackageDistractionBroadcast( 8701 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"}, 8702 new int[] {1000, 1001}); 8703 ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class); 8704 8705 // should be called only once. 8706 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 8707 assertEquals(2, captorHide.getValue().size()); 8708 assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName()); 8709 assertEquals("b", captorHide.getValue().get(1).getSbn().getPackageName()); 8710 8711 // on broadcast, unhide the package 8712 simulatePackageDistractionBroadcast( 8713 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"}, 8714 new int[] {1000, 1001}); 8715 ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class); 8716 8717 // should be called only once. 8718 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 8719 assertEquals(2, captorUnhide.getValue().size()); 8720 assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName()); 8721 assertEquals("b", captorUnhide.getValue().get(1).getSbn().getPackageName()); 8722 } 8723 8724 @Test testNoNotificationsHiddenOnDistractingPackageBroadcast()8725 public void testNoNotificationsHiddenOnDistractingPackageBroadcast() { 8726 // post notification from this package 8727 final NotificationRecord notif1 = generateNotificationRecord( 8728 mTestNotificationChannel, 1, null, true); 8729 mService.addNotification(notif1); 8730 8731 // on broadcast, nothing is hidden since no notifications are of package "test_package" 8732 simulatePackageDistractionBroadcast( 8733 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"}, 8734 new int[]{notif1.getUid()}); 8735 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 8736 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 8737 assertEquals(0, captor.getValue().size()); 8738 } 8739 8740 @Test testCanUseManagedServicesNullPkg()8741 public void testCanUseManagedServicesNullPkg() { 8742 assertEquals(true, mService.canUseManagedServices(null, 0, null)); 8743 } 8744 8745 8746 @Test testCanUseManagedServicesNoValidPkg()8747 public void testCanUseManagedServicesNoValidPkg() { 8748 assertEquals(true, mService.canUseManagedServices("d", 0, null)); 8749 } 8750 8751 @Test testCanUseManagedServices_hasPermission()8752 public void testCanUseManagedServices_hasPermission() throws Exception { 8753 when(mPackageManager.checkPermission("perm", "pkg", 0)) 8754 .thenReturn(PackageManager.PERMISSION_GRANTED); 8755 8756 assertEquals(true, mService.canUseManagedServices("pkg", 0, "perm")); 8757 } 8758 8759 @Test testCanUseManagedServices_noPermission()8760 public void testCanUseManagedServices_noPermission() throws Exception { 8761 when(mPackageManager.checkPermission("perm", "pkg", 0)) 8762 .thenReturn(PackageManager.PERMISSION_DENIED); 8763 8764 assertEquals(false, mService.canUseManagedServices("pkg", 0, "perm")); 8765 } 8766 8767 @Test testCanUseManagedServices_permDoesNotMatter()8768 public void testCanUseManagedServices_permDoesNotMatter() { 8769 assertEquals(true, mService.canUseManagedServices("pkg", 0, null)); 8770 } 8771 8772 @Test testOnNotificationVisibilityChanged_triggersInterruptionUsageStat()8773 public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() { 8774 final NotificationRecord r = generateNotificationRecord( 8775 mTestNotificationChannel, 1, null, true); 8776 r.setTextChanged(true); 8777 mService.addNotification(r); 8778 8779 mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[] 8780 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}, 8781 new NotificationVisibility[]{}); 8782 8783 verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt()); 8784 } 8785 8786 @Test testOnNotificationVisibilityChanged_triggersVisibilityLog()8787 public void testOnNotificationVisibilityChanged_triggersVisibilityLog() { 8788 final NotificationRecord r = generateNotificationRecord( 8789 mTestNotificationChannel, 1, null, true); 8790 r.setTextChanged(true); 8791 r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 8792 mService.addNotification(r); 8793 8794 mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[] 8795 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}, 8796 new NotificationVisibility[]{}); 8797 8798 assertEquals(1, mNotificationRecordLogger.numCalls()); 8799 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN, 8800 mNotificationRecordLogger.event(0)); 8801 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 8802 8803 mService.mNotificationDelegate.onNotificationVisibilityChanged( 8804 new NotificationVisibility[]{}, 8805 new NotificationVisibility[] 8806 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)} 8807 ); 8808 8809 assertEquals(2, mNotificationRecordLogger.numCalls()); 8810 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE, 8811 mNotificationRecordLogger.event(1)); 8812 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 8813 } 8814 8815 @Test testSetNotificationsShownFromListener_triggersInterruptionUsageStat()8816 public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat() 8817 throws RemoteException { 8818 final NotificationRecord r = generateNotificationRecord( 8819 mTestNotificationChannel, 1, null, true); 8820 r.setTextChanged(true); 8821 mService.addNotification(r); 8822 8823 mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()}); 8824 8825 verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt()); 8826 } 8827 8828 @Test testSetNotificationsShownFromListener_protectsCrossUserInformation()8829 public void testSetNotificationsShownFromListener_protectsCrossUserInformation() 8830 throws RemoteException { 8831 Notification.Builder nb = new Notification.Builder( 8832 mContext, mTestNotificationChannel.getId()) 8833 .setContentTitle("foo") 8834 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8835 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 8836 "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, 8837 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), 8838 null, 0); 8839 final NotificationRecord r = 8840 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8841 r.setTextChanged(true); 8842 mService.addNotification(r); 8843 8844 // no security exception! 8845 mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()}); 8846 8847 verify(mAppUsageStats, never()).reportInterruptiveNotification( 8848 anyString(), anyString(), anyInt()); 8849 } 8850 8851 @Test testCancelNotificationsFromListener_protectsCrossUserInformation()8852 public void testCancelNotificationsFromListener_protectsCrossUserInformation() 8853 throws RemoteException { 8854 Notification.Builder nb = new Notification.Builder( 8855 mContext, mTestNotificationChannel.getId()) 8856 .setContentTitle("foo") 8857 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8858 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 8859 "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, 8860 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), 8861 null, 0); 8862 final NotificationRecord r = 8863 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8864 r.setTextChanged(true); 8865 mService.addNotification(r); 8866 8867 // no security exception! 8868 mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()}); 8869 8870 waitForIdle(); 8871 assertEquals(1, mService.getNotificationRecordCount()); 8872 } 8873 8874 @Test testMaybeRecordInterruptionLocked_doesNotRecordTwice()8875 public void testMaybeRecordInterruptionLocked_doesNotRecordTwice() 8876 throws RemoteException { 8877 final NotificationRecord r = generateNotificationRecord( 8878 mTestNotificationChannel, 1, null, true); 8879 r.setInterruptive(true); 8880 mService.addNotification(r); 8881 8882 mService.maybeRecordInterruptionLocked(r); 8883 mService.maybeRecordInterruptionLocked(r); 8884 8885 verify(mAppUsageStats, times(1)).reportInterruptiveNotification( 8886 anyString(), anyString(), anyInt()); 8887 verify(mHistoryManager, times(1)).addNotification(any()); 8888 } 8889 8890 @Test testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()8891 public void testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory() 8892 throws RemoteException { 8893 final NotificationRecord r = generateNotificationRecord( 8894 mTestNotificationChannel, 1, null, true); 8895 r.setInterruptive(true); 8896 r.getSbn().getNotification().setSmallIcon(null); 8897 mService.addNotification(r); 8898 8899 mService.maybeRecordInterruptionLocked(r); 8900 8901 verify(mAppUsageStats, times(1)).reportInterruptiveNotification( 8902 anyString(), anyString(), anyInt()); 8903 verify(mHistoryManager, never()).addNotification(any()); 8904 } 8905 8906 @Test testBubble()8907 public void testBubble() throws Exception { 8908 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE); 8909 assertFalse(mBinderService.areBubblesAllowed(mPkg)); 8910 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 8911 BUBBLE_PREFERENCE_NONE); 8912 } 8913 8914 @Test testUserApprovedBubblesForPackageSelected()8915 public void testUserApprovedBubblesForPackageSelected() throws Exception { 8916 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_SELECTED); 8917 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 8918 BUBBLE_PREFERENCE_SELECTED); 8919 } 8920 8921 @Test testUserApprovedBubblesForPackageAll()8922 public void testUserApprovedBubblesForPackageAll() throws Exception { 8923 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_ALL); 8924 assertTrue(mBinderService.areBubblesAllowed(mPkg)); 8925 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 8926 BUBBLE_PREFERENCE_ALL); 8927 } 8928 8929 @Test testUserRejectsBubblesForPackage()8930 public void testUserRejectsBubblesForPackage() throws Exception { 8931 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE); 8932 assertFalse(mBinderService.areBubblesAllowed(mPkg)); 8933 } 8934 8935 @Test testAreBubblesEnabled()8936 public void testAreBubblesEnabled() throws Exception { 8937 Settings.Secure.putInt(mContext.getContentResolver(), 8938 Settings.Secure.NOTIFICATION_BUBBLES, 1); 8939 mService.mPreferencesHelper.updateBubblesEnabled(); 8940 assertTrue(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid))); 8941 } 8942 8943 @Test testAreBubblesEnabled_false()8944 public void testAreBubblesEnabled_false() throws Exception { 8945 Settings.Secure.putIntForUser(mContext.getContentResolver(), 8946 Settings.Secure.NOTIFICATION_BUBBLES, 0, UserHandle.getUserId(mUid)); 8947 mService.mPreferencesHelper.updateBubblesEnabled(); 8948 assertFalse(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid))); 8949 } 8950 8951 @Test testAreBubblesEnabled_exception()8952 public void testAreBubblesEnabled_exception() throws Exception { 8953 try { 8954 assertTrue(mBinderService.areBubblesEnabled( 8955 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE))); 8956 fail("Cannot call cross user without permission"); 8957 } catch (SecurityException e) { 8958 // pass 8959 } 8960 // cross user, with permission, no problem 8961 enableInteractAcrossUsers(); 8962 assertTrue(mBinderService.areBubblesEnabled( 8963 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE))); 8964 } 8965 8966 @Test testIsCallerInstantApp_primaryUser()8967 public void testIsCallerInstantApp_primaryUser() throws Exception { 8968 ApplicationInfo info = new ApplicationInfo(); 8969 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 8970 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 8971 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 8972 8973 assertTrue(mService.isCallerInstantApp(45770, 0)); 8974 8975 info.privateFlags = 0; 8976 assertFalse(mService.isCallerInstantApp(575370, 0)); 8977 } 8978 8979 @Test testIsCallerInstantApp_secondaryUser()8980 public void testIsCallerInstantApp_secondaryUser() throws Exception { 8981 ApplicationInfo info = new ApplicationInfo(); 8982 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 8983 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info); 8984 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null); 8985 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 8986 8987 assertTrue(mService.isCallerInstantApp(68638450, 10)); 8988 } 8989 8990 @Test testIsCallerInstantApp_userAllNotification()8991 public void testIsCallerInstantApp_userAllNotification() throws Exception { 8992 ApplicationInfo info = new ApplicationInfo(); 8993 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 8994 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(USER_SYSTEM))) 8995 .thenReturn(info); 8996 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 8997 8998 assertTrue(mService.isCallerInstantApp(45770, UserHandle.USER_ALL)); 8999 9000 info.privateFlags = 0; 9001 assertFalse(mService.isCallerInstantApp(575370, UserHandle.USER_ALL )); 9002 } 9003 9004 @Test testResolveNotificationUid_sameApp_nonSystemUser()9005 public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception { 9006 ApplicationInfo info = new ApplicationInfo(); 9007 info.uid = Binder.getCallingUid(); 9008 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info); 9009 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null); 9010 9011 int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10); 9012 9013 assertEquals(info.uid, actualUid); 9014 } 9015 9016 @Test testResolveNotificationUid_sameApp()9017 public void testResolveNotificationUid_sameApp() throws Exception { 9018 ApplicationInfo info = new ApplicationInfo(); 9019 info.uid = Binder.getCallingUid(); 9020 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 9021 9022 int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0); 9023 9024 assertEquals(info.uid, actualUid); 9025 } 9026 9027 @Test testResolveNotificationUid_sameAppDiffPackage()9028 public void testResolveNotificationUid_sameAppDiffPackage() throws Exception { 9029 ApplicationInfo info = new ApplicationInfo(); 9030 info.uid = Binder.getCallingUid(); 9031 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 9032 9033 int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0); 9034 9035 assertEquals(info.uid, actualUid); 9036 } 9037 9038 @Test testResolveNotificationUid_sameAppWrongUid()9039 public void testResolveNotificationUid_sameAppWrongUid() throws Exception { 9040 ApplicationInfo info = new ApplicationInfo(); 9041 info.uid = 1356347; 9042 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(info); 9043 9044 try { 9045 mService.resolveNotificationUid("caller", "caller", 9, 0); 9046 fail("Incorrect uid didn't throw security exception"); 9047 } catch (SecurityException e) { 9048 // yay 9049 } 9050 } 9051 9052 @Test testResolveNotificationUid_delegateAllowed()9053 public void testResolveNotificationUid_delegateAllowed() throws Exception { 9054 int expectedUid = 123; 9055 9056 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid); 9057 mService.setPreferencesHelper(mPreferencesHelper); 9058 when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt())) 9059 .thenReturn(true); 9060 9061 assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0)); 9062 } 9063 9064 @Test testResolveNotificationUid_androidAllowed()9065 public void testResolveNotificationUid_androidAllowed() throws Exception { 9066 int expectedUid = 123; 9067 9068 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid); 9069 // no delegate 9070 9071 assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0)); 9072 } 9073 9074 @Test testPostFromAndroidForNonExistentPackage()9075 public void testPostFromAndroidForNonExistentPackage() throws Exception { 9076 final String notReal = "NOT REAL"; 9077 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())).thenThrow( 9078 PackageManager.NameNotFoundException.class); 9079 ApplicationInfo ai = new ApplicationInfo(); 9080 ai.uid = -1; 9081 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai); 9082 9083 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 9084 try { 9085 mInternalService.enqueueNotification(notReal, "android", 0, 0, 9086 "testPostFromAndroidForNonExistentPackage", 9087 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 9088 fail("can't post notifications for nonexistent packages, even if you exist"); 9089 } catch (SecurityException e) { 9090 // yay 9091 } 9092 } 9093 9094 @Test testCancelFromAndroidForNonExistentPackage()9095 public void testCancelFromAndroidForNonExistentPackage() throws Exception { 9096 final String notReal = "NOT REAL"; 9097 when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( 9098 PackageManager.NameNotFoundException.class); 9099 ApplicationInfo ai = new ApplicationInfo(); 9100 ai.uid = -1; 9101 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai); 9102 9103 // unlike the post case, ignore instead of throwing 9104 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 9105 9106 mInternalService.cancelNotification(notReal, "android", 0, 0, "tag", 9107 sbn.getId(), sbn.getUserId()); 9108 } 9109 9110 @Test testResolveNotificationUid_delegateNotAllowed()9111 public void testResolveNotificationUid_delegateNotAllowed() throws Exception { 9112 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123); 9113 // no delegate 9114 9115 try { 9116 mService.resolveNotificationUid("caller", "target", 9, 0); 9117 fail("Incorrect uid didn't throw security exception"); 9118 } catch (SecurityException e) { 9119 // yay 9120 } 9121 } 9122 9123 @Test testRemoveForegroundServiceFlagFromNotification_enqueued()9124 public void testRemoveForegroundServiceFlagFromNotification_enqueued() { 9125 when(mAmi.applyForegroundServiceNotification( 9126 any(), anyString(), anyInt(), anyString(), anyInt())) 9127 .thenReturn(SHOW_IMMEDIATELY); 9128 Notification n = new Notification.Builder(mContext, "").build(); 9129 n.flags |= FLAG_FOREGROUND_SERVICE; 9130 9131 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 9132 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9133 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9134 9135 mService.addEnqueuedNotification(r); 9136 9137 mInternalService.removeForegroundServiceFlagFromNotification( 9138 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9139 9140 waitForIdle(); 9141 9142 verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); 9143 } 9144 9145 @Test testRemoveForegroundServiceFlagFromNotification_posted()9146 public void testRemoveForegroundServiceFlagFromNotification_posted() { 9147 when(mAmi.applyForegroundServiceNotification( 9148 any(), anyString(), anyInt(), anyString(), anyInt())) 9149 .thenReturn(SHOW_IMMEDIATELY); 9150 Notification n = new Notification.Builder(mContext, "").build(); 9151 n.flags |= FLAG_FOREGROUND_SERVICE; 9152 9153 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 9154 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9155 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9156 9157 mService.addNotification(r); 9158 9159 mInternalService.removeForegroundServiceFlagFromNotification( 9160 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9161 9162 waitForIdle(); 9163 9164 ArgumentCaptor<NotificationRecord> captor = 9165 ArgumentCaptor.forClass(NotificationRecord.class); 9166 verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); 9167 9168 assertEquals(0, captor.getValue().getNotification().flags); 9169 } 9170 9171 @Test testCannotRemoveForegroundFlagWhenOverLimit_enqueued()9172 public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() { 9173 when(mAmi.applyForegroundServiceNotification( 9174 any(), anyString(), anyInt(), anyString(), anyInt())) 9175 .thenReturn(SHOW_IMMEDIATELY); 9176 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 9177 Notification n = new Notification.Builder(mContext, "").build(); 9178 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 9179 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9180 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9181 mService.addEnqueuedNotification(r); 9182 } 9183 Notification n = new Notification.Builder(mContext, "").build(); 9184 n.flags |= FLAG_FOREGROUND_SERVICE; 9185 9186 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9187 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 9188 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9189 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9190 9191 mService.addEnqueuedNotification(r); 9192 9193 mInternalService.removeForegroundServiceFlagFromNotification( 9194 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9195 9196 waitForIdle(); 9197 9198 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 9199 mService.getNotificationRecordCount()); 9200 } 9201 9202 @Test testCannotRemoveForegroundFlagWhenOverLimit_posted()9203 public void testCannotRemoveForegroundFlagWhenOverLimit_posted() { 9204 when(mAmi.applyForegroundServiceNotification( 9205 any(), anyString(), anyInt(), anyString(), anyInt())) 9206 .thenReturn(SHOW_IMMEDIATELY); 9207 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 9208 Notification n = new Notification.Builder(mContext, "").build(); 9209 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 9210 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9211 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9212 mService.addNotification(r); 9213 } 9214 Notification n = new Notification.Builder(mContext, "").build(); 9215 n.flags |= FLAG_FOREGROUND_SERVICE; 9216 9217 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9218 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 9219 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9220 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9221 9222 mService.addNotification(r); 9223 9224 mInternalService.removeForegroundServiceFlagFromNotification( 9225 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9226 9227 waitForIdle(); 9228 9229 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 9230 mService.getNotificationRecordCount()); 9231 } 9232 9233 @Test testAllowForegroundCustomToasts()9234 public void testAllowForegroundCustomToasts() throws Exception { 9235 final String testPackage = "testPackageName"; 9236 assertEquals(0, mService.mToastQueue.size()); 9237 mService.isSystemUid = false; 9238 mService.isSystemAppId = false; 9239 setToastRateIsWithinQuota(true); 9240 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9241 9242 // package is not suspended 9243 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9244 .thenReturn(false); 9245 9246 // notifications from this package are blocked by the user 9247 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 9248 9249 setAppInForegroundForToasts(mUid, true); 9250 9251 // enqueue toast -> toast should still enqueue 9252 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9253 assertEquals(1, mService.mToastQueue.size()); 9254 assertThat(wasEnqueued).isTrue(); 9255 } 9256 9257 @Test testDisallowBackgroundCustomToasts()9258 public void testDisallowBackgroundCustomToasts() throws Exception { 9259 final String testPackage = "testPackageName"; 9260 assertEquals(0, mService.mToastQueue.size()); 9261 mService.isSystemUid = false; 9262 mService.isSystemAppId = false; 9263 setToastRateIsWithinQuota(true); 9264 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9265 9266 // package is not suspended 9267 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9268 .thenReturn(false); 9269 9270 setAppInForegroundForToasts(mUid, false); 9271 9272 // enqueue toast -> no toasts enqueued 9273 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9274 assertEquals(0, mService.mToastQueue.size()); 9275 assertThat(wasEnqueued).isFalse(); 9276 } 9277 9278 @Test testDontCallShowToastAgainOnTheSameCustomToast()9279 public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception { 9280 final String testPackage = "testPackageName"; 9281 assertEquals(0, mService.mToastQueue.size()); 9282 mService.isSystemUid = false; 9283 mService.isSystemAppId = false; 9284 setToastRateIsWithinQuota(true); 9285 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9286 9287 // package is not suspended 9288 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9289 .thenReturn(false); 9290 9291 setAppInForegroundForToasts(mUid, true); 9292 9293 Binder token = new Binder(); 9294 ITransientNotification callback = mock(ITransientNotification.class); 9295 INotificationManager nmService = (INotificationManager) mService.mService; 9296 9297 // first time trying to show the toast, showToast gets called 9298 enqueueToast(nmService, testPackage, token, callback); 9299 verify(callback, times(1)).show(any()); 9300 9301 // second time trying to show the same toast, showToast isn't called again (total number of 9302 // invocations stays at one) 9303 enqueueToast(nmService, testPackage, token, callback); 9304 verify(callback, times(1)).show(any()); 9305 } 9306 9307 @Test testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()9308 public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground() 9309 throws Exception { 9310 final String testPackage = "testPackageName"; 9311 assertEquals(0, mService.mToastQueue.size()); 9312 mService.isSystemUid = false; 9313 mService.isSystemAppId = false; 9314 setToastRateIsWithinQuota(false); // rate limit reached 9315 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9316 9317 // package is not suspended 9318 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9319 .thenReturn(false); 9320 9321 setAppInForegroundForToasts(mUid, true); 9322 9323 Binder token = new Binder(); 9324 ITransientNotification callback = mock(ITransientNotification.class); 9325 INotificationManager nmService = (INotificationManager) mService.mService; 9326 9327 enqueueToast(nmService, testPackage, token, callback); 9328 verify(callback, times(1)).show(any()); 9329 } 9330 9331 @Test testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()9332 public void testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground() 9333 throws Exception { 9334 final String testPackage = "testPackageName"; 9335 assertEquals(0, mService.mToastQueue.size()); 9336 mService.isSystemUid = false; 9337 mService.isSystemAppId = false; 9338 setToastRateIsWithinQuota(true); 9339 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9340 9341 // package is not suspended 9342 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9343 .thenReturn(false); 9344 9345 setAppInForegroundForToasts(mUid, true); 9346 9347 Binder token1 = new Binder(); 9348 Binder token2 = new Binder(); 9349 ITransientNotification callback1 = mock(ITransientNotification.class); 9350 ITransientNotification callback2 = mock(ITransientNotification.class); 9351 INotificationManager nmService = (INotificationManager) mService.mService; 9352 9353 enqueueToast(nmService, testPackage, token1, callback1); 9354 enqueueToast(nmService, testPackage, token2, callback2); 9355 9356 assertEquals(2, mService.mToastQueue.size()); // Both toasts enqueued. 9357 verify(callback1, times(1)).show(any()); // First toast shown. 9358 9359 setAppInForegroundForToasts(mUid, false); 9360 9361 mService.cancelToastLocked(0); // Remove the first toast, and show next. 9362 9363 assertEquals(0, mService.mToastQueue.size()); // Both toasts processed. 9364 verify(callback2, never()).show(any()); // Second toast was never shown. 9365 } 9366 9367 @Test testAllowForegroundTextToasts()9368 public void testAllowForegroundTextToasts() throws Exception { 9369 final String testPackage = "testPackageName"; 9370 assertEquals(0, mService.mToastQueue.size()); 9371 mService.isSystemUid = false; 9372 mService.isSystemAppId = false; 9373 setToastRateIsWithinQuota(true); 9374 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9375 9376 // package is not suspended 9377 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9378 .thenReturn(false); 9379 9380 setAppInForegroundForToasts(mUid, true); 9381 9382 // enqueue toast -> toast should still enqueue 9383 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9384 assertEquals(1, mService.mToastQueue.size()); 9385 assertThat(wasEnqueued).isTrue(); 9386 } 9387 9388 @Test testAllowBackgroundTextToasts()9389 public void testAllowBackgroundTextToasts() throws Exception { 9390 final String testPackage = "testPackageName"; 9391 assertEquals(0, mService.mToastQueue.size()); 9392 mService.isSystemUid = false; 9393 mService.isSystemAppId = false; 9394 setToastRateIsWithinQuota(true); 9395 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9396 9397 // package is not suspended 9398 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9399 .thenReturn(false); 9400 9401 setAppInForegroundForToasts(mUid, false); 9402 9403 // enqueue toast -> toast should still enqueue 9404 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9405 assertEquals(1, mService.mToastQueue.size()); 9406 assertThat(wasEnqueued).isTrue(); 9407 } 9408 9409 @Test testDontCallShowToastAgainOnTheSameTextToast()9410 public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception { 9411 final String testPackage = "testPackageName"; 9412 assertEquals(0, mService.mToastQueue.size()); 9413 mService.isSystemUid = false; 9414 mService.isSystemAppId = false; 9415 setToastRateIsWithinQuota(true); 9416 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9417 9418 // package is not suspended 9419 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9420 .thenReturn(false); 9421 9422 setAppInForegroundForToasts(mUid, true); 9423 9424 Binder token = new Binder(); 9425 INotificationManager nmService = (INotificationManager) mService.mService; 9426 9427 // first time trying to show the toast, showToast gets called 9428 enqueueTextToast(testPackage, "Text"); 9429 verify(mStatusBar, times(1)) 9430 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9431 9432 // second time trying to show the same toast, showToast isn't called again (total number of 9433 // invocations stays at one) 9434 enqueueTextToast(testPackage, "Text"); 9435 verify(mStatusBar, times(1)) 9436 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9437 } 9438 9439 @Test testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()9440 public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground() 9441 throws Exception { 9442 final String testPackage = "testPackageName"; 9443 assertEquals(0, mService.mToastQueue.size()); 9444 mService.isSystemUid = false; 9445 mService.isSystemAppId = false; 9446 setToastRateIsWithinQuota(false); // rate limit reached 9447 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9448 setAppInForegroundForToasts(mUid, false); 9449 9450 // package is not suspended 9451 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9452 .thenReturn(false); 9453 9454 Binder token = new Binder(); 9455 INotificationManager nmService = (INotificationManager) mService.mService; 9456 9457 enqueueTextToast(testPackage, "Text"); 9458 verify(mStatusBar, times(0)) 9459 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9460 } 9461 9462 @Test testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()9463 public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground() 9464 throws Exception { 9465 final String testPackage = "testPackageName"; 9466 assertEquals(0, mService.mToastQueue.size()); 9467 mService.isSystemUid = false; 9468 mService.isSystemAppId = false; 9469 setToastRateIsWithinQuota(false); // rate limit reached 9470 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9471 setAppInForegroundForToasts(mUid, true); 9472 9473 // package is not suspended 9474 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9475 .thenReturn(false); 9476 9477 Binder token = new Binder(); 9478 INotificationManager nmService = (INotificationManager) mService.mService; 9479 9480 enqueueTextToast(testPackage, "Text"); 9481 verify(mStatusBar, times(1)) 9482 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9483 } 9484 9485 @Test testTextToastRateLimiterAllowsLimitAvoidanceWithPermission()9486 public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception { 9487 final String testPackage = "testPackageName"; 9488 assertEquals(0, mService.mToastQueue.size()); 9489 mService.isSystemUid = false; 9490 mService.isSystemAppId = false; 9491 setToastRateIsWithinQuota(false); // rate limit reached 9492 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true); 9493 setAppInForegroundForToasts(mUid, false); 9494 9495 // package is not suspended 9496 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9497 .thenReturn(false); 9498 9499 Binder token = new Binder(); 9500 INotificationManager nmService = (INotificationManager) mService.mService; 9501 9502 enqueueTextToast(testPackage, "Text"); 9503 verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 9504 anyInt()); 9505 } 9506 9507 @Test testRateLimitedToasts_windowsRemoved()9508 public void testRateLimitedToasts_windowsRemoved() throws Exception { 9509 final String testPackage = "testPackageName"; 9510 assertEquals(0, mService.mToastQueue.size()); 9511 mService.isSystemUid = false; 9512 mService.isSystemAppId = false; 9513 setToastRateIsWithinQuota(false); // rate limit reached 9514 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9515 setAppInForegroundForToasts(mUid, false); 9516 9517 // package is not suspended 9518 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9519 .thenReturn(false); 9520 9521 Binder token = new Binder(); 9522 INotificationManager nmService = (INotificationManager) mService.mService; 9523 9524 enqueueTextToast(testPackage, "Text"); 9525 9526 // window token was added when enqueued 9527 ArgumentCaptor<Binder> binderCaptor = 9528 ArgumentCaptor.forClass(Binder.class); 9529 verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(), 9530 eq(TYPE_TOAST), anyInt(), eq(null)); 9531 9532 // but never shown 9533 verify(mStatusBar, times(0)) 9534 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9535 9536 // and removed when rate limited 9537 verify(mWindowManagerInternal) 9538 .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt()); 9539 } 9540 9541 @Test backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast()9542 public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws 9543 Exception { 9544 final String testPackage = "testPackageName"; 9545 assertEquals(0, mService.mToastQueue.size()); 9546 mService.isSystemUid = true; 9547 setToastRateIsWithinQuota(true); 9548 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9549 9550 // package is not suspended 9551 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9552 .thenReturn(false); 9553 9554 // notifications from this package are blocked by the user 9555 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 9556 9557 setAppInForegroundForToasts(mUid, false); 9558 9559 // enqueue toast -> toast should still enqueue 9560 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9561 assertEquals(1, mService.mToastQueue.size()); 9562 assertThat(wasEnqueued).isTrue(); 9563 verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any()); 9564 } 9565 9566 @Test foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9567 public void foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws 9568 Exception { 9569 final String testPackage = "testPackageName"; 9570 assertEquals(0, mService.mToastQueue.size()); 9571 mService.isSystemUid = false; 9572 mService.isSystemAppId = false; 9573 setToastRateIsWithinQuota(true); 9574 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9575 9576 // package is not suspended 9577 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9578 .thenReturn(false); 9579 9580 setAppInForegroundForToasts(mUid, true); 9581 9582 // enqueue toast -> toast should still enqueue 9583 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9584 assertEquals(1, mService.mToastQueue.size()); 9585 assertThat(wasEnqueued).isTrue(); 9586 verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); 9587 } 9588 9589 @Test backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9590 public void backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws 9591 Exception { 9592 final String testPackage = "testPackageName"; 9593 assertEquals(0, mService.mToastQueue.size()); 9594 mService.isSystemUid = false; 9595 mService.isSystemAppId = false; 9596 setToastRateIsWithinQuota(true); 9597 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9598 9599 // package is not suspended 9600 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9601 .thenReturn(false); 9602 9603 setAppInForegroundForToasts(mUid, false); 9604 9605 // enqueue toast -> toast should still enqueue 9606 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9607 assertEquals(1, mService.mToastQueue.size()); 9608 assertThat(wasEnqueued).isTrue(); 9609 verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); 9610 } 9611 9612 @Test testTextToastsCallStatusBar()9613 public void testTextToastsCallStatusBar() throws Exception { 9614 allowTestPackageToToast(); 9615 9616 // enqueue toast -> no toasts enqueued 9617 boolean wasEnqueued = enqueueTextToast(TEST_PACKAGE, "Text"); 9618 assertThat(wasEnqueued).isTrue(); 9619 9620 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 9621 } 9622 9623 @Test testTextToastsCallStatusBar_nonUiContext_defaultDisplay()9624 public void testTextToastsCallStatusBar_nonUiContext_defaultDisplay() 9625 throws Exception { 9626 allowTestPackageToToast(); 9627 9628 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); 9629 9630 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 9631 } 9632 9633 @Test testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()9634 public void testTextToastsCallStatusBar_nonUiContext_secondaryDisplay() 9635 throws Exception { 9636 allowTestPackageToToast(); 9637 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9638 9639 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); 9640 9641 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9642 } 9643 9644 @Test testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()9645 public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay() 9646 throws Exception { 9647 mockIsVisibleBackgroundUsersSupported(true); 9648 mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); 9649 allowTestPackageToToast(); 9650 9651 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, DEFAULT_DISPLAY); 9652 9653 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 9654 9655 } 9656 9657 @Test testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()9658 public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay() 9659 throws Exception { 9660 mockIsVisibleBackgroundUsersSupported(true); 9661 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9662 mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used 9663 allowTestPackageToToast(); 9664 9665 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, SECONDARY_DISPLAY_ID); 9666 9667 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9668 } 9669 9670 @Test testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()9671 public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay() 9672 throws Exception { 9673 mockIsVisibleBackgroundUsersSupported(true); 9674 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9675 mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); 9676 allowTestPackageToToast(); 9677 9678 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); 9679 9680 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9681 } 9682 9683 @Test testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()9684 public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay() 9685 throws Exception { 9686 mockIsVisibleBackgroundUsersSupported(true); 9687 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9688 mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used 9689 allowTestPackageToToast(); 9690 9691 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); 9692 9693 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9694 } 9695 9696 @Test testTextToastsCallStatusBar_userNotVisibleOnDisplay()9697 public void testTextToastsCallStatusBar_userNotVisibleOnDisplay() throws Exception { 9698 final String testPackage = "testPackageName"; 9699 assertEquals(0, mService.mToastQueue.size()); 9700 mService.isSystemUid = false; 9701 mService.isSystemAppId = false; 9702 setToastRateIsWithinQuota(true); 9703 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9704 mockIsUserVisible(DEFAULT_DISPLAY, false); 9705 9706 // package is not suspended 9707 when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) 9708 .thenReturn(false); 9709 9710 // enqueue toast -> no toasts enqueued 9711 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9712 verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 9713 anyInt()); 9714 assertEquals(0, mService.mToastQueue.size()); 9715 assertThat(wasEnqueued).isFalse(); 9716 } 9717 9718 @Test testDisallowToastsFromSuspendedPackages()9719 public void testDisallowToastsFromSuspendedPackages() throws Exception { 9720 final String testPackage = "testPackageName"; 9721 assertEquals(0, mService.mToastQueue.size()); 9722 mService.isSystemUid = false; 9723 mService.isSystemAppId = false; 9724 setToastRateIsWithinQuota(true); 9725 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9726 9727 // package is suspended 9728 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9729 .thenReturn(true); 9730 9731 // notifications from this package are NOT blocked by the user 9732 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 9733 9734 // enqueue toast -> no toasts enqueued 9735 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9736 verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 9737 anyInt()); 9738 assertEquals(0, mService.mToastQueue.size()); 9739 assertThat(wasEnqueued).isFalse(); 9740 } 9741 9742 @Test testDisallowToastsFromBlockedApps()9743 public void testDisallowToastsFromBlockedApps() throws Exception { 9744 final String testPackage = "testPackageName"; 9745 assertEquals(0, mService.mToastQueue.size()); 9746 mService.isSystemUid = false; 9747 mService.isSystemAppId = false; 9748 setToastRateIsWithinQuota(true); 9749 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9750 9751 // package is not suspended 9752 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9753 .thenReturn(false); 9754 9755 // notifications from this package are blocked by the user 9756 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 9757 9758 setAppInForegroundForToasts(mUid, false); 9759 9760 // enqueue toast -> no toasts enqueued 9761 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9762 assertEquals(0, mService.mToastQueue.size()); 9763 assertThat(wasEnqueued).isFalse(); 9764 } 9765 9766 @Test testAlwaysAllowSystemToasts()9767 public void testAlwaysAllowSystemToasts() throws Exception { 9768 final String testPackage = "testPackageName"; 9769 assertEquals(0, mService.mToastQueue.size()); 9770 mService.isSystemUid = true; 9771 setToastRateIsWithinQuota(true); 9772 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9773 9774 // package is suspended 9775 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9776 .thenReturn(true); 9777 9778 // notifications from this package ARE blocked by the user 9779 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 9780 9781 setAppInForegroundForToasts(mUid, false); 9782 9783 // enqueue toast -> system toast can still be enqueued 9784 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9785 assertEquals(1, mService.mToastQueue.size()); 9786 assertThat(wasEnqueued).isTrue(); 9787 } 9788 9789 @Test testLimitNumberOfQueuedToastsFromPackage()9790 public void testLimitNumberOfQueuedToastsFromPackage() throws Exception { 9791 final String testPackage = "testPackageName"; 9792 assertEquals(0, mService.mToastQueue.size()); 9793 mService.isSystemUid = false; 9794 mService.isSystemAppId = false; 9795 setToastRateIsWithinQuota(true); 9796 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9797 9798 // package is not suspended 9799 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9800 .thenReturn(false); 9801 9802 INotificationManager nmService = (INotificationManager) mService.mService; 9803 9804 // Trying to quickly enqueue more toast than allowed. 9805 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) { 9806 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9807 if (i < NotificationManagerService.MAX_PACKAGE_TOASTS) { 9808 assertThat(wasEnqueued).isTrue(); 9809 } else { 9810 assertThat(wasEnqueued).isFalse(); 9811 } 9812 } 9813 // Only allowed number enqueued, rest ignored. 9814 assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size()); 9815 } 9816 9817 @Test testPrioritizeSystemToasts()9818 public void testPrioritizeSystemToasts() throws Exception { 9819 // Insert non-system toasts 9820 final String testPackage = "testPackageName"; 9821 assertEquals(0, mService.mToastQueue.size()); 9822 mService.isSystemUid = false; 9823 mService.isSystemAppId = false; 9824 setToastRateIsWithinQuota(true); 9825 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9826 9827 // package is not suspended 9828 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9829 .thenReturn(false); 9830 9831 INotificationManager nmService = (INotificationManager) mService.mService; 9832 9833 // Enqueue maximum number of toasts for test package 9834 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) { 9835 enqueueTextToast(testPackage, "Text"); 9836 } 9837 9838 // Enqueue system toast 9839 final String testPackageSystem = "testPackageNameSystem"; 9840 mService.isSystemUid = true; 9841 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem, false); 9842 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem, mUserId)) 9843 .thenReturn(false); 9844 9845 enqueueToast(testPackageSystem, new TestableToastCallback()); 9846 9847 // System toast is inserted at the front of the queue, behind current showing toast 9848 assertEquals(testPackageSystem, mService.mToastQueue.get(1).pkg); 9849 } 9850 9851 @Test testPrioritizeSystemToasts_enqueueAfterExistingSystemToast()9852 public void testPrioritizeSystemToasts_enqueueAfterExistingSystemToast() throws Exception { 9853 // Insert system toasts 9854 final String testPackageSystem1 = "testPackageNameSystem1"; 9855 assertEquals(0, mService.mToastQueue.size()); 9856 mService.isSystemUid = true; 9857 setToastRateIsWithinQuota(true); 9858 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem1, false); 9859 9860 // package is not suspended 9861 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem1, mUserId)) 9862 .thenReturn(false); 9863 9864 INotificationManager nmService = (INotificationManager) mService.mService; 9865 9866 // Enqueue maximum number of toasts for test package 9867 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) { 9868 enqueueTextToast(testPackageSystem1, "Text"); 9869 } 9870 9871 // Enqueue another system toast 9872 final String testPackageSystem2 = "testPackageNameSystem2"; 9873 mService.isSystemUid = true; 9874 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem2, false); 9875 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem2, mUserId)) 9876 .thenReturn(false); 9877 9878 enqueueToast(testPackageSystem2, new TestableToastCallback()); 9879 9880 // System toast is inserted at the back of the queue, after the other system toasts 9881 assertEquals(testPackageSystem2, 9882 mService.mToastQueue.get(mService.mToastQueue.size() - 1).pkg); 9883 } 9884 setAppInForegroundForToasts(int uid, boolean inForeground)9885 private void setAppInForegroundForToasts(int uid, boolean inForeground) { 9886 int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE; 9887 when(mActivityManager.getUidImportance(mUid)).thenReturn(importance); 9888 when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground); 9889 } 9890 setToastRateIsWithinQuota(boolean isWithinQuota)9891 private void setToastRateIsWithinQuota(boolean isWithinQuota) { 9892 when(mToastRateLimiter.isWithinQuota( 9893 anyInt(), 9894 anyString(), 9895 eq(NotificationManagerService.TOAST_QUOTA_TAG))) 9896 .thenReturn(isWithinQuota); 9897 } 9898 setIfPackageHasPermissionToAvoidToastRateLimiting( String pkg, boolean hasPermission)9899 private void setIfPackageHasPermissionToAvoidToastRateLimiting( 9900 String pkg, boolean hasPermission) throws Exception { 9901 when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS, 9902 pkg, mUserId)) 9903 .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED); 9904 } 9905 9906 @Test testOnPanelRevealedAndHidden()9907 public void testOnPanelRevealedAndHidden() { 9908 int items = 5; 9909 mService.mNotificationDelegate.onPanelRevealed(false, items); 9910 verify(mAssistants, times(1)).onPanelRevealed(eq(items)); 9911 9912 mService.mNotificationDelegate.onPanelHidden(); 9913 verify(mAssistants, times(1)).onPanelHidden(); 9914 9915 assertEquals(2, mNotificationRecordLogger.numCalls()); 9916 assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN, 9917 mNotificationRecordLogger.event(0)); 9918 assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE, 9919 mNotificationRecordLogger.event(1)); 9920 } 9921 9922 @Test 9923 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testOnNotificationSmartReplySent()9924 public void testOnNotificationSmartReplySent() { 9925 final int replyIndex = 2; 9926 final String reply = "Hello"; 9927 final boolean modifiedBeforeSending = true; 9928 final boolean generatedByAssistant = true; 9929 9930 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9931 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 9932 mService.addNotification(r); 9933 9934 mService.mNotificationDelegate.onNotificationSmartReplySent( 9935 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN, 9936 modifiedBeforeSending); 9937 verify(mAssistants).notifyAssistantSuggestedReplySent( 9938 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(reply), eq(generatedByAssistant)); 9939 assertEquals(1, mNotificationRecordLogger.numCalls()); 9940 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED, 9941 mNotificationRecordLogger.event(0)); 9942 // Check that r.recordSmartReplied was called. 9943 assertThat(r.getSbn().getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) 9944 .isGreaterThan(0); 9945 assertThat(r.getStats().hasSmartReplied()).isTrue(); 9946 } 9947 9948 @Test 9949 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate()9950 public void testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate() throws Exception { 9951 final int replyIndex = 2; 9952 final String reply = "Hello"; 9953 final boolean modifiedBeforeSending = true; 9954 9955 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9956 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 9957 r.getSbn().getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 9958 r.setSuggestionsGeneratedByAssistant(true); 9959 r.setCanceledAfterLifetimeExtension(true); 9960 r.setPostSilently(true); 9961 mService.addNotification(r); 9962 9963 mService.mNotificationDelegate.onNotificationSmartReplySent( 9964 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN, 9965 modifiedBeforeSending); 9966 waitForIdle(); 9967 9968 // At the moment prepareNotifyPostedLocked is called on the listeners, 9969 // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial 9970 // values. 9971 doAnswer( 9972 invocation -> { 9973 int flags = ((NotificationRecord) invocation.getArgument(0)) 9974 .getSbn().getNotification().flags; 9975 assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 9976 boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0)) 9977 .shouldPostSilently(); 9978 assertThat(shouldPostSilently).isTrue(); 9979 return null; 9980 } 9981 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 9982 9983 // Checks that a post update is sent. 9984 verify(mWorkerHandler, times(1)) 9985 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 9986 ArgumentCaptor<NotificationRecord> captor = 9987 ArgumentCaptor.forClass(NotificationRecord.class); 9988 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 9989 anyBoolean()); 9990 assertThat(captor.getValue().getNotification().flags 9991 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 9992 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 9993 // Flag was present before, so it's set afterward 9994 assertThat(captor.getValue().getNotification().flags 9995 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 9996 // Should post silently was set before, so it's set afterward. 9997 assertThat(captor.getValue().shouldPostSilently()).isTrue(); 9998 } 9999 10000 @Test testOnNotificationActionClick()10001 public void testOnNotificationActionClick() { 10002 final int actionIndex = 2; 10003 final Notification.Action action = 10004 new Notification.Action.Builder(null, "text", mActivityIntent).build(); 10005 final boolean generatedByAssistant = false; 10006 10007 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10008 mService.addNotification(r); 10009 10010 NotificationVisibility notificationVisibility = 10011 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10012 mService.mNotificationDelegate.onNotificationActionClick( 10013 10, 10, r.getKey(), actionIndex, action, notificationVisibility, 10014 generatedByAssistant); 10015 verify(mAssistants).notifyAssistantActionClicked( 10016 eq(r), eq(action), eq(generatedByAssistant)); 10017 10018 assertEquals(1, mNotificationRecordLogger.numCalls()); 10019 assertEquals( 10020 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED_2, 10021 mNotificationRecordLogger.event(0)); 10022 } 10023 10024 @Test 10025 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testActionClickLifetimeExtendedCancel()10026 public void testActionClickLifetimeExtendedCancel() throws Exception { 10027 final Notification.Action action = 10028 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 10029 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 10030 10031 // Creates a notification marked as being lifetime extended. 10032 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10033 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 10034 mService.addNotification(r); 10035 10036 StatusBarNotification[] notifs = 10037 mBinderService.getActiveNotifications(mPkg); 10038 assertThat(notifs.length).isEqualTo(1); 10039 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10040 10041 // Call on action click. 10042 NotificationVisibility notificationVisibility = 10043 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10044 mService.mNotificationDelegate.onNotificationActionClick( 10045 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 10046 /*generatedByAssistant=*/false); 10047 10048 // Lifetime extended flag persists. 10049 assertThat(r.getSbn().getNotification().flags 10050 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 10051 10052 mTestableLooper.moveTimeForward(210); 10053 waitForIdle(); 10054 verify(mWorkerHandler, times(1)) 10055 .scheduleCancelNotification( 10056 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 10057 10058 // Check that the cancelation occurred and the notification is gone. 10059 notifs = mBinderService.getActiveNotifications(mPkg); 10060 assertThat(notifs.length).isEqualTo(0); 10061 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 10062 } 10063 10064 @Test 10065 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testActionClickLifetimeExtendedCancel_PreventByNoDismiss()10066 public void testActionClickLifetimeExtendedCancel_PreventByNoDismiss() throws Exception { 10067 final Notification.Action action = 10068 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 10069 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 10070 10071 // Creates a notification marked as being lifetime extended. 10072 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10073 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 10074 // Make the notification non-dismissable 10075 r.getSbn().getNotification().flags |= FLAG_NO_DISMISS; 10076 mService.addNotification(r); 10077 10078 StatusBarNotification[] notifs = 10079 mBinderService.getActiveNotifications(mPkg); 10080 assertThat(notifs.length).isEqualTo(1); 10081 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10082 10083 // Call on action click. 10084 NotificationVisibility notificationVisibility = 10085 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10086 mService.mNotificationDelegate.onNotificationActionClick( 10087 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 10088 /*generatedByAssistant=*/false); 10089 10090 // Lifetime extended flag persists. 10091 assertThat(r.getSbn().getNotification().flags 10092 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 10093 10094 mTestableLooper.moveTimeForward(210); 10095 waitForIdle(); 10096 verify(mWorkerHandler, times(1)) 10097 .scheduleCancelNotification( 10098 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 10099 10100 // The cancellation is dropped and the notification is still present, with the update. 10101 notifs = mBinderService.getActiveNotifications(mPkg); 10102 assertThat(notifs.length).isEqualTo(1); 10103 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10104 } 10105 10106 @Test 10107 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testUpdateOnActionClickDropsLifetimeExtendedCancel()10108 public void testUpdateOnActionClickDropsLifetimeExtendedCancel() throws Exception { 10109 final Notification.Action action = 10110 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 10111 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 10112 10113 // Creates a notification marked as being lifetime extended. 10114 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10115 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 10116 mService.addNotification(r); 10117 10118 StatusBarNotification[] notifs = 10119 mBinderService.getActiveNotifications(mPkg); 10120 assertThat(notifs.length).isEqualTo(1); 10121 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10122 10123 // Call on action click. 10124 NotificationVisibility notificationVisibility = 10125 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10126 mService.mNotificationDelegate.onNotificationActionClick( 10127 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 10128 /*generatedByAssistant=*/false); 10129 10130 // The "app" sends an update of the notification in response. 10131 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 10132 r.getSbn().getId(), r.getSbn().getNotification(), r.getSbn().getUserId()); 10133 10134 mTestableLooper.moveTimeForward(210); 10135 waitForIdle(); 10136 verify(mWorkerHandler, times(1)) 10137 .scheduleCancelNotification( 10138 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 10139 10140 // The cancellation is dropped and the notification is still present, with the update. 10141 notifs = mBinderService.getActiveNotifications(mPkg); 10142 assertThat(notifs.length).isEqualTo(1); 10143 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10144 } 10145 10146 @Test testOnAssistantNotificationActionClick()10147 public void testOnAssistantNotificationActionClick() { 10148 final int actionIndex = 1; 10149 final Notification.Action action = 10150 new Notification.Action.Builder(null, "text", mActivityIntent).build(); 10151 final boolean generatedByAssistant = true; 10152 10153 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10154 mService.addNotification(r); 10155 10156 NotificationVisibility notificationVisibility = 10157 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10158 mService.mNotificationDelegate.onNotificationActionClick( 10159 10, 10, r.getKey(), actionIndex, action, notificationVisibility, 10160 generatedByAssistant); 10161 verify(mAssistants).notifyAssistantActionClicked( 10162 eq(r), eq(action), eq(generatedByAssistant)); 10163 10164 assertEquals(1, mNotificationRecordLogger.numCalls()); 10165 assertEquals( 10166 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ASSIST_ACTION_CLICKED_1, 10167 mNotificationRecordLogger.event(0)); 10168 } 10169 10170 10171 @Test testLogSmartSuggestionsVisible_triggerOnExpandAndVisible()10172 public void testLogSmartSuggestionsVisible_triggerOnExpandAndVisible() { 10173 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10174 mService.addNotification(r); 10175 10176 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 10177 NOTIFICATION_LOCATION_UNKNOWN); 10178 NotificationVisibility[] notificationVisibility = new NotificationVisibility[] { 10179 NotificationVisibility.obtain(r.getKey(), 0, 0, true) 10180 }; 10181 mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility, 10182 new NotificationVisibility[0]); 10183 10184 assertEquals(1, mService.countLogSmartSuggestionsVisible); 10185 } 10186 10187 @Test testLogSmartSuggestionsVisible_noTriggerOnExpand()10188 public void testLogSmartSuggestionsVisible_noTriggerOnExpand() { 10189 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10190 mService.addNotification(r); 10191 10192 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 10193 NOTIFICATION_LOCATION_UNKNOWN); 10194 10195 assertEquals(0, mService.countLogSmartSuggestionsVisible); 10196 } 10197 10198 @Test testLogSmartSuggestionsVisible_noTriggerOnVisible()10199 public void testLogSmartSuggestionsVisible_noTriggerOnVisible() { 10200 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10201 mService.addNotification(r); 10202 10203 NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{ 10204 NotificationVisibility.obtain(r.getKey(), 0, 0, true) 10205 }; 10206 mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility, 10207 new NotificationVisibility[0]); 10208 10209 assertEquals(0, mService.countLogSmartSuggestionsVisible); 10210 } 10211 10212 @Test testReportSeen_delegated()10213 public void testReportSeen_delegated() { 10214 Notification.Builder nb = 10215 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 10216 .setContentTitle("foo") 10217 .setSmallIcon(android.R.drawable.sym_def_app_icon); 10218 10219 StatusBarNotification sbn = new StatusBarNotification(mPkg, "opPkg", 0, "tag", mUid, 0, 10220 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10221 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10222 10223 mService.reportSeen(r); 10224 verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt()); 10225 10226 } 10227 10228 @Test testReportSeen_notDelegated()10229 public void testReportSeen_notDelegated() { 10230 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10231 10232 mService.reportSeen(r); 10233 verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt()); 10234 } 10235 10236 @Test testNotificationStats_notificationError()10237 public void testNotificationStats_notificationError() { 10238 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10239 mService.addNotification(r); 10240 10241 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, r.getSbn().getId(), 10242 r.getSbn().getTag(), mUid, 0, 10243 new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(), 10244 UserHandle.getUserHandleForUid(mUid), null, 0); 10245 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10246 mService.addEnqueuedNotification(update); 10247 assertNull(update.getSbn().getNotification().getSmallIcon()); 10248 10249 NotificationManagerService.PostNotificationRunnable runnable = 10250 mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(), 10251 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 10252 runnable.run(); 10253 waitForIdle(); 10254 10255 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 10256 verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture()); 10257 assertNotNull(captor.getValue()); 10258 } 10259 10260 @Test testCanNotifyAsUser_crossUser()10261 public void testCanNotifyAsUser_crossUser() throws Exception { 10262 // same user no problem 10263 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId()); 10264 10265 // cross user, no permission, problem 10266 try { 10267 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1); 10268 fail("Should not be callable cross user without cross user permission"); 10269 } catch (SecurityException e) { 10270 // good 10271 } 10272 10273 // cross user, with permission, no problem 10274 enableInteractAcrossUsers(); 10275 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1); 10276 } 10277 10278 @Test testGetNotificationChannels_crossUser()10279 public void testGetNotificationChannels_crossUser() throws Exception { 10280 // same user no problem 10281 mBinderService.getNotificationChannels("src", "target", mContext.getUserId()); 10282 10283 // cross user, no permission, problem 10284 try { 10285 mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1); 10286 fail("Should not be callable cross user without cross user permission"); 10287 } catch (SecurityException e) { 10288 // good 10289 } 10290 10291 // cross user, with permission, no problem 10292 enableInteractAcrossUsers(); 10293 mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1); 10294 } 10295 10296 @Test setDefaultAssistantForUser_fromConfigXml()10297 public void setDefaultAssistantForUser_fromConfigXml() { 10298 ComponentName xmlConfig = new ComponentName("config", "xml"); 10299 ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(xmlConfig)); 10300 when(mResources 10301 .getString( 10302 com.android.internal.R.string.config_defaultAssistantAccessComponent)) 10303 .thenReturn(xmlConfig.flattenToString()); 10304 when(mContext.getResources()).thenReturn(mResources); 10305 when(mAssistants.queryPackageForServices(eq(null), anyInt(), anyInt())) 10306 .thenReturn(components); 10307 when(mAssistants.getDefaultComponents()) 10308 .thenReturn(components); 10309 mService.setNotificationAssistantAccessGrantedCallback( 10310 mNotificationAssistantAccessGrantedCallback); 10311 10312 10313 mService.setDefaultAssistantForUser(0); 10314 10315 verify(mNotificationAssistantAccessGrantedCallback) 10316 .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false)); 10317 } 10318 10319 @Test clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne()10320 public void clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne() throws RemoteException { 10321 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 10322 generateResetComponentValues(); 10323 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners); 10324 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 10325 ComponentName deviceConfig1 = new ComponentName("device", "config1"); 10326 ComponentName deviceConfig2 = new ComponentName("device", "config2"); 10327 changes.put(true, new ArrayList(Arrays.asList(deviceConfig1, deviceConfig2))); 10328 changes.put(false, new ArrayList()); 10329 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes); 10330 mService.getBinderService().clearData("device", 0, false); 10331 verify(mAssistants, times(1)) 10332 .setPackageOrComponentEnabled( 10333 eq("device/config2"), 10334 eq(0), eq(true), eq(false)); 10335 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 10336 eq("device"), eq(0), eq(false), eq(true)); 10337 } 10338 10339 @Test testNASSettingUpgrade_userSetNull()10340 public void testNASSettingUpgrade_userSetNull() throws RemoteException { 10341 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 10342 TestableNotificationManagerService service = spy(mService); 10343 int userId = 11; 10344 setUsers(new int[]{userId}); 10345 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 10346 setNASMigrationDone(false, userId); 10347 when(mAssistants.getDefaultFromConfig()) 10348 .thenReturn(newDefaultComponent); 10349 when(mAssistants.getAllowedComponents(anyInt())) 10350 .thenReturn(new ArrayList<>()); 10351 when(mAssistants.hasUserSet(userId)).thenReturn(true); 10352 10353 service.migrateDefaultNAS(); 10354 assertTrue(service.isNASMigrationDone(userId)); 10355 verify(mAssistants, times(1)).clearDefaults(); 10356 } 10357 10358 @Test testNASSettingUpgrade_userSet()10359 public void testNASSettingUpgrade_userSet() throws RemoteException { 10360 ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component1"); 10361 TestableNotificationManagerService service = spy(mService); 10362 int userId = 11; 10363 setUsers(new int[]{userId}); 10364 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 10365 setNASMigrationDone(false, userId); 10366 when(mAssistants.getDefaultFromConfig()) 10367 .thenReturn(defaultComponent); 10368 when(mAssistants.getAllowedComponents(anyInt())) 10369 .thenReturn(new ArrayList(Arrays.asList(defaultComponent))); 10370 when(mAssistants.hasUserSet(userId)).thenReturn(true); 10371 10372 service.migrateDefaultNAS(); 10373 verify(mAssistants, times(1)).setUserSet(userId, false); 10374 //resetDefaultAssistantsIfNecessary should invoke from readPolicyXml() and migration 10375 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 10376 } 10377 10378 @Test testNASSettingUpgrade_multiUser()10379 public void testNASSettingUpgrade_multiUser() throws RemoteException { 10380 ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 10381 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2"); 10382 TestableNotificationManagerService service = spy(mService); 10383 int userId1 = 11; 10384 int userId2 = 12; 10385 setUsers(new int[]{userId1, userId2}); 10386 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1}); 10387 when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2}); 10388 10389 setNASMigrationDone(false, userId1); 10390 setNASMigrationDone(false, userId2); 10391 when(mAssistants.getDefaultComponents()) 10392 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent))); 10393 when(mAssistants.getDefaultFromConfig()) 10394 .thenReturn(newDefaultComponent); 10395 //User1: set different NAS 10396 when(mAssistants.getAllowedComponents(userId1)) 10397 .thenReturn(Arrays.asList(oldDefaultComponent)); 10398 //User2: set to none 10399 when(mAssistants.getAllowedComponents(userId2)) 10400 .thenReturn(new ArrayList<>()); 10401 10402 when(mAssistants.hasUserSet(userId1)).thenReturn(true); 10403 when(mAssistants.hasUserSet(userId2)).thenReturn(true); 10404 10405 service.migrateDefaultNAS(); 10406 // user1's setting get reset 10407 verify(mAssistants, times(1)).setUserSet(userId1, false); 10408 verify(mAssistants, times(0)).setUserSet(eq(userId2), anyBoolean()); 10409 assertTrue(service.isNASMigrationDone(userId2)); 10410 10411 } 10412 10413 @Test testNASSettingUpgrade_multiProfile()10414 public void testNASSettingUpgrade_multiProfile() throws RemoteException { 10415 ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 10416 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2"); 10417 TestableNotificationManagerService service = spy(mService); 10418 int userId1 = 11; 10419 int userId2 = 12; //work profile 10420 setUsers(new int[]{userId1, userId2}); 10421 when(mUm.isManagedProfile(userId2)).thenReturn(true); 10422 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2}); 10423 10424 setNASMigrationDone(false, userId1); 10425 setNASMigrationDone(false, userId2); 10426 when(mAssistants.getDefaultComponents()) 10427 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent))); 10428 when(mAssistants.getDefaultFromConfig()) 10429 .thenReturn(newDefaultComponent); 10430 //Both profiles: set different NAS 10431 when(mAssistants.getAllowedComponents(userId1)) 10432 .thenReturn(Arrays.asList(oldDefaultComponent)); 10433 when(mAssistants.getAllowedComponents(userId2)) 10434 .thenReturn(Arrays.asList(oldDefaultComponent)); 10435 10436 when(mAssistants.hasUserSet(userId1)).thenReturn(true); 10437 when(mAssistants.hasUserSet(userId2)).thenReturn(true); 10438 10439 service.migrateDefaultNAS(); 10440 assertFalse(service.isNASMigrationDone(userId1)); 10441 assertFalse(service.isNASMigrationDone(userId2)); 10442 } 10443 10444 10445 10446 @Test testNASSettingUpgrade_clearDataAfterMigrationIsDone()10447 public void testNASSettingUpgrade_clearDataAfterMigrationIsDone() throws RemoteException { 10448 ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component"); 10449 TestableNotificationManagerService service = spy(mService); 10450 int userId = 12; 10451 setUsers(new int[]{userId}); 10452 when(mAssistants.getDefaultComponents()) 10453 .thenReturn(new ArraySet<>(Arrays.asList(defaultComponent))); 10454 when(mAssistants.hasUserSet(userId)).thenReturn(true); 10455 setNASMigrationDone(true, userId); 10456 10457 //Test User clear data 10458 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 10459 generateResetComponentValues(); 10460 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners); 10461 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 10462 changes.put(true, new ArrayList(Arrays.asList(defaultComponent))); 10463 changes.put(false, new ArrayList()); 10464 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes); 10465 10466 //Clear data 10467 service.getBinderService().clearData("package", userId, false); 10468 //Test migrate flow again 10469 service.migrateDefaultNAS(); 10470 10471 //Migration should not happen again 10472 verify(mAssistants, times(0)).setUserSet(userId, false); 10473 verify(mAssistants, times(0)).clearDefaults(); 10474 //resetDefaultAssistantsIfNecessary should only invoke once from readPolicyXml() 10475 verify(mAssistants, times(1)).resetDefaultAssistantsIfNecessary(); 10476 10477 } 10478 setNASMigrationDone(boolean done, int userId)10479 private void setNASMigrationDone(boolean done, int userId) { 10480 Settings.Secure.putIntForUser(mContext.getContentResolver(), 10481 Settings.Secure.NAS_SETTINGS_UPDATED, done ? 1 : 0, userId); 10482 } 10483 setUsers(int[] userIds)10484 private void setUsers(int[] userIds) { 10485 List<UserInfo> users = new ArrayList<>(); 10486 for (int id: userIds) { 10487 users.add(new UserInfo(id, String.valueOf(id), 0)); 10488 } 10489 for (UserInfo user : users) { 10490 when(mUm.getUserInfo(eq(user.id))).thenReturn(user); 10491 } 10492 when(mUm.getUsers()).thenReturn(users); 10493 } 10494 10495 @Test clearDefaultListenersPackageShouldEnableIt()10496 public void clearDefaultListenersPackageShouldEnableIt() throws RemoteException { 10497 ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants = 10498 generateResetComponentValues(); 10499 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changedAssistants); 10500 ComponentName deviceConfig = new ComponentName("device", "config"); 10501 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 10502 changes.put(true, new ArrayList(Arrays.asList(deviceConfig))); 10503 changes.put(false, new ArrayList()); 10504 when(mListeners.resetComponents(anyString(), anyInt())) 10505 .thenReturn(changes); 10506 mService.getBinderService().clearData("device", 0, false); 10507 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 10508 eq("device"), eq(0), eq(false), eq(true)); 10509 } 10510 10511 @Test clearDefaultDnDPackageShouldEnableIt()10512 public void clearDefaultDnDPackageShouldEnableIt() throws RemoteException { 10513 ArrayMap<Boolean, ArrayList<ComponentName>> changed = generateResetComponentValues(); 10514 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changed); 10515 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changed); 10516 mService.getBinderService().clearData("pkgName", 0, false); 10517 verify(mConditionProviders, times(1)).resetPackage( 10518 eq("pkgName"), eq(0)); 10519 } 10520 10521 @Test testFlagBubble()10522 public void testFlagBubble() throws RemoteException { 10523 setUpPrefsForBubbles(mPkg, mUid, 10524 true /* global */, 10525 BUBBLE_PREFERENCE_ALL /* app */, 10526 true /* channel */); 10527 10528 NotificationRecord nr = 10529 generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble"); 10530 10531 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10532 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10533 waitForIdle(); 10534 10535 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10536 assertEquals(1, notifs.length); 10537 assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0); 10538 assertTrue(mService.getNotificationRecord( 10539 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10540 } 10541 10542 @Test testFlagBubble_noFlag_appNotAllowed()10543 public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException { 10544 setUpPrefsForBubbles(mPkg, mUid, 10545 true /* global */, 10546 BUBBLE_PREFERENCE_NONE /* app */, 10547 true /* channel */); 10548 10549 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10550 "testFlagBubble_noFlag_appNotAllowed"); 10551 10552 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10553 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10554 waitForIdle(); 10555 10556 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10557 assertEquals(1, notifs.length); 10558 assertEquals((notifs[0].getNotification().flags & FLAG_BUBBLE), 0); 10559 assertFalse(mService.getNotificationRecord( 10560 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10561 } 10562 10563 @Test testFlagBubbleNotifs_noFlag_whenAppForeground()10564 public void testFlagBubbleNotifs_noFlag_whenAppForeground() throws RemoteException { 10565 setUpPrefsForBubbles(mPkg, mUid, 10566 true /* global */, 10567 BUBBLE_PREFERENCE_ALL /* app */, 10568 true /* channel */); 10569 10570 // Notif with bubble metadata but not our other misc requirements 10571 Notification.Builder nb = new Notification.Builder(mContext, 10572 mTestNotificationChannel.getId()) 10573 .setContentTitle("foo") 10574 .setSmallIcon(android.R.drawable.sym_def_app_icon) 10575 .setBubbleMetadata(getBubbleMetadata()); 10576 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 0, 10577 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10578 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10579 10580 // Say we're foreground 10581 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 10582 IMPORTANCE_FOREGROUND); 10583 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10584 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10585 waitForIdle(); 10586 10587 // if notif isn't configured properly it doesn't get to bubble just because app is 10588 // foreground. 10589 assertFalse(mService.getNotificationRecord( 10590 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10591 } 10592 10593 @Test testFlagBubbleNotifs_flag_messaging()10594 public void testFlagBubbleNotifs_flag_messaging() throws RemoteException { 10595 setUpPrefsForBubbles(mPkg, mUid, 10596 true /* global */, 10597 BUBBLE_PREFERENCE_ALL /* app */, 10598 true /* channel */); 10599 10600 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10601 "testFlagBubbleNotifs_flag_messaging"); 10602 10603 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10604 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10605 waitForIdle(); 10606 10607 // yes allowed, yes messaging, yes bubble 10608 assertTrue(mService.getNotificationRecord( 10609 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10610 } 10611 10612 @Test testFlagBubbleNotifs_noFlag_noShortcut()10613 public void testFlagBubbleNotifs_noFlag_noShortcut() throws RemoteException { 10614 setUpPrefsForBubbles(mPkg, mUid, 10615 true /* global */, 10616 BUBBLE_PREFERENCE_ALL /* app */, 10617 true /* channel */); 10618 10619 Notification.Builder nb = getMessageStyleNotifBuilder(true, null, false, true); 10620 nb.setShortcutId(null); 10621 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 10622 null, mUid, 0, 10623 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10624 10625 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 10626 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 10627 waitForIdle(); 10628 10629 // no shortcut no bubble 10630 assertFalse(mService.getNotificationRecord( 10631 sbn.getKey()).getNotification().isBubbleNotification()); 10632 } 10633 10634 @Test testFlagBubbleNotifs_noFlag_messaging_appNotAllowed()10635 public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException { 10636 setUpPrefsForBubbles(mPkg, mUid, 10637 true /* global */, 10638 BUBBLE_PREFERENCE_NONE /* app */, 10639 true /* channel */); 10640 10641 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10642 "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed"); 10643 10644 // Post the notification 10645 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10646 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10647 waitForIdle(); 10648 10649 // not allowed, no bubble 10650 assertFalse(mService.getNotificationRecord( 10651 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10652 } 10653 10654 @Test testFlagBubbleNotifs_noFlag_notBubble()10655 public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException { 10656 setUpPrefsForBubbles(mPkg, mUid, 10657 true /* global */, 10658 BUBBLE_PREFERENCE_ALL /* app */, 10659 true /* channel */); 10660 10661 // Messaging notif WITHOUT bubble metadata 10662 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addBubbleMetadata */, 10663 null /* groupKey */, false /* isSummary */, true); 10664 10665 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 10666 "testFlagBubbleNotifs_noFlag_notBubble", mUid, 0, 10667 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10668 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10669 10670 // Post the notification 10671 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10672 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10673 waitForIdle(); 10674 10675 // no bubble metadata, no bubble 10676 assertFalse(mService.getNotificationRecord( 10677 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10678 } 10679 10680 @Test testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed()10681 public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException { 10682 setUpPrefsForBubbles(mPkg, mUid, 10683 true /* global */, 10684 BUBBLE_PREFERENCE_ALL /* app */, 10685 false /* channel */); 10686 10687 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10688 "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed"); 10689 nr.getChannel().lockFields(USER_LOCKED_ALLOW_BUBBLE); 10690 10691 // Post the notification 10692 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10693 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10694 waitForIdle(); 10695 10696 // channel not allowed, no bubble 10697 assertFalse(mService.getNotificationRecord( 10698 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10699 } 10700 10701 @Test testCancelNotificationsFromApp_cancelsBubbles()10702 public void testCancelNotificationsFromApp_cancelsBubbles() throws Exception { 10703 final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel); 10704 nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE; 10705 10706 // Post the notification 10707 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 10708 "testAppCancelNotifications_cancelsBubbles", 10709 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(), 10710 nrBubble.getSbn().getUserId()); 10711 waitForIdle(); 10712 10713 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10714 assertEquals(1, notifs.length); 10715 assertEquals(1, mService.getNotificationRecordCount()); 10716 10717 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 10718 "testAppCancelNotifications_cancelsBubbles", nrBubble.getSbn().getId(), 10719 nrBubble.getSbn().getUserId()); 10720 waitForIdle(); 10721 10722 StatusBarNotification[] notifs2 = mBinderService.getActiveNotifications(mPkg); 10723 assertEquals(0, notifs2.length); 10724 assertEquals(0, mService.getNotificationRecordCount()); 10725 } 10726 10727 @Test testCancelAllNotificationsFromApp_cancelsBubble()10728 public void testCancelAllNotificationsFromApp_cancelsBubble() throws Exception { 10729 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10730 nr.getSbn().getNotification().flags |= FLAG_BUBBLE; 10731 mService.addNotification(nr); 10732 10733 mBinderService.cancelAllNotifications(mPkg, nr.getSbn().getUserId()); 10734 waitForIdle(); 10735 10736 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10737 assertEquals(0, notifs.length); 10738 assertEquals(0, mService.getNotificationRecordCount()); 10739 } 10740 10741 @Test testCancelAllNotificationsFromListener_ignoresBubbles()10742 public void testCancelAllNotificationsFromListener_ignoresBubbles() throws Exception { 10743 final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel); 10744 final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel); 10745 nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE; 10746 10747 mService.addNotification(nrNormal); 10748 mService.addNotification(nrBubble); 10749 10750 mService.getBinderService().cancelNotificationsFromListener(null, null); 10751 waitForIdle(); 10752 10753 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10754 assertEquals(1, notifs.length); 10755 assertEquals(1, mService.getNotificationRecordCount()); 10756 } 10757 10758 @Test testCancelNotificationsFromListener_cancelsNonBubble()10759 public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception { 10760 // Add non-bubble notif 10761 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10762 mService.addNotification(nr); 10763 10764 // Cancel via listener 10765 String[] keys = {nr.getSbn().getKey()}; 10766 mService.getBinderService().cancelNotificationsFromListener(null, keys); 10767 waitForIdle(); 10768 10769 // Notif not active anymore 10770 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10771 assertEquals(0, notifs.length); 10772 assertEquals(0, mService.getNotificationRecordCount()); 10773 // Cancel event is logged 10774 assertEquals(1, mNotificationRecordLogger.numCalls()); 10775 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 10776 .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0)); 10777 } 10778 10779 @Test testCancelNotificationsFromListener_suppressesBubble()10780 public void testCancelNotificationsFromListener_suppressesBubble() throws Exception { 10781 // Add bubble notif 10782 setUpPrefsForBubbles(mPkg, mUid, 10783 true /* global */, 10784 BUBBLE_PREFERENCE_ALL /* app */, 10785 true /* channel */); 10786 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 10787 10788 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10789 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10790 waitForIdle(); 10791 10792 // Cancel via listener 10793 String[] keys = {nr.getSbn().getKey()}; 10794 mService.getBinderService().cancelNotificationsFromListener(null, keys); 10795 waitForIdle(); 10796 10797 // Bubble notif active and suppressed 10798 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10799 assertEquals(1, notifs.length); 10800 assertEquals(1, mService.getNotificationRecordCount()); 10801 assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed()); 10802 } 10803 10804 @Test testCancelAllNotificationsFromStatusBar_ignoresBubble()10805 public void testCancelAllNotificationsFromStatusBar_ignoresBubble() throws Exception { 10806 // GIVEN a notification bubble 10807 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10808 nr.getSbn().getNotification().flags |= FLAG_BUBBLE; 10809 mService.addNotification(nr); 10810 10811 // WHEN the status bar clears all notifications 10812 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 10813 nr.getSbn().getUserId()); 10814 waitForIdle(); 10815 10816 // THEN the bubble notification does not get removed 10817 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10818 assertEquals(1, notifs.length); 10819 assertEquals(1, mService.getNotificationRecordCount()); 10820 } 10821 10822 10823 @Test testGetAllowedAssistantAdjustments()10824 public void testGetAllowedAssistantAdjustments() throws Exception { 10825 List<String> adjustments = mBinderService.getAllowedAssistantAdjustments(null); 10826 assertNotNull(adjustments); 10827 } 10828 10829 @Test testAdjustRestrictedKey()10830 public void testAdjustRestrictedKey() throws Exception { 10831 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10832 mService.addNotification(r); 10833 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 10834 10835 when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true); 10836 when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false); 10837 10838 Bundle signals = new Bundle(); 10839 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); 10840 signals.putInt(KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE); 10841 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 10842 "", r.getUser().getIdentifier()); 10843 10844 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 10845 r.applyAdjustments(); 10846 10847 assertEquals(IMPORTANCE_LOW, r.getAssistantImportance()); 10848 assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment()); 10849 } 10850 10851 @Test testAutomaticZenRuleValidation_policyFilterAgreement()10852 public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception { 10853 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10854 .thenReturn(true); 10855 mService.setZenHelper(mock(ZenModeHelper.class)); 10856 ComponentName owner = new ComponentName(mContext, this.getClass()); 10857 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10858 boolean isEnabled = true; 10859 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10860 zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); 10861 10862 try { 10863 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 10864 fail("Zen policy only applies to priority only mode"); 10865 } catch (IllegalArgumentException e) { 10866 // yay 10867 } 10868 10869 rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10870 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10871 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 10872 10873 rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10874 null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); 10875 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 10876 } 10877 10878 @Test testAddAutomaticZenRule_systemCallTakesPackageFromOwner()10879 public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception { 10880 mService.isSystemUid = true; 10881 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 10882 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10883 .thenReturn(true); 10884 mService.setZenHelper(mockZenModeHelper); 10885 ComponentName owner = new ComponentName("android", "ProviderName"); 10886 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10887 boolean isEnabled = true; 10888 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10889 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10890 mBinderService.addAutomaticZenRule(rule, "com.android.settings", false); 10891 10892 // verify that zen mode helper gets passed in a package name of "android" 10893 verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule), 10894 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt()); 10895 } 10896 10897 @Test testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner()10898 public void testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner() throws Exception { 10899 // The multi-user case: where the calling uid doesn't match the system uid, but the calling 10900 // *appid* is the system. 10901 mService.isSystemUid = false; 10902 mService.isSystemAppId = true; 10903 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 10904 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10905 .thenReturn(true); 10906 mService.setZenHelper(mockZenModeHelper); 10907 ComponentName owner = new ComponentName("android", "ProviderName"); 10908 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10909 boolean isEnabled = true; 10910 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10911 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10912 mBinderService.addAutomaticZenRule(rule, "com.android.settings", false); 10913 10914 // verify that zen mode helper gets passed in a package name of "android" 10915 verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule), 10916 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt()); 10917 } 10918 10919 @Test testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg()10920 public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception { 10921 mService.isSystemUid = false; 10922 mService.isSystemAppId = false; 10923 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 10924 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10925 .thenReturn(true); 10926 mService.setZenHelper(mockZenModeHelper); 10927 ComponentName owner = new ComponentName("android", "ProviderName"); 10928 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10929 boolean isEnabled = true; 10930 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10931 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10932 mBinderService.addAutomaticZenRule(rule, "another.package", false); 10933 10934 // verify that zen mode helper gets passed in the package name from the arg, not the owner 10935 verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("another.package"), eq(rule), 10936 eq(ZenModeConfig.ORIGIN_APP), anyString(), 10937 anyInt()); // doesn't count as a system/systemui call 10938 } 10939 10940 @Test 10941 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners()10942 public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception { 10943 ZenModeHelper zenModeHelper = setUpMockZenTest(); 10944 mService.setCallerIsNormalPackage(); 10945 10946 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 10947 .setType(AutomaticZenRule.TYPE_MANAGED) 10948 .setOwner(new ComponentName(mPkg, "cls")) 10949 .build(); 10950 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); 10951 10952 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 10953 10954 verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(), 10955 anyInt()); 10956 } 10957 10958 @Test 10959 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeManagedCanBeUsedBySystem()10960 public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception { 10961 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED); 10962 } 10963 10964 @Test 10965 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps()10966 public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception { 10967 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 10968 AutomaticZenRule.TYPE_MANAGED); 10969 } 10970 10971 @Test 10972 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing()10973 public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception { 10974 ZenModeHelper zenModeHelper = setUpMockZenTest(); 10975 mService.setCallerIsNormalPackage(); 10976 reset(mPackageManagerInternal); 10977 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 10978 when(mResources 10979 .getString(com.android.internal.R.string.config_systemWellbeing)) 10980 .thenReturn(mPkg); 10981 when(mContext.getResources()).thenReturn(mResources); 10982 10983 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 10984 .setType(AutomaticZenRule.TYPE_BEDTIME) 10985 .setOwner(new ComponentName(mPkg, "cls")) 10986 .build(); 10987 10988 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 10989 10990 verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(), 10991 anyInt()); 10992 } 10993 10994 @Test 10995 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem()10996 public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception { 10997 reset(mPackageManagerInternal); 10998 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 10999 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_BEDTIME); 11000 } 11001 11002 @Test 11003 @EnableFlags(android.app.Flags.FLAG_MODES_API) testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps()11004 public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception { 11005 reset(mPackageManagerInternal); 11006 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 11007 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 11008 AutomaticZenRule.TYPE_BEDTIME); 11009 } 11010 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( @utomaticZenRule.Type int ruleType)11011 private void addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( 11012 @AutomaticZenRule.Type int ruleType) throws Exception { 11013 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11014 mService.isSystemUid = true; 11015 11016 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 11017 .setType(ruleType) 11018 .setOwner(new ComponentName(mPkg, "cls")) 11019 .build(); 11020 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); 11021 11022 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 11023 11024 verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(), 11025 anyInt()); 11026 } 11027 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( @utomaticZenRule.Type int ruleType)11028 private void addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 11029 @AutomaticZenRule.Type int ruleType) { 11030 mService.setCallerIsNormalPackage(); 11031 mService.setZenHelper(mock(ZenModeHelper.class)); 11032 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 11033 .thenReturn(true); 11034 11035 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 11036 .setType(ruleType) 11037 .setOwner(new ComponentName(mPkg, "cls")) 11038 .build(); 11039 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false); 11040 11041 assertThrows(IllegalArgumentException.class, 11042 () -> mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false)); 11043 } 11044 11045 @Test 11046 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromUser_mappedToOriginUser()11047 public void addAutomaticZenRule_fromUser_mappedToOriginUser() throws Exception { 11048 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11049 mService.isSystemUid = true; 11050 11051 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true); 11052 11053 verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE), 11054 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt()); 11055 } 11056 11057 @Test 11058 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem()11059 public void addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem() throws Exception { 11060 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11061 mService.isSystemUid = true; 11062 11063 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false); 11064 11065 verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE), 11066 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt()); 11067 } 11068 11069 @Test 11070 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromApp_mappedToOriginApp()11071 public void addAutomaticZenRule_fromApp_mappedToOriginApp() throws Exception { 11072 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11073 mService.setCallerIsNormalPackage(); 11074 11075 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false); 11076 11077 verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE), 11078 eq(ZenModeConfig.ORIGIN_APP), anyString(), anyInt()); 11079 } 11080 11081 @Test 11082 @EnableFlags(android.app.Flags.FLAG_MODES_API) addAutomaticZenRule_fromAppFromUser_blocked()11083 public void addAutomaticZenRule_fromAppFromUser_blocked() throws Exception { 11084 setUpMockZenTest(); 11085 mService.setCallerIsNormalPackage(); 11086 11087 assertThrows(SecurityException.class, () -> 11088 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true)); 11089 } 11090 11091 @Test 11092 @EnableFlags(android.app.Flags.FLAG_MODES_API) updateAutomaticZenRule_fromUserFromSystem_allowed()11093 public void updateAutomaticZenRule_fromUserFromSystem_allowed() throws Exception { 11094 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11095 mService.isSystemUid = true; 11096 11097 mBinderService.updateAutomaticZenRule("id", SOME_ZEN_RULE, /* fromUser= */ true); 11098 11099 verify(zenModeHelper).updateAutomaticZenRule(any(), eq("id"), eq(SOME_ZEN_RULE), 11100 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt()); 11101 } 11102 11103 @Test 11104 @EnableFlags(android.app.Flags.FLAG_MODES_API) updateAutomaticZenRule_fromUserFromApp_blocked()11105 public void updateAutomaticZenRule_fromUserFromApp_blocked() throws Exception { 11106 setUpMockZenTest(); 11107 mService.setCallerIsNormalPackage(); 11108 11109 assertThrows(SecurityException.class, () -> 11110 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true)); 11111 } 11112 11113 @Test 11114 @EnableFlags(android.app.Flags.FLAG_MODES_API) removeAutomaticZenRule_fromUserFromSystem_allowed()11115 public void removeAutomaticZenRule_fromUserFromSystem_allowed() throws Exception { 11116 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11117 mService.isSystemUid = true; 11118 11119 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true); 11120 11121 verify(zenModeHelper).removeAutomaticZenRule(any(), eq("id"), 11122 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt()); 11123 } 11124 11125 @Test 11126 @EnableFlags(android.app.Flags.FLAG_MODES_API) removeAutomaticZenRule_fromUserFromApp_blocked()11127 public void removeAutomaticZenRule_fromUserFromApp_blocked() throws Exception { 11128 setUpMockZenTest(); 11129 mService.setCallerIsNormalPackage(); 11130 11131 assertThrows(SecurityException.class, () -> 11132 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true)); 11133 } 11134 11135 @Test 11136 @EnableFlags(android.app.Flags.FLAG_MODES_API) setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp()11137 public void setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp() 11138 throws Exception { 11139 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11140 mService.setCallerIsNormalPackage(); 11141 11142 Condition withSourceUser = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11143 SOURCE_USER_ACTION); 11144 mBinderService.setAutomaticZenRuleState("id", withSourceUser); 11145 11146 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceUser), 11147 eq(ZenModeConfig.ORIGIN_USER_IN_APP), anyInt()); 11148 } 11149 11150 @Test 11151 @EnableFlags(android.app.Flags.FLAG_MODES_API) setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp()11152 public void setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp() 11153 throws Exception { 11154 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11155 mService.setCallerIsNormalPackage(); 11156 11157 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11158 SOURCE_CONTEXT); 11159 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 11160 11161 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext), 11162 eq(ZenModeConfig.ORIGIN_APP), anyInt()); 11163 } 11164 11165 @Test 11166 @EnableFlags(android.app.Flags.FLAG_MODES_API) setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi()11167 public void setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi() 11168 throws Exception { 11169 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11170 mService.isSystemUid = true; 11171 11172 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11173 SOURCE_USER_ACTION); 11174 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 11175 11176 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext), 11177 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyInt()); 11178 } 11179 @Test 11180 @EnableFlags(android.app.Flags.FLAG_MODES_API) setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem()11181 public void setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem() 11182 throws Exception { 11183 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11184 mService.isSystemUid = true; 11185 11186 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11187 SOURCE_CONTEXT); 11188 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 11189 11190 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext), 11191 eq(ZenModeConfig.ORIGIN_SYSTEM), anyInt()); 11192 } 11193 11194 11195 @Test 11196 @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER) getAutomaticZenRules_fromSystem_readsWithCurrentUser()11197 public void getAutomaticZenRules_fromSystem_readsWithCurrentUser() throws Exception { 11198 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11199 mService.isSystemUid = true; 11200 11201 // Representative used to verify getCallingZenUser(). 11202 mBinderService.getAutomaticZenRules(); 11203 11204 verify(zenModeHelper).getAutomaticZenRules(eq(UserHandle.CURRENT)); 11205 } 11206 11207 @Test 11208 @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER) getAutomaticZenRules_fromNormalPackage_readsWithBinderUser()11209 public void getAutomaticZenRules_fromNormalPackage_readsWithBinderUser() throws Exception { 11210 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11211 mService.setCallerIsNormalPackage(); 11212 11213 // Representative used to verify getCallingZenUser(). 11214 mBinderService.getAutomaticZenRules(); 11215 11216 verify(zenModeHelper).getAutomaticZenRules(eq(Binder.getCallingUserHandle())); 11217 } 11218 11219 /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */ setUpMockZenTest()11220 private ZenModeHelper setUpMockZenTest() { 11221 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 11222 mService.setZenHelper(zenModeHelper); 11223 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 11224 .thenReturn(true); 11225 return zenModeHelper; 11226 } 11227 11228 @Test onZenModeChanged_sendsBroadcasts()11229 public void onZenModeChanged_sendsBroadcasts() throws Exception { 11230 when(mAmi.getCurrentUserId()).thenReturn(100); 11231 when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102}); 11232 when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() { 11233 @Override 11234 public List<String> answer(InvocationOnMock invocation) { 11235 int userId = invocation.getArgument(0); 11236 switch (userId) { 11237 case 100: 11238 return Lists.newArrayList("a", "b", "c"); 11239 case 101: 11240 return Lists.newArrayList(); 11241 case 102: 11242 return Lists.newArrayList("b"); 11243 default: 11244 throw new IllegalArgumentException( 11245 "Why would you ask for packages of userId " + userId + "?"); 11246 } 11247 } 11248 }); 11249 11250 mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null, 11251 "testing!", false); 11252 waitForIdle(); 11253 11254 InOrder inOrder = inOrder(mContext); 11255 // Verify broadcasts for registered receivers 11256 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 11257 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 11258 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null)); 11259 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 11260 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 11261 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null)); 11262 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 11263 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 11264 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null)); 11265 11266 // Verify broadcast for packages that manage DND. 11267 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11268 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags( 11269 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 11270 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11271 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( 11272 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 11273 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11274 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags( 11275 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 11276 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11277 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( 11278 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102))); 11279 } 11280 11281 @Test 11282 @EnableFlags(android.app.Flags.FLAG_MODES_API) onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner()11283 public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception { 11284 mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged( 11285 mUserId, "rule.owner.pkg", "rule_id", AUTOMATIC_RULE_STATUS_ACTIVATED)); 11286 11287 Intent expected = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED) 11288 .setPackage("rule.owner.pkg") 11289 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, "rule_id") 11290 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, AUTOMATIC_RULE_STATUS_ACTIVATED) 11291 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 11292 11293 verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId))); 11294 } 11295 eqIntent(Intent wanted)11296 private static Intent eqIntent(Intent wanted) { 11297 return ArgumentMatchers.argThat( 11298 new ArgumentMatcher<Intent>() { 11299 @Override 11300 public boolean matches(Intent argument) { 11301 return wanted.filterEquals(argument) 11302 && wanted.getFlags() == argument.getFlags() 11303 && equalBundles(wanted.getExtras(), argument.getExtras()); 11304 } 11305 11306 @Override 11307 public String toString() { 11308 return wanted.toString(); 11309 } 11310 11311 private boolean equalBundles(Bundle one, Bundle two) { 11312 if (one == null && two == null) { 11313 return true; 11314 } 11315 if ((one == null) != (two == null)) { 11316 return false; 11317 } 11318 if (one.size() != two.size()) { 11319 return false; 11320 } 11321 11322 HashSet<String> setOne = new HashSet<>(one.keySet()); 11323 setOne.addAll(two.keySet()); 11324 11325 for (String key : setOne) { 11326 if (!one.containsKey(key) || !two.containsKey(key)) { 11327 return false; 11328 } 11329 11330 Object valueOne = one.get(key); 11331 Object valueTwo = two.get(key); 11332 if (valueOne instanceof Bundle 11333 && valueTwo instanceof Bundle 11334 && !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) { 11335 return false; 11336 } else if (valueOne == null) { 11337 if (valueTwo != null) { 11338 return false; 11339 } 11340 } else if (!valueOne.equals(valueTwo)) { 11341 return false; 11342 } 11343 } 11344 return true; 11345 } 11346 }); 11347 } 11348 11349 @Test 11350 public void testAreNotificationsEnabledForPackage() throws Exception { 11351 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 11352 mUid); 11353 11354 verify(mPermissionHelper).hasPermission(mUid); 11355 } 11356 11357 @Test 11358 public void testAreNotificationsEnabledForPackage_crossUser() throws Exception { 11359 try { 11360 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 11361 mUid + UserHandle.PER_USER_RANGE); 11362 fail("Cannot call cross user without permission"); 11363 } catch (SecurityException e) { 11364 // pass 11365 } 11366 verify(mPermissionHelper, never()).hasPermission(anyInt()); 11367 11368 // cross user, with permission, no problem 11369 enableInteractAcrossUsers(); 11370 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 11371 mUid + UserHandle.PER_USER_RANGE); 11372 11373 verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE); 11374 } 11375 11376 @Test 11377 public void testAreNotificationsEnabledForPackage_viaInternalService() { 11378 mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid); 11379 verify(mPermissionHelper).hasPermission(mUid); 11380 } 11381 11382 @Test 11383 public void testGetPackageImportance() throws Exception { 11384 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 11385 assertThat(mBinderService.getPackageImportance(mContext.getPackageName())) 11386 .isEqualTo(IMPORTANCE_DEFAULT); 11387 11388 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 11389 assertThat(mBinderService.getPackageImportance(mContext.getPackageName())) 11390 .isEqualTo(IMPORTANCE_NONE); 11391 } 11392 11393 @Test 11394 public void testAreBubblesAllowedForPackage_crossUser() throws Exception { 11395 try { 11396 mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), 11397 mUid + UserHandle.PER_USER_RANGE); 11398 fail("Cannot call cross user without permission"); 11399 } catch (SecurityException e) { 11400 // pass 11401 } 11402 11403 // cross user, with permission, no problem 11404 enableInteractAcrossUsers(); 11405 mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), 11406 mUid + UserHandle.PER_USER_RANGE); 11407 } 11408 11409 private void enableInteractAcrossUsers() { 11410 TestablePermissions perms = mContext.getTestablePermissions(); 11411 perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); 11412 } 11413 11414 @Test 11415 public void testNotificationBubbleChanged_false() throws Exception { 11416 setUpPrefsForBubbles(mPkg, mUid, 11417 true /* global */, 11418 BUBBLE_PREFERENCE_ALL /* app */, 11419 true /* channel */); 11420 11421 // Notif with bubble metadata 11422 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11423 "testNotificationBubbleChanged_false"); 11424 11425 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11426 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11427 waitForIdle(); 11428 11429 // Reset as this is called when the notif is first sent 11430 reset(mListeners); 11431 11432 // First we were a bubble 11433 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11434 assertEquals(1, notifsBefore.length); 11435 assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0); 11436 11437 // Notify we're not a bubble 11438 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 11439 waitForIdle(); 11440 11441 // Make sure we are not a bubble 11442 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11443 assertEquals(1, notifsAfter.length); 11444 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 11445 } 11446 11447 @Test 11448 public void testNotificationBubbleChanged_true() throws Exception { 11449 setUpPrefsForBubbles(mPkg, mUid, 11450 true /* global */, 11451 BUBBLE_PREFERENCE_ALL /* app */, 11452 true /* channel */); 11453 11454 // Notif that is not a bubble 11455 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 11456 1, null, false); 11457 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11458 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11459 waitForIdle(); 11460 11461 // Would be a normal notification because wouldn't have met requirements to bubble 11462 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11463 assertEquals(1, notifsBefore.length); 11464 assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0); 11465 11466 // Update the notification to be message style / meet bubble requirements 11467 NotificationRecord nr2 = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11468 nr.getSbn().getTag()); 11469 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr2.getSbn().getTag(), 11470 nr2.getSbn().getId(), nr2.getSbn().getNotification(), nr2.getSbn().getUserId()); 11471 waitForIdle(); 11472 11473 // Reset as this is called when the notif is first sent 11474 reset(mListeners); 11475 11476 // Notify we are now a bubble 11477 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 11478 waitForIdle(); 11479 11480 // Make sure we are a bubble 11481 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11482 assertEquals(1, notifsAfter.length); 11483 assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0); 11484 } 11485 11486 @Test 11487 public void testNotificationBubbleChanged_true_notAllowed() throws Exception { 11488 setUpPrefsForBubbles(mPkg, mUid, 11489 true /* global */, 11490 BUBBLE_PREFERENCE_ALL /* app */, 11491 true /* channel */); 11492 11493 // Notif that is not a bubble 11494 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 11495 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11496 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11497 waitForIdle(); 11498 11499 // Reset as this is called when the notif is first sent 11500 reset(mListeners); 11501 11502 // Would be a normal notification because wouldn't have met requirements to bubble 11503 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11504 assertEquals(1, notifsBefore.length); 11505 assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0); 11506 11507 // Notify we are now a bubble 11508 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 11509 waitForIdle(); 11510 11511 // We still wouldn't be a bubble because the notification didn't meet requirements 11512 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11513 assertEquals(1, notifsAfter.length); 11514 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 11515 } 11516 11517 @Test 11518 public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception { 11519 setUpPrefsForBubbles(mPkg, mUid, 11520 true /* global */, 11521 BUBBLE_PREFERENCE_ALL /* app */, 11522 true /* channel */); 11523 11524 // Notif with bubble metadata 11525 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11526 "testNotificationBubbleIsFlagRemoved_resetOnUpdate"); 11527 11528 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11529 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11530 waitForIdle(); 11531 // Flag shouldn't be modified 11532 NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11533 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11534 11535 // Notify we're not a bubble 11536 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 11537 waitForIdle(); 11538 // Flag should be modified 11539 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11540 assertTrue(recordToCheck.isFlagBubbleRemoved()); 11541 11542 11543 // Update the notif 11544 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11545 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11546 waitForIdle(); 11547 // And the flag is reset 11548 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11549 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11550 } 11551 11552 @Test 11553 public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception { 11554 setUpPrefsForBubbles(mPkg, mUid, 11555 true /* global */, 11556 BUBBLE_PREFERENCE_ALL /* app */, 11557 true /* channel */); 11558 11559 // Notif with bubble metadata 11560 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11561 "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue"); 11562 11563 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11564 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11565 waitForIdle(); 11566 // Flag shouldn't be modified 11567 NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11568 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11569 11570 // Notify we're not a bubble 11571 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 11572 waitForIdle(); 11573 // Flag should be modified 11574 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11575 assertTrue(recordToCheck.isFlagBubbleRemoved()); 11576 11577 // Notify we are a bubble 11578 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 11579 waitForIdle(); 11580 // And the flag is reset 11581 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11582 } 11583 11584 @Test 11585 public void testOnBubbleMetadataFlagChanged() throws Exception { 11586 setUpPrefsForBubbles(mPkg, mUid, 11587 true /* global */, 11588 BUBBLE_PREFERENCE_ALL /* app */, 11589 true /* channel */); 11590 11591 // Post a bubble notification 11592 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 11593 // Set this so that the bubble can be suppressed 11594 nr.getNotification().getBubbleMetadata().setFlags( 11595 Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE); 11596 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11597 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11598 waitForIdle(); 11599 11600 // Check the flags 11601 Notification n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 11602 assertFalse(n.getBubbleMetadata().isNotificationSuppressed()); 11603 assertFalse(n.getBubbleMetadata().getAutoExpandBubble()); 11604 assertFalse(n.getBubbleMetadata().isBubbleSuppressed()); 11605 assertTrue(n.getBubbleMetadata().isBubbleSuppressable()); 11606 11607 // Reset as this is called when the notif is first sent 11608 reset(mListeners); 11609 11610 // Test: change the flags 11611 int flags = Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE; 11612 flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; 11613 flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 11614 flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; 11615 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), flags); 11616 waitForIdle(); 11617 11618 // Check 11619 n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 11620 assertEquals(flags, n.getBubbleMetadata().getFlags()); 11621 11622 // Reset to check again 11623 reset(mListeners); 11624 11625 // Test: clear flags 11626 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 0); 11627 waitForIdle(); 11628 11629 // Check 11630 n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 11631 assertEquals(0, n.getBubbleMetadata().getFlags()); 11632 } 11633 11634 @Test 11635 public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped() 11636 throws RemoteException { 11637 11638 setUpPrefsForBubbles(mPkg, mUid, 11639 true /* global */, 11640 BUBBLE_PREFERENCE_ALL /* app */, 11641 true /* channel */); 11642 11643 // Post a bubble notification 11644 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 11645 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11646 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11647 waitForIdle(); 11648 11649 // Test: suppress notification via bubble metadata update 11650 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 11651 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 11652 waitForIdle(); 11653 11654 // Check audio is stopped 11655 verify(mAttentionHelper).clearEffectsLocked(nr.getKey()); 11656 } 11657 11658 @Test 11659 public void testGrantInlineReplyUriPermission_recordExists() throws Exception { 11660 int userId = UserManager.isHeadlessSystemUserMode() 11661 ? UserHandle.getUserId(UID_HEADLESS) 11662 : USER_SYSTEM; 11663 11664 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 11665 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 11666 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11667 waitForIdle(); 11668 11669 // A notification exists for the given record 11670 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11671 assertEquals(1, notifsBefore.length); 11672 11673 reset(mPackageManager); 11674 11675 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11676 11677 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11678 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11679 nr.getSbn().getUid()); 11680 11681 // Grant permission called for the UID of SystemUI under the target user ID 11682 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11683 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 11684 anyInt(), eq(nr.getSbn().getUserId())); 11685 } 11686 11687 @Test 11688 public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception { 11689 int userId = UserManager.isHeadlessSystemUserMode() 11690 ? UserHandle.getUserId(UID_HEADLESS) 11691 : USER_SYSTEM; 11692 11693 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 11694 waitForIdle(); 11695 11696 // No notifications exist for the given record 11697 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11698 assertEquals(0, notifsBefore.length); 11699 11700 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11701 11702 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11703 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11704 nr.getSbn().getUid()); 11705 11706 // Grant permission still called if no NotificationRecord exists for the given key 11707 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11708 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 11709 anyInt(), eq(nr.getSbn().getUserId())); 11710 } 11711 11712 @Test 11713 public void testGrantInlineReplyUriPermission_userAll() throws Exception { 11714 // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM 11715 NotificationRecord nr = 11716 generateNotificationRecord(mTestNotificationChannel, UserHandle.USER_ALL); 11717 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 11718 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11719 waitForIdle(); 11720 11721 // A notification exists for the given record 11722 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11723 assertEquals(1, notifsBefore.length); 11724 11725 reset(mPackageManager); 11726 11727 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11728 11729 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11730 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11731 nr.getSbn().getUid()); 11732 11733 // Target user for the grant is USER_ALL instead of USER_SYSTEM 11734 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11735 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 11736 anyInt(), UserManager.isHeadlessSystemUserMode() 11737 ? eq(UserHandle.getUserId(UID_HEADLESS)) 11738 : eq(USER_SYSTEM)); 11739 } 11740 11741 @Test 11742 public void testGrantInlineReplyUriPermission_acrossUsers() throws Exception { 11743 // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM 11744 int otherUserId = 11; 11745 NotificationRecord nr = 11746 generateNotificationRecord(mTestNotificationChannel, otherUserId); 11747 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 11748 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11749 waitForIdle(); 11750 11751 // A notification exists for the given record 11752 List<StatusBarNotification> notifsBefore = 11753 mBinderService.getAppActiveNotifications(mPkg, nr.getSbn().getUserId()).getList(); 11754 assertEquals(1, notifsBefore.size()); 11755 11756 reset(mPackageManager); 11757 11758 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11759 11760 int uid = 0; // sysui on primary user 11761 int otherUserUid = (otherUserId * 100000) + 1; // sysui as a different user 11762 String sysuiPackage = "sysui"; 11763 final String[] sysuiPackages = new String[] { sysuiPackage }; 11764 when(mPackageManager.getPackagesForUid(uid)).thenReturn(sysuiPackages); 11765 11766 // Make sure to mock call for USER_SYSTEM and not USER_ALL, since it's been replaced by the 11767 // time this is called 11768 when(mPackageManager.getPackageUid(sysuiPackage, 0, otherUserId)) 11769 .thenReturn(otherUserUid); 11770 11771 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11772 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), uid); 11773 11774 // Target user for the grant is USER_ALL instead of USER_SYSTEM 11775 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11776 eq(otherUserUid), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), anyInt(), 11777 eq(otherUserId)); 11778 } 11779 11780 @Test 11781 public void testClearInlineReplyUriPermission_uriRecordExists() throws Exception { 11782 int userId = UserManager.isHeadlessSystemUserMode() 11783 ? UserHandle.getUserId(UID_HEADLESS) 11784 : USER_SYSTEM; 11785 11786 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 11787 reset(mPackageManager); 11788 11789 Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11790 Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2); 11791 11792 // create an inline record with two uris in it 11793 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11794 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11795 nr.getSbn().getUid()); 11796 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11797 nr.getKey(), uri2, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11798 nr.getSbn().getUid()); 11799 11800 InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey()); 11801 assertNotNull(record); // record exists 11802 assertEquals(record.getUris().size(), 2); // record has two uris in it 11803 11804 mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), 11805 nr.getSbn().getUid()); 11806 11807 // permissionOwner destroyed 11808 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner( 11809 eq(record.getPermissionOwner()), eq(null), eq(~0), eq(nr.getUserId())); 11810 } 11811 11812 11813 @Test 11814 public void testClearInlineReplyUriPermission_noUriRecordExists() throws Exception { 11815 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0); 11816 reset(mPackageManager); 11817 11818 mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), 11819 nr.getSbn().getUid()); 11820 11821 // no permissionOwner destroyed 11822 verify(mUgmInternal, times(0)).revokeUriPermissionFromOwner( 11823 any(), eq(null), eq(~0), eq(nr.getUserId())); 11824 } 11825 11826 @Test 11827 public void testClearInlineReplyUriPermission_userAll() throws Exception { 11828 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 11829 UserHandle.USER_ALL); 11830 reset(mPackageManager); 11831 11832 Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11833 11834 // create an inline record a uri in it 11835 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11836 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11837 nr.getSbn().getUid()); 11838 11839 InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey()); 11840 assertNotNull(record); // record exists 11841 11842 mService.mNotificationDelegate.clearInlineReplyUriPermissions( 11843 nr.getKey(), nr.getSbn().getUid()); 11844 11845 // permissionOwner destroyed for USER_SYSTEM, not USER_ALL 11846 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner( 11847 eq(record.getPermissionOwner()), eq(null), eq(~0), 11848 UserManager.isHeadlessSystemUserMode() 11849 ? eq(UserHandle.getUserId(UID_HEADLESS)) 11850 : eq(USER_SYSTEM)); 11851 } 11852 11853 @Test 11854 public void testNotificationBubbles_disabled_lowRamDevice() throws Exception { 11855 setUpPrefsForBubbles(mPkg, mUid, 11856 true /* global */, 11857 BUBBLE_PREFERENCE_ALL /* app */, 11858 true /* channel */); 11859 11860 // And we are low ram 11861 when(mActivityManager.isLowRamDevice()).thenReturn(true); 11862 11863 // Notification that would typically bubble 11864 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11865 "testNotificationBubbles_disabled_lowRamDevice"); 11866 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11867 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11868 waitForIdle(); 11869 11870 // But we wouldn't be a bubble because the device is low ram & all bubbles are disabled. 11871 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11872 assertEquals(1, notifsAfter.length); 11873 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 11874 } 11875 11876 @Test 11877 @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS) 11878 public void testRemoveLargeRemoteViews() throws Exception { 11879 int removeSize = mContext.getResources().getInteger( 11880 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); 11881 11882 RemoteViews rv = mock(RemoteViews.class); 11883 when(rv.estimateMemoryUsage()).thenReturn(removeSize); 11884 when(rv.clone()).thenReturn(rv); 11885 RemoteViews rv1 = mock(RemoteViews.class); 11886 when(rv1.estimateMemoryUsage()).thenReturn(removeSize); 11887 when(rv1.clone()).thenReturn(rv1); 11888 RemoteViews rv2 = mock(RemoteViews.class); 11889 when(rv2.estimateMemoryUsage()).thenReturn(removeSize); 11890 when(rv2.clone()).thenReturn(rv2); 11891 RemoteViews rv3 = mock(RemoteViews.class); 11892 when(rv3.estimateMemoryUsage()).thenReturn(removeSize); 11893 when(rv3.clone()).thenReturn(rv3); 11894 RemoteViews rv4 = mock(RemoteViews.class); 11895 when(rv4.estimateMemoryUsage()).thenReturn(removeSize); 11896 when(rv4.clone()).thenReturn(rv4); 11897 // note: different! 11898 RemoteViews rv5 = mock(RemoteViews.class); 11899 when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1); 11900 when(rv5.clone()).thenReturn(rv5); 11901 11902 Notification np = new Notification.Builder(mContext, "test") 11903 .setSmallIcon(android.R.drawable.sym_def_app_icon) 11904 .setContentText("test") 11905 .setCustomContentView(rv) 11906 .setCustomBigContentView(rv1) 11907 .setCustomHeadsUpContentView(rv2) 11908 .build(); 11909 Notification n = new Notification.Builder(mContext, "test") 11910 .setSmallIcon(android.R.drawable.sym_def_app_icon) 11911 .setContentText("test") 11912 .setCustomContentView(rv3) 11913 .setCustomBigContentView(rv4) 11914 .setCustomHeadsUpContentView(rv5) 11915 .setPublicVersion(np) 11916 .build(); 11917 11918 assertNotNull(np.contentView); 11919 assertNotNull(np.bigContentView); 11920 assertNotNull(np.headsUpContentView); 11921 11922 assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); 11923 assertNotNull(n.publicVersion.contentView); 11924 assertNotNull(n.publicVersion.bigContentView); 11925 assertNotNull(n.publicVersion.headsUpContentView); 11926 11927 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 11928 11929 assertNull(n.contentView); 11930 assertNull(n.bigContentView); 11931 assertNotNull(n.headsUpContentView); 11932 assertNull(n.publicVersion.contentView); 11933 assertNull(n.publicVersion.bigContentView); 11934 assertNull(n.publicVersion.headsUpContentView); 11935 11936 verify(mUsageStats, times(5)).registerImageRemoved(mPkg); 11937 } 11938 11939 @Test 11940 @EnableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS) 11941 public void testRemoveRemoteViews() throws Exception { 11942 Notification np = new Notification.Builder(mContext, "test") 11943 .setSmallIcon(android.R.drawable.sym_def_app_icon) 11944 .setContentText("test") 11945 .setCustomContentView(mock(RemoteViews.class)) 11946 .setCustomBigContentView(mock(RemoteViews.class)) 11947 .setCustomHeadsUpContentView(mock(RemoteViews.class)) 11948 .build(); 11949 Notification n = new Notification.Builder(mContext, "test") 11950 .setSmallIcon(android.R.drawable.sym_def_app_icon) 11951 .setContentText("test") 11952 .setCustomContentView(mock(RemoteViews.class)) 11953 .setCustomBigContentView(mock(RemoteViews.class)) 11954 .setCustomHeadsUpContentView(mock(RemoteViews.class)) 11955 .setPublicVersion(np) 11956 .build(); 11957 11958 assertNotNull(n.contentView); 11959 assertNotNull(n.bigContentView); 11960 assertNotNull(n.headsUpContentView); 11961 11962 assertTrue(np.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); 11963 assertNotNull(np.contentView); 11964 assertNotNull(np.bigContentView); 11965 assertNotNull(np.headsUpContentView); 11966 11967 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 11968 11969 assertNull(n.contentView); 11970 assertNull(n.bigContentView); 11971 assertNull(n.headsUpContentView); 11972 assertNull(n.publicVersion.contentView); 11973 assertNull(n.publicVersion.bigContentView); 11974 assertNull(n.publicVersion.headsUpContentView); 11975 11976 verify(mUsageStats, times(1)).registerImageRemoved(mPkg); 11977 } 11978 11979 @Test 11980 public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground() 11981 throws Exception { 11982 setUpPrefsForBubbles(mPkg, mUid, 11983 true /* global */, 11984 BUBBLE_PREFERENCE_ALL /* app */, 11985 true /* channel */); 11986 11987 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11988 "testNotificationBubbles_flagAutoExpandForeground_fails_notForeground"); 11989 // Modify metadata flags 11990 nr.getSbn().getNotification().getBubbleMetadata().setFlags( 11991 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE 11992 | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 11993 11994 // Ensure we're not foreground 11995 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 11996 IMPORTANCE_VISIBLE); 11997 11998 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11999 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12000 waitForIdle(); 12001 12002 // yes allowed, yes messaging, yes bubble 12003 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12004 assertTrue(notif.isBubbleNotification()); 12005 12006 // The flag should have failed since we're not foreground 12007 assertFalse(notif.getBubbleMetadata().getAutoExpandBubble()); 12008 } 12009 12010 @Test 12011 public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground() 12012 throws RemoteException { 12013 setUpPrefsForBubbles(mPkg, mUid, 12014 true /* global */, 12015 BUBBLE_PREFERENCE_ALL /* app */, 12016 true /* channel */); 12017 12018 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 12019 "testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground"); 12020 // Modify metadata flags 12021 nr.getSbn().getNotification().getBubbleMetadata().setFlags( 12022 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE 12023 | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 12024 12025 // Ensure we are in the foreground 12026 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 12027 IMPORTANCE_FOREGROUND); 12028 12029 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12030 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12031 waitForIdle(); 12032 12033 // yes allowed, yes messaging, yes bubble 12034 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12035 assertTrue(notif.isBubbleNotification()); 12036 12037 // Our flags should have passed since we are foreground 12038 assertTrue(notif.getBubbleMetadata().getAutoExpandBubble()); 12039 assertTrue(notif.getBubbleMetadata().isNotificationSuppressed()); 12040 } 12041 12042 @Test 12043 public void testNotificationBubbles_flagRemoved_whenShortcutRemoved() 12044 throws RemoteException { 12045 setUpPrefsForBubbles(mPkg, mUid, 12046 true /* global */, 12047 BUBBLE_PREFERENCE_ALL /* app */, 12048 true /* channel */); 12049 12050 ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback = 12051 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class); 12052 12053 // Messaging notification with shortcut info 12054 Notification.BubbleMetadata metadata = 12055 new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build(); 12056 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12057 null /* groupKey */, false /* isSummary */, true); 12058 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12059 nb.setBubbleMetadata(metadata); 12060 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12061 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12062 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12063 12064 // Test: Send the bubble notification 12065 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12066 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12067 waitForIdle(); 12068 12069 // Verify: 12070 12071 // Make sure we register the callback for shortcut changes 12072 verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback( 12073 shortcutChangeCallback.capture()); 12074 12075 // yes allowed, yes messaging w/shortcut, yes bubble 12076 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12077 assertTrue(notif.isBubbleNotification()); 12078 12079 // Make sure the shortcut is cached. 12080 verify(mShortcutServiceInternal).cacheShortcuts( 12081 anyInt(), any(), eq(mPkg), eq(singletonList(VALID_CONVO_SHORTCUT_ID)), 12082 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); 12083 12084 // Test: Remove the shortcut 12085 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12086 ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>(); 12087 removedShortcuts.add(createMockConvoShortcut()); 12088 shortcutChangeCallback.getValue().onShortcutsRemoved(mPkg, removedShortcuts, 12089 UserHandle.getUserHandleForUid(mUid)); 12090 waitForIdle(); 12091 12092 // Verify: 12093 12094 // Make sure callback is unregistered 12095 verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback( 12096 shortcutChangeCallback.getValue()); 12097 12098 // We're no longer a bubble 12099 NotificationRecord notif2 = mService.getNotificationRecord( 12100 nr.getSbn().getKey()); 12101 assertNull(notif2.getShortcutInfo()); 12102 assertFalse(notif2.getNotification().isBubbleNotification()); 12103 } 12104 12105 @Test 12106 public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved() 12107 throws RemoteException { 12108 final String shortcutId = "someshortcutId"; 12109 setUpPrefsForBubbles(mPkg, mUid, 12110 true /* global */, 12111 BUBBLE_PREFERENCE_ALL /* app */, 12112 true /* channel */); 12113 12114 ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback = 12115 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class); 12116 12117 // Messaging notification with shortcut info 12118 Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder( 12119 shortcutId).build(); 12120 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12121 null /* groupKey */, false /* isSummary */, true); 12122 nb.setShortcutId(shortcutId); 12123 nb.setBubbleMetadata(metadata); 12124 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12125 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12126 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12127 12128 // Pretend the shortcut exists 12129 List<ShortcutInfo> shortcutInfos = new ArrayList<>(); 12130 ShortcutInfo info = mock(ShortcutInfo.class); 12131 when(info.getPackage()).thenReturn(mPkg); 12132 when(info.getId()).thenReturn(shortcutId); 12133 when(info.getUserId()).thenReturn(USER_SYSTEM); 12134 when(info.isLongLived()).thenReturn(true); 12135 when(info.isEnabled()).thenReturn(true); 12136 shortcutInfos.add(info); 12137 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); 12138 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 12139 anyString(), anyInt(), any())).thenReturn(true); 12140 12141 // Test: Send the bubble notification 12142 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12143 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12144 waitForIdle(); 12145 12146 // Verify: 12147 12148 // Make sure we register the callback for shortcut changes 12149 verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback( 12150 shortcutChangeCallback.capture()); 12151 12152 // yes allowed, yes messaging w/shortcut, yes bubble 12153 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12154 assertTrue(notif.isBubbleNotification()); 12155 12156 // Make sure the shortcut is cached. 12157 verify(mShortcutServiceInternal).cacheShortcuts( 12158 anyInt(), any(), eq(mPkg), eq(singletonList(shortcutId)), 12159 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); 12160 12161 // Test: Remove the notification 12162 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12163 nr.getSbn().getId(), nr.getSbn().getUserId()); 12164 waitForIdle(); 12165 12166 // Verify: 12167 12168 // Make sure callback is unregistered 12169 verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback( 12170 shortcutChangeCallback.getValue()); 12171 } 12172 12173 @Test 12174 public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed() 12175 throws Exception { 12176 setUpPrefsForBubbles(mPkg, mUid, 12177 true /* global */, 12178 BUBBLE_PREFERENCE_ALL /* app */, 12179 true /* channel */); 12180 12181 NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( 12182 true /* summaryAutoCancel */); 12183 12184 // Dismiss summary 12185 final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, 12186 true); 12187 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, 12188 nrSummary.getUserId(), nrSummary.getKey(), 12189 NotificationStats.DISMISSAL_SHADE, 12190 NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv); 12191 waitForIdle(); 12192 12193 // The bubble should still exist 12194 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12195 assertEquals(1, notifsAfter.length); 12196 } 12197 12198 @Test 12199 public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked() 12200 throws Exception { 12201 setUpPrefsForBubbles(mPkg, mUid, 12202 true /* global */, 12203 BUBBLE_PREFERENCE_ALL /* app */, 12204 true /* channel */); 12205 12206 NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( 12207 true /* summaryAutoCancel */); 12208 12209 // Click summary 12210 final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, 12211 true); 12212 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 12213 nrSummary.getKey(), nv); 12214 waitForIdle(); 12215 12216 // The bubble should still exist 12217 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12218 assertEquals(1, notifsAfter.length); 12219 12220 // Check we got the click log and associated dismissal logs 12221 assertEquals(6, mNotificationRecordLogger.numCalls()); 12222 // Skip the notification-creation logs 12223 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 12224 mNotificationRecordLogger.event(3)); 12225 assertEquals(NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK, 12226 mNotificationRecordLogger.event(4)); 12227 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 12228 .NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED, 12229 mNotificationRecordLogger.event(5)); 12230 } 12231 12232 @Test 12233 public void testNotificationBubbles_bubbleStays_whenClicked() 12234 throws Exception { 12235 setUpPrefsForBubbles(mPkg, mUid, 12236 true /* global */, 12237 BUBBLE_PREFERENCE_ALL /* app */, 12238 true /* channel */); 12239 12240 // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble 12241 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 12242 nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL; 12243 mService.addNotification(nr); 12244 12245 // WHEN we click the notification 12246 final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true); 12247 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 12248 nr.getKey(), nv); 12249 waitForIdle(); 12250 12251 // THEN the bubble should still exist 12252 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12253 assertEquals(1, notifsAfter.length); 12254 12255 // Check we got the click log 12256 assertEquals(1, mNotificationRecordLogger.numCalls()); 12257 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 12258 mNotificationRecordLogger.event(0)); 12259 } 12260 12261 /** 12262 * When something is bubble'd and the bubble is dismissed, but the notification is still 12263 * visible, clicking on the notification shouldn't auto-cancel it because clicking on 12264 * it will produce a bubble. 12265 */ 12266 @Test 12267 public void testNotificationBubbles_bubbleStays_whenClicked_afterBubbleDismissed() 12268 throws Exception { 12269 setUpPrefsForBubbles(mPkg, mUid, 12270 true /* global */, 12271 BUBBLE_PREFERENCE_ALL /* app */, 12272 true /* channel */); 12273 12274 // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble 12275 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 12276 nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL; 12277 nr.setAllowBubble(true); 12278 mService.addNotification(nr); 12279 12280 // And the bubble is dismissed 12281 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), 12282 false /* isBubble */, 0 /* bubbleFlags */); 12283 waitForIdle(); 12284 assertTrue(nr.isFlagBubbleRemoved()); 12285 12286 // WHEN we click the notification 12287 final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true); 12288 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 12289 nr.getKey(), nv); 12290 waitForIdle(); 12291 12292 // THEN the bubble should still exist 12293 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12294 assertEquals(1, notifsAfter.length); 12295 12296 // Check we got the click log 12297 assertEquals(1, mNotificationRecordLogger.numCalls()); 12298 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 12299 mNotificationRecordLogger.event(0)); 12300 } 12301 12302 @Test 12303 public void testLoadDefaultApprovedServices_emptyResources() { 12304 TestableResources tr = mContext.getOrCreateTestableResources(); 12305 tr.addOverride(com.android.internal.R.string.config_defaultListenerAccessPackages, ""); 12306 tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, ""); 12307 tr.addOverride(com.android.internal.R.string.config_defaultAssistantAccessComponent, ""); 12308 12309 mService.loadDefaultApprovedServices(USER_SYSTEM); 12310 12311 verify(mListeners, never()).addDefaultComponentOrPackage(anyString()); 12312 verify(mConditionProviders, never()).addDefaultComponentOrPackage(anyString()); 12313 verify(mAssistants, never()).addDefaultComponentOrPackage(anyString()); 12314 } 12315 12316 @Test 12317 public void testLoadDefaultApprovedServices_dnd() { 12318 TestableResources tr = mContext.getOrCreateTestableResources(); 12319 tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "test"); 12320 when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt())) 12321 .thenReturn(new ArraySet<>()); 12322 12323 mService.loadDefaultApprovedServices(USER_SYSTEM); 12324 12325 verify(mConditionProviders, times(1)).loadDefaultsFromConfig(); 12326 } 12327 12328 // TODO: add tests for the rest of the non-empty cases 12329 12330 @Test 12331 public void testOnUnlockUser() { 12332 UserInfo ui = new UserInfo(); 12333 ui.id = 10; 12334 mService.onUserUnlocked(new TargetUser(ui)); 12335 waitForIdle(); 12336 12337 verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id); 12338 } 12339 12340 @Test 12341 public void testOnStopUser() { 12342 UserInfo ui = new UserInfo(); 12343 ui.id = 10; 12344 mService.onUserStopping(new TargetUser(ui)); 12345 waitForIdle(); 12346 12347 verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id); 12348 } 12349 12350 @Test 12351 public void testHandleOnPackageChanged() { 12352 String[] pkgs = new String[] {mPkg, PKG_N_MR1}; 12353 int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1}; 12354 12355 mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids); 12356 12357 verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString()); 12358 12359 mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids); 12360 12361 verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]); 12362 verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]); 12363 } 12364 12365 @Test 12366 public void testHandleOnPackageRemoved_ClearsHistory() throws Exception { 12367 // Enables Notification History setting 12368 setUpPrefsForHistory(mUserId, true /* =enabled */); 12369 12370 // Posts a notification to the mTestNotificationChannel. 12371 final NotificationRecord notif = generateNotificationRecord( 12372 mTestNotificationChannel, 1, null, false); 12373 mService.addNotification(notif); 12374 StatusBarNotification[] notifs = mBinderService.getActiveNotifications( 12375 notif.getSbn().getPackageName()); 12376 assertEquals(1, notifs.length); 12377 12378 // Cancels all notifications. 12379 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 12380 notif.getUserId(), REASON_CANCEL); 12381 waitForIdle(); 12382 notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 12383 assertEquals(0, notifs.length); 12384 12385 // Checks that notification history's recently canceled archive contains the notification. 12386 notifs = mBinderService.getHistoricalNotificationsWithAttribution(mPkg, 12387 mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); 12388 waitForIdle(); 12389 assertEquals(1, notifs.length); 12390 12391 // Remove sthe package that contained the channel 12392 simulatePackageRemovedBroadcast(mPkg, mUid); 12393 waitForIdle(); 12394 12395 // Checks that notification history no longer contains the notification. 12396 notifs = mBinderService.getHistoricalNotificationsWithAttribution( 12397 mPkg, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); 12398 waitForIdle(); 12399 assertEquals(0, notifs.length); 12400 } 12401 12402 @Test 12403 public void testNotificationHistory_addNoisyNotification() throws Exception { 12404 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 12405 null /* tvExtender */); 12406 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12407 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12408 waitForIdle(); 12409 12410 verify(mHistoryManager, times(1)).addNotification(any()); 12411 } 12412 12413 @Test 12414 public void createConversationNotificationChannel() throws Exception { 12415 int userId = UserManager.isHeadlessSystemUserMode() 12416 ? UserHandle.getUserId(UID_HEADLESS) 12417 : USER_SYSTEM; 12418 12419 NotificationChannel original = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 12420 original.setAllowBubbles(!original.canBubble()); 12421 original.setShowBadge(!original.canShowBadge()); 12422 12423 Parcel parcel = Parcel.obtain(); 12424 original.writeToParcel(parcel, 0); 12425 parcel.setDataPosition(0); 12426 NotificationChannel orig = NotificationChannel.CREATOR.createFromParcel(parcel); 12427 assertEquals(original, orig); 12428 assertFalse(TextUtils.isEmpty(orig.getName())); 12429 12430 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(Arrays.asList( 12431 orig))); 12432 12433 mBinderService.createConversationNotificationChannelForPackage( 12434 mPkg, mUid, orig, "friend"); 12435 12436 NotificationChannel friendChannel = mBinderService.getConversationNotificationChannel( 12437 mPkg, userId, mPkg, original.getId(), false, "friend"); 12438 12439 assertEquals(original.getName(), friendChannel.getName()); 12440 assertEquals(original.getId(), friendChannel.getParentChannelId()); 12441 assertEquals("friend", friendChannel.getConversationId()); 12442 assertEquals(null, original.getConversationId()); 12443 assertEquals(original.canShowBadge(), friendChannel.canShowBadge()); 12444 assertFalse(friendChannel.canBubble()); // can't be modified by app 12445 assertFalse(original.getId().equals(friendChannel.getId())); 12446 assertNotNull(friendChannel.getId()); 12447 } 12448 12449 @Test 12450 public void testCorrectCategory_systemOn_appCannotTurnOff() { 12451 int requested = 0; 12452 int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12453 12454 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12455 system); 12456 12457 assertEquals(PRIORITY_CATEGORY_CONVERSATIONS, actual); 12458 } 12459 12460 @Test 12461 public void testCorrectCategory_systemOff_appTurnOff_noChanges() { 12462 int requested = PRIORITY_CATEGORY_CALLS; 12463 int system = PRIORITY_CATEGORY_CALLS; 12464 12465 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12466 system); 12467 12468 assertEquals(PRIORITY_CATEGORY_CALLS, actual); 12469 } 12470 12471 @Test 12472 public void testCorrectCategory_systemOn_appTurnOn_noChanges() { 12473 int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12474 int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12475 12476 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12477 system); 12478 12479 assertEquals(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS, actual); 12480 } 12481 12482 @Test 12483 public void testCorrectCategory_systemOff_appCannotTurnOn() { 12484 int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12485 int system = PRIORITY_CATEGORY_CALLS; 12486 12487 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12488 system); 12489 12490 assertEquals(PRIORITY_CATEGORY_CALLS, actual); 12491 } 12492 12493 @Test 12494 public void testRestoreConversationChannel_deleted() throws Exception { 12495 // Create parent channel 12496 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12497 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12498 IMPORTANCE_DEFAULT); 12499 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12500 NotificationChannel.CREATOR); 12501 assertEquals(originalChannel, parentChannel); 12502 mBinderService.createNotificationChannels(mPkg, 12503 new ParceledListSlice(Arrays.asList(parentChannel))); 12504 12505 //Create deleted conversation channel 12506 mBinderService.createConversationNotificationChannelForPackage( 12507 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 12508 final NotificationChannel conversationChannel = 12509 mBinderService.getConversationNotificationChannel( 12510 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 12511 conversationChannel.setDeleted(true); 12512 12513 //Create notification record 12514 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12515 null /* groupKey */, false /* isSummary */, true); 12516 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12517 nb.setChannelId(originalChannel.getId()); 12518 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12519 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12520 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12521 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12522 12523 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12524 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12525 waitForIdle(); 12526 12527 // Verify that the channel was changed to the conversation channel and restored 12528 assertThat(mService.getNotificationRecord(nr.getKey()).isConversation()).isTrue(); 12529 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 12530 conversationChannel); 12531 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().isDeleted()).isFalse(); 12532 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().getDeletedTimeMs()) 12533 .isEqualTo(-1); 12534 } 12535 12536 @Test 12537 public void testDoNotRestoreParentChannel_deleted() throws Exception { 12538 // Create parent channel and set as deleted 12539 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12540 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12541 IMPORTANCE_DEFAULT); 12542 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12543 NotificationChannel.CREATOR); 12544 assertEquals(originalChannel, parentChannel); 12545 mBinderService.createNotificationChannels(mPkg, 12546 new ParceledListSlice(Arrays.asList(parentChannel))); 12547 parentChannel.setDeleted(true); 12548 12549 //Create notification record 12550 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12551 null /* groupKey */, false /* isSummary */, true); 12552 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12553 nb.setChannelId(originalChannel.getId()); 12554 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12555 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12556 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12557 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12558 12559 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 12560 12561 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12562 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12563 waitForIdle(); 12564 12565 // Verify that the channel was not restored and the notification was not posted 12566 assertThat(mService.mChannelToastsSent).contains(mUid); 12567 assertThat(mService.getNotificationRecord(nr.getKey())).isNull(); 12568 assertThat(parentChannel.isDeleted()).isTrue(); 12569 } 12570 12571 @Test 12572 public void testEnqueueToConversationChannel_notDeleted_doesNotRestore() throws Exception { 12573 TestableNotificationManagerService service = spy(mService); 12574 PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper); 12575 service.setPreferencesHelper(preferencesHelper); 12576 // Create parent channel 12577 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12578 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12579 IMPORTANCE_DEFAULT); 12580 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12581 NotificationChannel.CREATOR); 12582 assertEquals(originalChannel, parentChannel); 12583 mBinderService.createNotificationChannels(mPkg, 12584 new ParceledListSlice(Arrays.asList(parentChannel))); 12585 12586 //Create conversation channel 12587 mBinderService.createConversationNotificationChannelForPackage( 12588 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 12589 final NotificationChannel conversationChannel = 12590 mBinderService.getConversationNotificationChannel( 12591 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 12592 12593 //Create notification record 12594 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12595 null /* groupKey */, false /* isSummary */, true); 12596 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12597 nb.setChannelId(originalChannel.getId()); 12598 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12599 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12600 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12601 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12602 12603 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12604 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12605 waitForIdle(); 12606 12607 // Verify that the channel was changed to the conversation channel and not restored 12608 assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isTrue(); 12609 assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 12610 conversationChannel); 12611 verify(service, never()).handleSavePolicyFile(); 12612 verify(preferencesHelper, never()).createNotificationChannel(anyString(), 12613 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()); 12614 } 12615 12616 @Test 12617 public void testEnqueueToParentChannel_notDeleted_doesNotRestore() throws Exception { 12618 TestableNotificationManagerService service = spy(mService); 12619 PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper); 12620 service.setPreferencesHelper(preferencesHelper); 12621 // Create parent channel 12622 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12623 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12624 IMPORTANCE_DEFAULT); 12625 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12626 NotificationChannel.CREATOR); 12627 assertEquals(originalChannel, parentChannel); 12628 mBinderService.createNotificationChannels(mPkg, 12629 new ParceledListSlice(Arrays.asList(parentChannel))); 12630 12631 //Create deleted conversation channel 12632 mBinderService.createConversationNotificationChannelForPackage( 12633 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 12634 final NotificationChannel conversationChannel = 12635 mBinderService.getConversationNotificationChannel( 12636 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 12637 12638 //Create notification record without a shortcutId 12639 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12640 null /* groupKey */, false /* isSummary */, true); 12641 nb.setShortcutId(null); 12642 nb.setChannelId(originalChannel.getId()); 12643 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12644 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12645 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12646 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12647 12648 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12649 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12650 waitForIdle(); 12651 12652 // Verify that the channel is the parent channel and no channel was restored 12653 //assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isFalse(); 12654 assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 12655 parentChannel); 12656 verify(service, never()).handleSavePolicyFile(); 12657 verify(preferencesHelper, never()).createNotificationChannel(anyString(), 12658 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()); 12659 } 12660 12661 @Test 12662 public void testGetConversationsForPackage_hasShortcut() throws Exception { 12663 mService.setPreferencesHelper(mPreferencesHelper); 12664 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 12665 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 12666 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 12667 channel1.setConversationId("parent1", "convo 1"); 12668 convo1.setNotificationChannel(channel1); 12669 convos.add(convo1); 12670 12671 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 12672 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 12673 channel2.setConversationId("parent1", "convo 2"); 12674 convo2.setNotificationChannel(channel2); 12675 convos.add(convo2); 12676 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 12677 12678 ShortcutInfo si = mock(ShortcutInfo.class); 12679 when(si.getPackage()).thenReturn(PKG_P); 12680 when(si.getId()).thenReturn("convo"); 12681 when(si.getUserId()).thenReturn(USER_SYSTEM); 12682 when(si.getLabel()).thenReturn("Hello"); 12683 when(si.isLongLived()).thenReturn(true); 12684 when(si.isEnabled()).thenReturn(true); 12685 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); 12686 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 12687 anyString(), anyInt(), any())).thenReturn(true); 12688 12689 List<ConversationChannelWrapper> conversations = 12690 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12691 assertEquals(si, conversations.get(0).getShortcutInfo()); 12692 assertEquals(si, conversations.get(1).getShortcutInfo()); 12693 12694 // Returns null shortcuts when locked. 12695 when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(false); 12696 conversations = 12697 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12698 assertThat(conversations.get(0).getShortcutInfo()).isNull(); 12699 assertThat(conversations.get(1).getShortcutInfo()).isNull(); 12700 } 12701 12702 @Test 12703 public void testGetConversationsForPackage_shortcut_notLongLived() throws Exception { 12704 mService.setPreferencesHelper(mPreferencesHelper); 12705 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 12706 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 12707 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 12708 channel1.setConversationId("parent1", "convo 1"); 12709 convo1.setNotificationChannel(channel1); 12710 convos.add(convo1); 12711 12712 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 12713 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 12714 channel2.setConversationId("parent1", "convo 2"); 12715 convo2.setNotificationChannel(channel2); 12716 convos.add(convo2); 12717 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 12718 12719 ShortcutInfo si = mock(ShortcutInfo.class); 12720 when(si.getPackage()).thenReturn(PKG_P); 12721 when(si.getId()).thenReturn("convo"); 12722 when(si.getUserId()).thenReturn(USER_SYSTEM); 12723 when(si.getLabel()).thenReturn("Hello"); 12724 when(si.isLongLived()).thenReturn(false); 12725 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); 12726 12727 List<ConversationChannelWrapper> conversations = 12728 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12729 assertNull(conversations.get(0).getShortcutInfo()); 12730 assertNull(conversations.get(1).getShortcutInfo()); 12731 } 12732 12733 @Test 12734 public void testGetConversationsForPackage_doesNotHaveShortcut() throws Exception { 12735 mService.setPreferencesHelper(mPreferencesHelper); 12736 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 12737 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 12738 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 12739 channel1.setConversationId("parent1", "convo 1"); 12740 convo1.setNotificationChannel(channel1); 12741 convos.add(convo1); 12742 12743 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 12744 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 12745 channel2.setConversationId("parent1", "convo 2"); 12746 convo2.setNotificationChannel(channel2); 12747 convos.add(convo2); 12748 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 12749 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12750 12751 List<ConversationChannelWrapper> conversations = 12752 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12753 assertNull(conversations.get(0).getShortcutInfo()); 12754 assertNull(conversations.get(1).getShortcutInfo()); 12755 } 12756 12757 @Test 12758 public void testShortcutHelperNull_doesntCrashEnqueue() throws RemoteException { 12759 mService.setShortcutHelper(null); 12760 NotificationRecord nr = 12761 generateMessageBubbleNotifRecord(mTestNotificationChannel, 12762 "testShortcutHelperNull_doesntCrashEnqueue"); 12763 try { 12764 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12765 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12766 waitForIdle(); 12767 } catch (Exception e) { 12768 fail(e.getMessage()); 12769 } 12770 } 12771 12772 @Test 12773 public void testRecordMessages_invalidMsg() throws RemoteException { 12774 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12775 null /* groupKey */, false /* isSummary */, true); 12776 nb.setShortcutId(null); 12777 StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1, 12778 "testRecordMessages_invalidMsg", mUid, 0, nb.build(), 12779 UserHandle.getUserHandleForUid(mUid), null, 0); 12780 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12781 12782 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12783 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 12784 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12785 waitForIdle(); 12786 12787 assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 12788 } 12789 12790 @Test 12791 public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException { 12792 Notification.Builder nb = new Notification.Builder(mContext, 12793 mTestNotificationChannel.getId()) 12794 .setContentTitle("foo") 12795 .setShortcutId(null) 12796 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12797 .setCategory(Notification.CATEGORY_MESSAGE); 12798 StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1, 12799 "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(), 12800 UserHandle.getUserHandleForUid(mUid), null, 0); 12801 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12802 12803 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12804 mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(), 12805 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12806 waitForIdle(); 12807 12808 // PKG_O is allowed to be in conversation space b/c of override in 12809 // TestableNotificationManagerService 12810 assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid)); 12811 } 12812 12813 @Test 12814 public void testRecordMessages_validMsg() throws RemoteException { 12815 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12816 null /* groupKey */, false /* isSummary */, true); 12817 nb.setShortcutId(null); 12818 StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1, 12819 "testRecordMessages_validMsg", mUid, 0, nb.build(), 12820 UserHandle.getUserHandleForUid(mUid), null, 0); 12821 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12822 12823 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 12824 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12825 waitForIdle(); 12826 12827 assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 12828 12829 nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 12830 "testRecordMessages_validMsg"); 12831 12832 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 12833 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12834 waitForIdle(); 12835 12836 assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 12837 } 12838 12839 @Test 12840 public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException { 12841 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 12842 "testRecordMessages_invalidMsg_afterValidMsg_1"); 12843 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12844 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12845 waitForIdle(); 12846 assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation()); 12847 12848 mBinderService.cancelAllNotifications(mPkg, mUid); 12849 waitForIdle(); 12850 12851 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12852 null /* groupKey */, false /* isSummary */, true); 12853 nb.setShortcutId(null); 12854 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12855 "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(), 12856 UserHandle.getUserHandleForUid(mUid), null, 0); 12857 nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12858 12859 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12860 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12861 waitForIdle(); 12862 12863 assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation()); 12864 } 12865 12866 @Test 12867 public void testCanPostFgsWhenOverLimit() throws RemoteException { 12868 when(mAmi.applyForegroundServiceNotification( 12869 any(), anyString(), anyInt(), anyString(), anyInt())) 12870 .thenReturn(SHOW_IMMEDIATELY); 12871 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 12872 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 12873 i, null, false).getSbn(); 12874 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12875 "testCanPostFgsWhenOverLimit", 12876 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 12877 } 12878 12879 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 12880 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 12881 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12882 "testCanPostFgsWhenOverLimit - fgs over limit!", 12883 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 12884 12885 waitForIdle(); 12886 12887 StatusBarNotification[] notifs = 12888 mBinderService.getActiveNotifications(sbn.getPackageName()); 12889 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 12890 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 12891 mService.getNotificationRecordCount()); 12892 } 12893 12894 @Test 12895 public void testCannotPostNonFgsWhenOverLimit() throws RemoteException { 12896 when(mAmi.applyForegroundServiceNotification( 12897 any(), anyString(), anyInt(), anyString(), anyInt())) 12898 .thenReturn(SHOW_IMMEDIATELY); 12899 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 12900 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 12901 i, null, false).getSbn(); 12902 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12903 "testCanPostFgsWhenOverLimit", 12904 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 12905 waitForIdle(); 12906 } 12907 12908 final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 12909 100, null, false).getSbn(); 12910 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 12911 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12912 "testCanPostFgsWhenOverLimit - fgs over limit!", 12913 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 12914 12915 final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel, 12916 101, null, false).getSbn(); 12917 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12918 "testCanPostFgsWhenOverLimit - non fgs over limit!", 12919 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId()); 12920 12921 12922 when(mAmi.applyForegroundServiceNotification( 12923 any(), anyString(), anyInt(), anyString(), anyInt())) 12924 .thenReturn(NOT_FOREGROUND_SERVICE); 12925 final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel, 12926 101, null, false).getSbn(); 12927 sbn3.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 12928 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12929 "testCanPostFgsWhenOverLimit - fake fgs over limit!", 12930 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId()); 12931 12932 waitForIdle(); 12933 12934 StatusBarNotification[] notifs = 12935 mBinderService.getActiveNotifications(sbn.getPackageName()); 12936 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 12937 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 12938 mService.getNotificationRecordCount()); 12939 } 12940 12941 @Test 12942 public void testIsVisibleToListener_notEnabled() { 12943 StatusBarNotification sbn = mock(StatusBarNotification.class); 12944 when(sbn.getUserId()).thenReturn(10); 12945 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12946 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 12947 info.userid = 10; 12948 when(info.isSameUser(anyInt())).thenReturn(true); 12949 when(assistant.isSameUser(anyInt())).thenReturn(true); 12950 when(info.enabledAndUserMatches(info.userid)).thenReturn(false); 12951 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 12952 12953 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 12954 } 12955 12956 @Test 12957 public void testIsVisibleToListener_noAssistant() { 12958 StatusBarNotification sbn = mock(StatusBarNotification.class); 12959 when(sbn.getUserId()).thenReturn(10); 12960 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12961 info.userid = 10; 12962 when(info.isSameUser(anyInt())).thenReturn(true); 12963 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 12964 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null); 12965 12966 assertTrue(mService.isVisibleToListener(sbn, 0, info)); 12967 } 12968 12969 @Test 12970 public void testIsVisibleToListener_assistant_differentUser() { 12971 StatusBarNotification sbn = mock(StatusBarNotification.class); 12972 when(sbn.getUserId()).thenReturn(10); 12973 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12974 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 12975 info.userid = 0; 12976 when(info.isSameUser(anyInt())).thenReturn(true); 12977 when(assistant.isSameUser(anyInt())).thenReturn(true); 12978 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 12979 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 12980 12981 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 12982 } 12983 12984 @Test 12985 public void testIsVisibleToListener_assistant_sameUser() { 12986 StatusBarNotification sbn = mock(StatusBarNotification.class); 12987 when(sbn.getUserId()).thenReturn(10); 12988 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 12989 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 12990 info.userid = 10; 12991 when(info.isSameUser(anyInt())).thenReturn(true); 12992 when(assistant.isSameUser(anyInt())).thenReturn(true); 12993 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 12994 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 12995 12996 assertTrue(mService.isVisibleToListener(sbn, 0, info)); 12997 } 12998 12999 @Test 13000 public void testIsVisibleToListener_mismatchedType() { 13001 when(mNlf.isTypeAllowed(anyInt())).thenReturn(false); 13002 13003 StatusBarNotification sbn = mock(StatusBarNotification.class); 13004 when(sbn.getUserId()).thenReturn(10); 13005 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13006 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 13007 info.userid = 10; 13008 when(info.isSameUser(anyInt())).thenReturn(true); 13009 when(assistant.isSameUser(anyInt())).thenReturn(true); 13010 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 13011 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 13012 13013 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 13014 } 13015 13016 @Test 13017 public void testIsVisibleToListener_disallowedPackage() { 13018 when(mNlf.isPackageAllowed(any())).thenReturn(false); 13019 13020 StatusBarNotification sbn = mock(StatusBarNotification.class); 13021 when(sbn.getUserId()).thenReturn(10); 13022 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13023 ManagedServices.ManagedServiceInfo assistant = 13024 mock(ManagedServices.ManagedServiceInfo.class); 13025 info.userid = 10; 13026 when(info.isSameUser(anyInt())).thenReturn(true); 13027 when(assistant.isSameUser(anyInt())).thenReturn(true); 13028 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 13029 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 13030 13031 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 13032 } 13033 13034 @Test 13035 public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedFirst() { 13036 final NotificationRecord parent = spy(generateNotificationRecord( 13037 mTestNotificationChannel, 1, "group", true)); 13038 final NotificationRecord child = spy(generateNotificationRecord( 13039 mTestNotificationChannel, 2, "group", false)); 13040 mService.addNotification(parent); 13041 mService.addNotification(child); 13042 13043 InOrder inOrder = inOrder(parent, child); 13044 13045 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 13046 parent.getUserId()); 13047 waitForIdle(); 13048 inOrder.verify(parent).recordDismissalSentiment(anyInt()); 13049 inOrder.verify(child).recordDismissalSentiment(anyInt()); 13050 } 13051 13052 @Test 13053 public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedSecond() { 13054 final NotificationRecord parent = spy(generateNotificationRecord( 13055 mTestNotificationChannel, 1, "group", true)); 13056 final NotificationRecord child = spy(generateNotificationRecord( 13057 mTestNotificationChannel, 2, "group", false)); 13058 mService.addNotification(child); 13059 mService.addNotification(parent); 13060 13061 InOrder inOrder = inOrder(parent, child); 13062 13063 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 13064 parent.getUserId()); 13065 waitForIdle(); 13066 inOrder.verify(parent).recordDismissalSentiment(anyInt()); 13067 inOrder.verify(child).recordDismissalSentiment(anyInt()); 13068 } 13069 13070 @Test 13071 public void testImmutableBubbleIntent() throws Exception { 13072 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13073 NotificationRecord r = generateMessageBubbleNotifRecord(true, 13074 mTestNotificationChannel, 7, "testImmutableBubbleIntent", null, false, false); 13075 try { 13076 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13077 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13078 13079 waitForIdle(); 13080 fail("Allowed a bubble with an immutable intent to be posted"); 13081 } catch (IllegalArgumentException e) { 13082 // good 13083 } 13084 } 13085 13086 @Test 13087 public void testMutableBubbleIntent() throws Exception { 13088 NotificationRecord r = generateMessageBubbleNotifRecord(true, 13089 mTestNotificationChannel, 7, "testMutableBubbleIntent", null, false, true); 13090 13091 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13092 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13093 13094 waitForIdle(); 13095 StatusBarNotification[] notifs = 13096 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 13097 assertEquals(1, notifs.length); 13098 } 13099 13100 @Test 13101 public void testImmutableDirectReplyActionIntent() throws Exception { 13102 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13103 NotificationRecord r = generateMessageBubbleNotifRecord(false, 13104 mTestNotificationChannel, 7, "testImmutableDirectReplyActionIntent", null, false, 13105 false); 13106 try { 13107 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13108 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13109 13110 waitForIdle(); 13111 fail("Allowed a direct reply with an immutable intent to be posted"); 13112 } catch (IllegalArgumentException e) { 13113 // good 13114 } 13115 } 13116 13117 @Test 13118 public void testMutableDirectReplyActionIntent() throws Exception { 13119 NotificationRecord r = generateMessageBubbleNotifRecord(false, 13120 mTestNotificationChannel, 7, "testMutableDirectReplyActionIntent", null, false, 13121 true); 13122 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13123 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13124 13125 waitForIdle(); 13126 StatusBarNotification[] notifs = 13127 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 13128 assertEquals(1, notifs.length); 13129 } 13130 13131 @Test 13132 public void testImmutableDirectReplyContextualActionIntent() throws Exception { 13133 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13134 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13135 13136 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13137 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 13138 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 13139 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 13140 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 13141 mActivityIntentImmutable).addRemoteInput(remoteInput) 13142 .build(); 13143 extraAction.add(replyAction); 13144 Bundle signals = new Bundle(); 13145 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 13146 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 13147 r.getUser()); 13148 r.addAdjustment(adjustment); 13149 r.applyAdjustments(); 13150 13151 try { 13152 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 13153 r.getSbn().getTag(), r, false, false); 13154 fail("Allowed a contextual direct reply with an immutable intent to be posted"); 13155 } catch (IllegalArgumentException e) { 13156 // good 13157 } 13158 } 13159 13160 @Test 13161 public void testMutableDirectReplyContextualActionIntent() throws Exception { 13162 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13163 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13164 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 13165 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 13166 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 13167 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 13168 mActivityIntent).addRemoteInput(remoteInput) 13169 .build(); 13170 extraAction.add(replyAction); 13171 Bundle signals = new Bundle(); 13172 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 13173 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 13174 r.getUser()); 13175 r.addAdjustment(adjustment); 13176 r.applyAdjustments(); 13177 13178 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 13179 r.getSbn().getTag(), r, false, false); 13180 } 13181 13182 @Test 13183 public void testImmutableActionIntent() throws Exception { 13184 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13185 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13186 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13187 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13188 13189 waitForIdle(); 13190 StatusBarNotification[] notifs = 13191 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 13192 assertEquals(1, notifs.length); 13193 } 13194 13195 @Test 13196 public void testImmutableContextualActionIntent() throws Exception { 13197 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13198 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13199 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13200 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 13201 extraAction.add(new Notification.Action(0, "hello", mActivityIntentImmutable)); 13202 Bundle signals = new Bundle(); 13203 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 13204 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 13205 r.getUser()); 13206 r.addAdjustment(adjustment); 13207 r.applyAdjustments(); 13208 13209 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 13210 r.getSbn().getTag(), r, false, false); 13211 } 13212 13213 @Test 13214 public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception { 13215 int uid = 9000; 13216 int[] userIds = new int[] {mUserId, 1000}; 13217 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13218 List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); 13219 for (int userId : userIds) { 13220 for (String pkg : disallowedApps) { 13221 when(mPackageManager.getPackageUid(pkg, 0, userId)).thenReturn(uid++); 13222 } 13223 } 13224 13225 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 13226 new NotificationListenerFilter()); 13227 13228 mBinderService.migrateNotificationFilter(null, 13229 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13230 disallowedApps); 13231 13232 ArgumentCaptor<NotificationListenerFilter> captor = 13233 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13234 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13235 13236 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13237 captor.getValue().getTypes()); 13238 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9000))); 13239 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9002))); 13240 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9003))); 13241 13242 // hypothetical other user untouched 13243 assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 10000))); 13244 } 13245 13246 @Test 13247 public void testMigrateNotificationFilter_invalidPackage() throws Exception { 13248 int[] userIds = new int[] {mUserId, 1000}; 13249 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13250 List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); 13251 for (int userId : userIds) { 13252 when(mPackageManager.getPackageUid("apples", 0, userId)).thenThrow( 13253 new RemoteException("")); 13254 when(mPackageManager.getPackageUid("bananas", 0, userId)).thenReturn(9000); 13255 when(mPackageManager.getPackageUid("cherries", 0, userId)).thenReturn(9001); 13256 } 13257 13258 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 13259 new NotificationListenerFilter()); 13260 13261 mBinderService.migrateNotificationFilter(null, 13262 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13263 disallowedApps); 13264 13265 ArgumentCaptor<NotificationListenerFilter> captor = 13266 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13267 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13268 13269 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13270 captor.getValue().getTypes()); 13271 // valid values stay 13272 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("bananas", 9000))); 13273 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9001))); 13274 // don't store invalid values 13275 for (VersionedPackage vp : captor.getValue().getDisallowedPackages()) { 13276 assertNotEquals("apples", vp.getPackageName()); 13277 } 13278 } 13279 13280 @Test 13281 public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception { 13282 int[] userIds = new int[] {mUserId}; 13283 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13284 List<String> disallowedApps = ImmutableList.of("apples"); 13285 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 13286 .thenReturn(1001); 13287 13288 when(mListeners.getNotificationListenerFilter(any())).thenReturn(null); 13289 13290 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 13291 disallowedApps); 13292 13293 ArgumentCaptor<NotificationListenerFilter> captor = 13294 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13295 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13296 13297 assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes()); 13298 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 13299 } 13300 13301 @Test 13302 public void testMigrateNotificationFilter_existingTypeFilter() throws Exception { 13303 int[] userIds = new int[] {mUserId}; 13304 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13305 List<String> disallowedApps = ImmutableList.of("apples"); 13306 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 13307 .thenReturn(1001); 13308 13309 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 13310 new NotificationListenerFilter(FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>())); 13311 13312 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 13313 disallowedApps); 13314 13315 ArgumentCaptor<NotificationListenerFilter> captor = 13316 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13317 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13318 13319 // type isn't saved but pkg list is 13320 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, captor.getValue().getTypes()); 13321 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 13322 } 13323 13324 @Test 13325 public void testMigrateNotificationFilter_existingPkgFilter() throws Exception { 13326 int[] userIds = new int[] {mUserId}; 13327 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13328 List<String> disallowedApps = ImmutableList.of("apples"); 13329 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 13330 .thenReturn(1001); 13331 13332 NotificationListenerFilter preexisting = new NotificationListenerFilter(); 13333 preexisting.addPackage(new VersionedPackage("test", 1002)); 13334 when(mListeners.getNotificationListenerFilter(any())).thenReturn(preexisting); 13335 13336 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 13337 disallowedApps); 13338 13339 ArgumentCaptor<NotificationListenerFilter> captor = 13340 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13341 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13342 13343 // type is saved but pkg list isn't 13344 assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes()); 13345 assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 13346 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002))); 13347 } 13348 13349 @Test 13350 public void getPackagesBypassingDnd_blocked() 13351 throws RemoteException, PackageManager.NameNotFoundException { 13352 13353 NotificationChannel channel1 = new NotificationChannel("id1", "name1", 13354 NotificationManager.IMPORTANCE_MAX); 13355 NotificationChannel channel2 = new NotificationChannel("id3", "name3", 13356 NotificationManager.IMPORTANCE_MAX); 13357 NotificationChannel channel3 = new NotificationChannel("id4", "name3", 13358 NotificationManager.IMPORTANCE_MAX); 13359 channel1.setBypassDnd(true); 13360 channel2.setBypassDnd(true); 13361 channel3.setBypassDnd(false); 13362 // has DND access, so can set bypassDnd attribute 13363 mService.mPreferencesHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, 13364 /*has DND access*/ true, UID_N_MR1, false); 13365 mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel2, true, true, 13366 UID_P, false); 13367 mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true, 13368 UID_P, false); 13369 13370 when(mPackageManager.getPackageUid(eq(PKG_P), anyLong(), anyInt())).thenReturn(UID_P); 13371 when(mPackageManager.getPackageUid(eq(PKG_N_MR1), anyLong(), anyInt())) 13372 .thenReturn(UID_N_MR1); 13373 when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false); 13374 when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true); 13375 13376 enableInteractAcrossUsers(); 13377 assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList()) 13378 .containsExactly(new ZenBypassingApp(PKG_P, false)); 13379 } 13380 13381 @Test 13382 public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException { 13383 mService.setPreferencesHelper(mPreferencesHelper); 13384 13385 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13386 13387 assertThat(mBinderService.getNotificationChannelsBypassingDnd(mPkg, mUid).getList()) 13388 .isEmpty(); 13389 verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid); 13390 } 13391 13392 @Test 13393 public void testGetPackagesBypassingDnd_empty() throws RemoteException { 13394 mService.setPreferencesHelper(mPreferencesHelper); 13395 List<String> result = mBinderService.getPackagesBypassingDnd(mUserId).getList(); 13396 assertThat(result).isEmpty(); 13397 } 13398 13399 @Test 13400 public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception { 13401 // set the testable NMS to not system uid/appid 13402 mService.isSystemUid = false; 13403 mService.isSystemAppId = false; 13404 13405 // make sure a caller without listener access or read_contacts permission can't call 13406 // matchesCallFilter. 13407 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 13408 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 13409 eq("android.permission.READ_CONTACTS"), anyString()); 13410 13411 try { 13412 // shouldn't matter what we're passing in, if we get past this line fail immediately 13413 ((INotificationManager) mService.mService).matchesCallFilter(null); 13414 fail("call to matchesCallFilter with no permissions should fail"); 13415 } catch (SecurityException e) { 13416 // pass 13417 } 13418 } 13419 13420 @Test 13421 public void testMatchesCallFilter_hasSystemPermission() throws Exception { 13422 // set the testable NMS to system uid 13423 mService.isSystemUid = true; 13424 13425 // make sure caller doesn't have listener access or read_contacts permission 13426 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 13427 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 13428 eq("android.permission.READ_CONTACTS"), anyString()); 13429 13430 try { 13431 ((INotificationManager) mService.mService).matchesCallFilter(null); 13432 // pass, but check that we actually checked for system permissions 13433 assertTrue(mService.countSystemChecks > 0); 13434 } catch (SecurityException e) { 13435 fail("call to matchesCallFilter with just system permissions should work"); 13436 } 13437 } 13438 13439 @Test 13440 public void testMatchesCallFilter_hasListenerPermission() throws Exception { 13441 mService.isSystemUid = false; 13442 mService.isSystemAppId = false; 13443 13444 // make sure a caller with only listener access and not read_contacts permission can call 13445 // matchesCallFilter. 13446 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(true); 13447 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 13448 eq("android.permission.READ_CONTACTS"), anyString()); 13449 13450 try { 13451 ((INotificationManager) mService.mService).matchesCallFilter(null); 13452 // pass, this is not a functionality test 13453 } catch (SecurityException e) { 13454 fail("call to matchesCallFilter with listener permissions should work"); 13455 } 13456 } 13457 13458 @Test 13459 public void testMatchesCallFilter_hasContactsPermission() throws Exception { 13460 mService.isSystemUid = false; 13461 mService.isSystemAppId = false; 13462 13463 // make sure a caller with only read_contacts permission and not listener access can call 13464 // matchesCallFilter. 13465 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 13466 doNothing().when(mContext).enforceCallingPermission( 13467 eq("android.permission.READ_CONTACTS"), anyString()); 13468 13469 try { 13470 ((INotificationManager) mService.mService).matchesCallFilter(null); 13471 // pass, this is not a functionality test 13472 } catch (SecurityException e) { 13473 fail("call to matchesCallFilter with listener permissions should work"); 13474 } 13475 } 13476 13477 @Test 13478 public void testMediaNotificationsBypassBlock() throws Exception { 13479 when(mAmi.getPendingIntentFlags(any(IIntentSender.class))) 13480 .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT); 13481 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13482 13483 Notification.Builder nb = new Notification.Builder( 13484 mContext, mTestNotificationChannel.getId()) 13485 .setContentTitle("foo") 13486 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13487 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13488 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13489 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13490 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13491 13492 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13493 13494 // normal blocked notifications - blocked 13495 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13496 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13497 13498 // just using the style - blocked 13499 nb.setStyle(new Notification.MediaStyle()); 13500 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13501 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13502 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13503 13504 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13505 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13506 13507 // using the style, but incorrect type in session - blocked 13508 nb.setStyle(new Notification.MediaStyle()); 13509 Bundle extras = new Bundle(); 13510 extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent()); 13511 nb.addExtras(extras); 13512 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13513 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13514 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13515 13516 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13517 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13518 13519 // style + media session - bypasses block 13520 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); 13521 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13522 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13523 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13524 13525 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13526 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13527 } 13528 13529 @Test 13530 public void testMediaNotificationsBypassBlock_atPost() throws Exception { 13531 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 13532 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13533 13534 Notification.Builder nb = new Notification.Builder( 13535 mContext, mTestNotificationChannel.getId()) 13536 .setContentTitle("foo") 13537 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13538 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13539 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13540 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13541 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13542 13543 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 13544 13545 mService.addEnqueuedNotification(r); 13546 NotificationManagerService.PostNotificationRunnable runnable = 13547 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 13548 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 13549 runnable.run(); 13550 waitForIdle(); 13551 13552 verify(mUsageStats).registerBlocked(any()); 13553 verify(mUsageStats, never()).registerPostedByApp(any()); 13554 13555 // just using the style - blocked 13556 mService.clearNotifications(); 13557 reset(mUsageStats); 13558 nb.setStyle(new Notification.MediaStyle()); 13559 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13560 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13561 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13562 13563 mService.addEnqueuedNotification(r); 13564 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 13565 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 13566 runnable.run(); 13567 waitForIdle(); 13568 13569 verify(mUsageStats).registerBlocked(any()); 13570 verify(mUsageStats, never()).registerPostedByApp(any()); 13571 13572 // style + media session - bypasses block 13573 mService.clearNotifications(); 13574 reset(mUsageStats); 13575 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); 13576 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13577 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13578 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13579 13580 mService.addEnqueuedNotification(r); 13581 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 13582 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 13583 runnable.run(); 13584 waitForIdle(); 13585 13586 verify(mUsageStats, never()).registerBlocked(any()); 13587 verify(mUsageStats).registerPostedByApp(any()); 13588 } 13589 13590 @Test 13591 public void testCallNotificationsBypassBlock() throws Exception { 13592 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13593 13594 Notification.Builder nb = new Notification.Builder( 13595 mContext, mTestNotificationChannel.getId()) 13596 .setContentTitle("foo") 13597 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13598 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13599 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13600 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13601 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13602 13603 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13604 13605 // normal blocked notifications - blocked 13606 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13607 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13608 13609 // just using the style - blocked 13610 Person person = new Person.Builder() 13611 .setName("caller") 13612 .build(); 13613 nb.setStyle(Notification.CallStyle.forOngoingCall( 13614 person, mActivityIntent)); 13615 nb.setFullScreenIntent(mActivityIntent, true); 13616 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13617 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13618 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13619 13620 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13621 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13622 13623 // style + managed call - bypasses block 13624 when(mTelecomManager.isInManagedCall()).thenReturn(true); 13625 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13626 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13627 13628 // style + self managed call - bypasses block 13629 when(mTelecomManager.isInSelfManagedCall( 13630 r.getSbn().getPackageName(), UserHandle.ALL)).thenReturn(true); 13631 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13632 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13633 13634 // set telecom manager to null - blocked 13635 mService.setTelecomManager(null); 13636 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13637 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 13638 .isFalse(); 13639 13640 // set telecom feature to false - blocked 13641 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false); 13642 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13643 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 13644 .isFalse(); 13645 13646 // telecom manager is not ready - blocked 13647 mService.setTelecomManager(mTelecomManager); 13648 when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready")); 13649 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13650 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 13651 .isFalse(); 13652 } 13653 13654 @Test 13655 public void testCallNotificationsBypassBlock_atPost() throws Exception { 13656 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 13657 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13658 13659 Notification.Builder nb = 13660 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 13661 .setContentTitle("foo") 13662 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13663 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13664 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13665 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13666 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13667 13668 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13669 13670 // normal blocked notifications - blocked 13671 mService.addEnqueuedNotification(r); 13672 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13673 mPostNotificationTrackerFactory.newTracker(null)).run(); 13674 waitForIdle(); 13675 13676 verify(mUsageStats).registerBlocked(any()); 13677 verify(mUsageStats, never()).registerPostedByApp(any()); 13678 13679 // just using the style - blocked 13680 mService.clearNotifications(); 13681 reset(mUsageStats); 13682 Person person = new Person.Builder().setName("caller").build(); 13683 nb.setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)); 13684 nb.setFullScreenIntent(mActivityIntent, true); 13685 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, nb.build(), 13686 UserHandle.getUserHandleForUid(mUid), null, 0); 13687 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13688 13689 mService.addEnqueuedNotification(r); 13690 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13691 mPostNotificationTrackerFactory.newTracker(null)).run(); 13692 waitForIdle(); 13693 13694 verify(mUsageStats).registerBlocked(any()); 13695 verify(mUsageStats, never()).registerPostedByApp(any()); 13696 13697 // style + managed call - bypasses block 13698 mService.clearNotifications(); 13699 reset(mUsageStats); 13700 when(mTelecomManager.isInManagedCall()).thenReturn(true); 13701 13702 mService.addEnqueuedNotification(r); 13703 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13704 mPostNotificationTrackerFactory.newTracker(null)).run(); 13705 waitForIdle(); 13706 13707 verify(mUsageStats, never()).registerBlocked(any()); 13708 verify(mUsageStats).registerPostedByApp(any()); 13709 13710 // style + self managed call - bypasses block 13711 mService.clearNotifications(); 13712 reset(mUsageStats); 13713 when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), UserHandle.ALL)) 13714 .thenReturn(true); 13715 13716 mService.addEnqueuedNotification(r); 13717 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13718 mPostNotificationTrackerFactory.newTracker(null)).run(); 13719 waitForIdle(); 13720 13721 verify(mUsageStats, never()).registerBlocked(any()); 13722 verify(mUsageStats).registerPostedByApp(any()); 13723 13724 // set telecom manager to null - notifications should be blocked 13725 // but post notifications runnable should not crash 13726 mService.clearNotifications(); 13727 reset(mUsageStats); 13728 mService.setTelecomManager(null); 13729 13730 mService.addEnqueuedNotification(r); 13731 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13732 mPostNotificationTrackerFactory.newTracker(null)).run(); 13733 waitForIdle(); 13734 13735 verify(mUsageStats).registerBlocked(any()); 13736 verify(mUsageStats, never()).registerPostedByApp(any()); 13737 13738 // set FEATURE_TELECOM to false - notifications should be blocked 13739 // but post notifications runnable should not crash 13740 mService.setTelecomManager(mTelecomManager); 13741 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false); 13742 reset(mUsageStats); 13743 mService.setTelecomManager(null); 13744 13745 mService.addEnqueuedNotification(r); 13746 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13747 mPostNotificationTrackerFactory.newTracker(null)).run(); 13748 waitForIdle(); 13749 13750 verify(mUsageStats).registerBlocked(any()); 13751 verify(mUsageStats, never()).registerPostedByApp(any()); 13752 13753 // telecom is not ready - notifications should be blocked but no crashes 13754 mService.setTelecomManager(mTelecomManager); 13755 when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready")); 13756 reset(mUsageStats); 13757 13758 mService.addEnqueuedNotification(r); 13759 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13760 mPostNotificationTrackerFactory.newTracker(null)).run(); 13761 waitForIdle(); 13762 13763 verify(mUsageStats).registerBlocked(any()); 13764 verify(mUsageStats, never()).registerPostedByApp(any()); 13765 } 13766 13767 @Test 13768 public void testGetAllUsersNotificationPermissions() { 13769 // In this case, there are multiple users each with notification permissions (and also, 13770 // for good measure, some without). 13771 // make sure the collection returned contains info for all of them 13772 final List<UserInfo> userInfos = new ArrayList<>(); 13773 userInfos.add(new UserInfo(0, "user0", 0)); 13774 userInfos.add(new UserInfo(1, "user1", 0)); 13775 userInfos.add(new UserInfo(2, "user2", 0)); 13776 when(mUm.getUsers()).thenReturn(userInfos); 13777 13778 // construct the permissions for each of them 13779 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(), 13780 permissions1 = new ArrayMap<>(); 13781 permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false)); 13782 permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true)); 13783 permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false)); 13784 permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true)); 13785 when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0); 13786 when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1); 13787 when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>()); 13788 13789 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions = 13790 mService.getAllUsersNotificationPermissions(); 13791 assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first); 13792 assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second); 13793 assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first); 13794 assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second); 13795 assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first); 13796 assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second); 13797 assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first); 13798 assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second); 13799 } 13800 13801 @Test 13802 public void testGetActiveNotification_filtersUsers() throws Exception { 13803 when(mUm.getProfileIds(mUserId, false)).thenReturn(new int[]{mUserId, 10}); 13804 13805 NotificationRecord nr0 = 13806 generateNotificationRecord(mTestNotificationChannel, mUserId); 13807 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 13808 nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId()); 13809 13810 NotificationRecord nr10 = 13811 generateNotificationRecord(mTestNotificationChannel, 10); 13812 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag10", 13813 nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId()); 13814 13815 NotificationRecord nr11 = 13816 generateNotificationRecord(mTestNotificationChannel, 11); 13817 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag11", 13818 nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId()); 13819 waitForIdle(); 13820 13821 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 13822 assertEquals(2, notifs.length); 13823 for (StatusBarNotification sbn : notifs) { 13824 if (sbn.getUserId() == 11) { 13825 fail("leaked data across users"); 13826 } 13827 } 13828 } 13829 13830 @Test 13831 public void testGetActiveNotificationsFromListener_redactNotification() throws Exception { 13832 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 13833 NotificationRecord r = 13834 generateNotificationRecord(mTestNotificationChannel, 0, 0); 13835 mService.addNotification(r); 13836 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 13837 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 13838 StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1); 13839 when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted); 13840 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13841 info.userid = 0; 13842 when(info.isSameUser(anyInt())).thenReturn(true); 13843 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 13844 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 13845 List<StatusBarNotification> notifications = mBinderService 13846 .getActiveNotificationsFromListener(mock(INotificationListener.class), null, -1) 13847 .getList(); 13848 13849 boolean foundRedactedSbn = false; 13850 for (StatusBarNotification sbn: notifications) { 13851 String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString(); 13852 if (REDACTED_TEXT.equals(text)) { 13853 foundRedactedSbn = true; 13854 break; 13855 } 13856 } 13857 assertTrue("expect to find a redacted notification", foundRedactedSbn); 13858 } 13859 13860 @Test 13861 public void testGetSnoozedNotificationsFromListener_redactNotification() throws Exception { 13862 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 13863 NotificationRecord r = 13864 generateNotificationRecord(mTestNotificationChannel, 0, 0); 13865 when(mSnoozeHelper.getSnoozed()).thenReturn(List.of(r)); 13866 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 13867 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 13868 StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1); 13869 when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted); 13870 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13871 info.userid = 0; 13872 when(info.isSameUser(anyInt())).thenReturn(true); 13873 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 13874 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 13875 List<StatusBarNotification> notifications = mBinderService 13876 .getSnoozedNotificationsFromListener(mock(INotificationListener.class), -1) 13877 .getList(); 13878 13879 boolean foundRedactedSbn = false; 13880 for (StatusBarNotification sbn: notifications) { 13881 String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString(); 13882 if (REDACTED_TEXT.equals(text)) { 13883 foundRedactedSbn = true; 13884 break; 13885 } 13886 } 13887 assertTrue("expect to find a redacted notification", foundRedactedSbn); 13888 } 13889 13890 @Test 13891 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 13892 public void testCancelAutogroupSummary_cancelsAllChildren() throws Exception { 13893 final String originalGroupName = "originalGroup"; 13894 final String aggregateGroupName = "Aggregate_Test"; 13895 final int summaryId = Integer.MAX_VALUE; 13896 // Add 2 group notifications without a summary 13897 NotificationRecord nr0 = 13898 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 13899 NotificationRecord nr1 = 13900 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 13901 mService.addNotification(nr0); 13902 mService.addNotification(nr1); 13903 mService.mSummaryByGroupKey.remove(nr0.getGroupKey()); 13904 13905 // GroupHelper is a mock, so make the calls it would make 13906 // Add aggregate group summary 13907 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 13908 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 13909 nr0.getChannel().getId()); 13910 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 13911 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 13912 mService.addNotification(aggregateSummary); 13913 nr0.setOverrideGroupKey(aggregateGroupName); 13914 nr1.setOverrideGroupKey(aggregateGroupName); 13915 final String fullAggregateGroupKey = nr0.getGroupKey(); 13916 13917 // Check that the aggregate group summary was created 13918 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 13919 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 13920 nr0.getChannel().getId()); 13921 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 13922 13923 // Cancel aggregate group summary 13924 mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(), 13925 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId()); 13926 waitForIdle(); 13927 13928 // Check that child notifications are also removed 13929 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary)); 13930 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0)); 13931 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1)); 13932 13933 // Make sure the summary was removed and not re-posted 13934 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 13935 } 13936 13937 @Test 13938 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 13939 public void testCancelAutogroupSummary_forceGrouping_cancelsAllChildren() throws Exception { 13940 final String originalGroupName = "originalGroup"; 13941 final String aggregateGroupName = "Aggregate_Test"; 13942 final int summaryId = Integer.MAX_VALUE; 13943 // Add 2 group notifications without a summary 13944 NotificationRecord nr0 = 13945 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 13946 NotificationRecord nr1 = 13947 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 13948 mService.addNotification(nr0); 13949 mService.addNotification(nr1); 13950 mService.mSummaryByGroupKey.remove(nr0.getGroupKey()); 13951 13952 // GroupHelper is a mock, so make the calls it would make 13953 // Add aggregate group summary 13954 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 13955 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 13956 nr0.getChannel().getId()); 13957 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 13958 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 13959 mService.addNotification(aggregateSummary); 13960 nr0.setOverrideGroupKey(aggregateGroupName); 13961 nr1.setOverrideGroupKey(aggregateGroupName); 13962 final String fullAggregateGroupKey = nr0.getGroupKey(); 13963 13964 // Check that the aggregate group summary was created 13965 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 13966 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 13967 nr0.getChannel().getId()); 13968 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 13969 13970 // Cancel aggregate group summary 13971 mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(), 13972 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId()); 13973 waitForIdle(); 13974 13975 // Check that child notifications are also removed 13976 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary), any()); 13977 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any()); 13978 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any()); 13979 13980 // Make sure the summary was removed and not re-posted 13981 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 13982 } 13983 13984 @Test 13985 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 13986 public void testUngroupingOngoingAutoSummary() throws Exception { 13987 NotificationRecord nr0 = 13988 generateNotificationRecord(mTestNotificationChannel, 0); 13989 NotificationRecord nr1 = 13990 generateNotificationRecord(mTestNotificationChannel, 0); 13991 nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT; 13992 13993 mService.addNotification(nr0); 13994 mService.addNotification(nr1); 13995 13996 // grouphelper is a mock here, so make the calls it would make 13997 13998 // add summary 13999 NotificationAttributes attr = new NotificationAttributes( 14000 GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0, 14001 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14002 mService.addNotification( 14003 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14004 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14005 14006 // cancel both children 14007 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(), 14008 nr0.getSbn().getId(), nr0.getSbn().getUserId()); 14009 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(), 14010 nr1.getSbn().getId(), nr1.getSbn().getUserId()); 14011 waitForIdle(); 14012 14013 // group helper would send 'remove summary' event 14014 mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(), 14015 AUTOGROUP_KEY); 14016 waitForIdle(); 14017 14018 // make sure the summary was removed and not re-posted 14019 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 14020 } 14021 14022 @Test 14023 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14024 public void testUngroupingOngoingAutoSummary_forceGrouping() throws Exception { 14025 NotificationRecord nr0 = 14026 generateNotificationRecord(mTestNotificationChannel, 0); 14027 NotificationRecord nr1 = 14028 generateNotificationRecord(mTestNotificationChannel, 0); 14029 nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT; 14030 14031 mService.addNotification(nr0); 14032 mService.addNotification(nr1); 14033 14034 // grouphelper is a mock here, so make the calls it would make 14035 14036 // add summary 14037 NotificationAttributes attr = new NotificationAttributes( 14038 GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0, 14039 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14040 mService.addNotification( 14041 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14042 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14043 14044 // cancel both children 14045 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(), 14046 nr0.getSbn().getId(), nr0.getSbn().getUserId()); 14047 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(), 14048 nr1.getSbn().getId(), nr1.getSbn().getUserId()); 14049 waitForIdle(); 14050 14051 // group helper would send 'remove summary' event 14052 mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(), 14053 AUTOGROUP_KEY); 14054 waitForIdle(); 14055 14056 // make sure the summary was removed and not re-posted 14057 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 14058 } 14059 14060 @Test 14061 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14062 public void testUngroupingAutoSummary_differentUsers() throws Exception { 14063 NotificationRecord nr0 = 14064 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM); 14065 NotificationRecord nr1 = 14066 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM); 14067 14068 // add notifications + summary for USER_SYSTEM 14069 NotificationAttributes attr = new NotificationAttributes( 14070 GroupHelper.BASE_FLAGS, mock(Icon.class), 0, 14071 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14072 mService.addNotification(nr0); 14073 mService.addNotification(nr1); 14074 mService.addNotification( 14075 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14076 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14077 14078 // add notifications + summary for USER_ALL 14079 NotificationRecord nr0_all = 14080 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL); 14081 NotificationRecord nr1_all = 14082 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL); 14083 14084 mService.addNotification(nr0_all); 14085 mService.addNotification(nr1_all); 14086 mService.addNotification( 14087 mService.createAutoGroupSummary(nr0_all.getUserId(), 14088 nr0_all.getSbn().getPackageName(), 14089 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14090 14091 // cancel both children for USER_ALL 14092 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(), 14093 nr0_all.getSbn().getId(), UserHandle.USER_ALL); 14094 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(), 14095 nr1_all.getSbn().getId(), UserHandle.USER_ALL); 14096 waitForIdle(); 14097 14098 // group helper would send 'remove summary' event 14099 mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL, 14100 nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY); 14101 waitForIdle(); 14102 14103 // make sure the right summary was removed 14104 assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(), 14105 UserHandle.USER_ALL, 0, null)).isEqualTo(0); 14106 14107 // the USER_SYSTEM notifications + summary were not removed 14108 assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(), 14109 USER_SYSTEM, 0, null)).isEqualTo(3); 14110 } 14111 14112 @Test 14113 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14114 public void testUngroupingAutoSummary_differentUsers_forceGrouping() throws Exception { 14115 NotificationRecord nr0 = 14116 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM); 14117 NotificationRecord nr1 = 14118 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM); 14119 14120 // add notifications + summary for USER_SYSTEM 14121 NotificationAttributes attr = new NotificationAttributes( 14122 GroupHelper.BASE_FLAGS, mock(Icon.class), 0, 14123 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14124 mService.addNotification(nr0); 14125 mService.addNotification(nr1); 14126 mService.addNotification( 14127 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14128 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14129 14130 // add notifications + summary for USER_ALL 14131 NotificationRecord nr0_all = 14132 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL); 14133 NotificationRecord nr1_all = 14134 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL); 14135 14136 mService.addNotification(nr0_all); 14137 mService.addNotification(nr1_all); 14138 mService.addNotification( 14139 mService.createAutoGroupSummary(nr0_all.getUserId(), 14140 nr0_all.getSbn().getPackageName(), 14141 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14142 14143 // cancel both children for USER_ALL 14144 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(), 14145 nr0_all.getSbn().getId(), UserHandle.USER_ALL); 14146 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(), 14147 nr1_all.getSbn().getId(), UserHandle.USER_ALL); 14148 waitForIdle(); 14149 14150 // group helper would send 'remove summary' event 14151 mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL, 14152 nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY); 14153 waitForIdle(); 14154 14155 // make sure the right summary was removed 14156 assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(), 14157 UserHandle.USER_ALL, 0, null)).isEqualTo(0); 14158 14159 // the USER_SYSTEM notifications + summary were not removed 14160 assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(), 14161 USER_SYSTEM, 0, null)).isEqualTo(3); 14162 } 14163 14164 @Test 14165 public void testStrongAuthTracker_isInLockDownMode() { 14166 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 14167 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 14168 mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); 14169 assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); 14170 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId()); 14171 mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); 14172 assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); 14173 } 14174 14175 @Test 14176 public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() { 14177 // post 2 notifications from 2 packages 14178 NotificationRecord pkgA = new NotificationRecord(mContext, 14179 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14180 mService.addNotification(pkgA); 14181 NotificationRecord pkgB = new NotificationRecord(mContext, 14182 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 14183 mService.addNotification(pkgB); 14184 14185 // when entering the lockdown mode, cancel the 2 notifications. 14186 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 14187 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 14188 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14189 assertTrue(mStrongAuthTracker.isInLockDownMode(0)); 14190 14191 // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN. 14192 ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); 14193 verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any()); 14194 assertEquals(REASON_LOCKDOWN, captor.getValue().intValue()); 14195 14196 // exit lockdown mode. 14197 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); 14198 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14199 assertFalse(mStrongAuthTracker.isInLockDownMode(0)); 14200 14201 // the notifyPostedLocked function is called twice. 14202 verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong()); 14203 } 14204 14205 @Test 14206 public void testMakeRankingUpdateLockedInLockDownMode() { 14207 // post 2 notifications from a same package 14208 NotificationRecord pkgA = new NotificationRecord(mContext, 14209 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14210 mService.addNotification(pkgA); 14211 NotificationRecord pkgB = new NotificationRecord(mContext, 14212 generateSbn("a", 1000, 9, 1), mTestNotificationChannel); 14213 mService.addNotification(pkgB); 14214 14215 mService.setIsVisibleToListenerReturnValue(true); 14216 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(null); 14217 assertEquals(2, nru.getRankingMap().getOrderedKeys().length); 14218 14219 // when only user 0 entering the lockdown mode, its notification will be suppressed. 14220 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 14221 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 14222 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14223 assertTrue(mStrongAuthTracker.isInLockDownMode(0)); 14224 assertFalse(mStrongAuthTracker.isInLockDownMode(1)); 14225 14226 nru = mService.makeRankingUpdateLocked(null); 14227 assertEquals(1, nru.getRankingMap().getOrderedKeys().length); 14228 14229 // User 0 exits lockdown mode. Its notification will be resumed. 14230 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); 14231 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14232 assertFalse(mStrongAuthTracker.isInLockDownMode(0)); 14233 assertFalse(mStrongAuthTracker.isInLockDownMode(1)); 14234 14235 nru = mService.makeRankingUpdateLocked(null); 14236 assertEquals(2, nru.getRankingMap().getOrderedKeys().length); 14237 } 14238 14239 @Test 14240 public void testMakeRankingUpdate_redactsIfRecordSensitiveAndServiceUntrusted() { 14241 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 14242 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 14243 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 14244 NotificationRecord pkgA = new NotificationRecord(mContext, 14245 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14246 addSmartActionsAndReplies(pkgA); 14247 mService.addNotification(pkgA); 14248 NotificationRecord pkgB = new NotificationRecord(mContext, 14249 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 14250 addSmartActionsAndReplies(pkgB); 14251 mService.addNotification(pkgB); 14252 14253 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 14254 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 14255 when(info.isSameUser(anyInt())).thenReturn(true); 14256 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 14257 NotificationListenerService.Ranking ranking = 14258 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14259 assertEquals(0, ranking.getSmartActions().size()); 14260 assertEquals(0, ranking.getSmartReplies().size()); 14261 NotificationListenerService.Ranking ranking2 = 14262 nru.getRankingMap().getRawRankingObject(pkgB.getSbn().getKey()); 14263 assertEquals(0, ranking2.getSmartActions().size()); 14264 assertEquals(0, ranking2.getSmartReplies().size()); 14265 } 14266 14267 @Test 14268 public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() { 14269 mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 14270 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 14271 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 14272 NotificationRecord pkgA = new NotificationRecord(mContext, 14273 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14274 addSmartActionsAndReplies(pkgA); 14275 14276 mService.addNotification(pkgA); 14277 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 14278 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 14279 when(info.isSameUser(anyInt())).thenReturn(true); 14280 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 14281 NotificationListenerService.Ranking ranking = 14282 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14283 assertEquals(1, ranking.getSmartActions().size()); 14284 assertEquals(1, ranking.getSmartReplies().size()); 14285 } 14286 14287 @Test 14288 public void testMakeRankingUpdate_doesntRedactIfNotSensitiveOrServiceTrusted() { 14289 mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 14290 NotificationRecord pkgA = new NotificationRecord(mContext, 14291 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14292 addSmartActionsAndReplies(pkgA); 14293 14294 mService.addNotification(pkgA); 14295 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 14296 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 14297 when(info.isSameUser(anyInt())).thenReturn(true); 14298 14299 // No sensitive content, no redaction 14300 when(mListeners.isUidTrusted(eq(1000))).thenReturn(false); 14301 when(mListeners.hasSensitiveContent(any())).thenReturn(false); 14302 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 14303 NotificationListenerService.Ranking ranking = 14304 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14305 assertEquals(1, ranking.getSmartActions().size()); 14306 assertEquals(1, ranking.getSmartReplies().size()); 14307 14308 // trusted listener, no redaction 14309 when(mListeners.isUidTrusted(eq(1000))).thenReturn(true); 14310 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 14311 nru = mService.makeRankingUpdateLocked(info); 14312 ranking = nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14313 assertEquals(1, ranking.getSmartActions().size()); 14314 assertEquals(1, ranking.getSmartReplies().size()); 14315 } 14316 14317 private void addSmartActionsAndReplies(NotificationRecord record) { 14318 Bundle b = new Bundle(); 14319 ArrayList<Notification.Action> actions = new ArrayList<>(); 14320 actions.add(new Notification.Action(0, "", null)); 14321 b.putParcelableArrayList(KEY_CONTEXTUAL_ACTIONS, actions); 14322 ArrayList<CharSequence> replies = new ArrayList<>(List.of("test")); 14323 b.putCharSequenceArrayList(KEY_TEXT_REPLIES, replies); 14324 Adjustment a = new Adjustment(record.getSbn().getPackageName(), record.getSbn().getKey(), 14325 b, "", record.getUserId()); 14326 record.addAdjustment(a); 14327 record.applyAdjustments(); 14328 } 14329 14330 @Test 14331 public void testMaybeShowReviewPermissionsNotification_flagOff() { 14332 mService.setShowReviewPermissionsNotification(false); 14333 reset(mMockNm); 14334 14335 // If state is SHOULD_SHOW, it would show, but not if the flag is off! 14336 Settings.Global.putInt(mContext.getContentResolver(), 14337 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14338 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 14339 mService.maybeShowInitialReviewPermissionsNotification(); 14340 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14341 } 14342 14343 @Test 14344 public void testMaybeShowReviewPermissionsNotification_unknown() { 14345 mService.setShowReviewPermissionsNotification(true); 14346 reset(mMockNm); 14347 14348 // Set up various possible states of the settings int and confirm whether or not the 14349 // notification is shown as expected 14350 14351 // Initial state: default/unknown setting, make sure nothing happens 14352 Settings.Global.putInt(mContext.getContentResolver(), 14353 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14354 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN); 14355 mService.maybeShowInitialReviewPermissionsNotification(); 14356 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14357 } 14358 14359 @Test 14360 public void testMaybeShowReviewPermissionsNotification_shouldShow() { 14361 mService.setShowReviewPermissionsNotification(true); 14362 reset(mMockNm); 14363 14364 // If state is SHOULD_SHOW, it ... should show 14365 Settings.Global.putInt(mContext.getContentResolver(), 14366 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14367 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 14368 mService.maybeShowInitialReviewPermissionsNotification(); 14369 verify(mMockNm, times(1)).notify(eq(TAG), 14370 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 14371 any(Notification.class)); 14372 } 14373 14374 @Test 14375 public void testMaybeShowReviewPermissionsNotification_alreadyShown() { 14376 mService.setShowReviewPermissionsNotification(true); 14377 reset(mMockNm); 14378 14379 // If state is either USER_INTERACTED or DISMISSED, we should not show this on boot 14380 Settings.Global.putInt(mContext.getContentResolver(), 14381 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14382 NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED); 14383 mService.maybeShowInitialReviewPermissionsNotification(); 14384 14385 Settings.Global.putInt(mContext.getContentResolver(), 14386 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14387 NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED); 14388 mService.maybeShowInitialReviewPermissionsNotification(); 14389 14390 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14391 } 14392 14393 @Test 14394 public void testMaybeShowReviewPermissionsNotification_reshown() { 14395 mService.setShowReviewPermissionsNotification(true); 14396 reset(mMockNm); 14397 14398 // If we have re-shown the notification and the user did not subsequently interacted with 14399 // it, then make sure we show when trying on boot 14400 Settings.Global.putInt(mContext.getContentResolver(), 14401 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14402 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN); 14403 mService.maybeShowInitialReviewPermissionsNotification(); 14404 verify(mMockNm, times(1)).notify(eq(TAG), 14405 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 14406 any(Notification.class)); 14407 } 14408 14409 @Test 14410 public void testRescheduledReviewPermissionsNotification() { 14411 mService.setShowReviewPermissionsNotification(true); 14412 reset(mMockNm); 14413 14414 // when rescheduled, the notification goes through the NotificationManagerInternal service 14415 // this call doesn't need to know anything about previously scheduled state -- if called, 14416 // it should send the notification & write the appropriate int to Settings 14417 mInternalService.sendReviewPermissionsNotification(); 14418 14419 // Notification should be sent 14420 verify(mMockNm, times(1)).notify(eq(TAG), 14421 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 14422 any(Notification.class)); 14423 14424 // write STATE_RESHOWN to settings 14425 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN, 14426 Settings.Global.getInt(mContext.getContentResolver(), 14427 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14428 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 14429 } 14430 14431 @Test 14432 public void testRescheduledReviewPermissionsNotification_flagOff() { 14433 mService.setShowReviewPermissionsNotification(false); 14434 reset(mMockNm); 14435 14436 // no notification should be sent if the flag is off 14437 mInternalService.sendReviewPermissionsNotification(); 14438 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14439 } 14440 14441 private void verifyStickyHun(int permissionState, boolean appRequested, 14442 boolean isSticky) throws Exception { 14443 14444 when(mPermissionHelper.hasRequestedPermission(Manifest.permission.USE_FULL_SCREEN_INTENT, 14445 mPkg, mUserId)).thenReturn(appRequested); 14446 14447 when(mPermissionManager.checkPermissionForDataDelivery( 14448 eq(Manifest.permission.USE_FULL_SCREEN_INTENT), any(), any())) 14449 .thenReturn(permissionState); 14450 14451 Notification n = new Notification.Builder(mContext, "test") 14452 .setFullScreenIntent(mActivityIntent, true) 14453 .build(); 14454 14455 mService.fixNotification(n, mPkg, "tag", 9, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 14456 14457 final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED; 14458 14459 if (isSticky) { 14460 assertNotSame(0, stickyFlag); 14461 } else { 14462 assertSame(0, stickyFlag); 14463 } 14464 } 14465 14466 @Test 14467 public void testFixNotification_flagEnableStickyHun_fsiPermissionHardDenied_showStickyHun() 14468 throws Exception { 14469 14470 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_HARD_DENIED, true, 14471 /* isSticky= */ true); 14472 } 14473 14474 @Test 14475 public void testFixNotification_flagEnableStickyHun_fsiPermissionSoftDenied_showStickyHun() 14476 throws Exception { 14477 14478 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, true, 14479 /* isSticky= */ true); 14480 } 14481 14482 @Test 14483 public void testFixNotification_fsiPermissionSoftDenied_appNotRequest_noShowStickyHun() 14484 throws Exception { 14485 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, false, 14486 /* isSticky= */ false); 14487 } 14488 14489 14490 @Test 14491 public void testFixNotification_flagEnableStickyHun_fsiPermissionGranted_showFsi() 14492 throws Exception { 14493 14494 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_GRANTED, true, 14495 /* isSticky= */ false); 14496 } 14497 14498 @Test 14499 public void fixNotification_withFgsFlag_butIsNotFgs() throws Exception { 14500 final ApplicationInfo applicationInfo = new ApplicationInfo(); 14501 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14502 .thenReturn(applicationInfo); 14503 14504 Notification n = new Notification.Builder(mContext, "test") 14505 .setFlag(FLAG_FOREGROUND_SERVICE, true) 14506 .setFlag(FLAG_CAN_COLORIZE, true) 14507 .build(); 14508 14509 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14510 14511 assertFalse(n.isForegroundService()); 14512 assertFalse(n.hasColorizedPermission()); 14513 } 14514 14515 @Test 14516 public void checkCallStyleNotification_withoutAnyValidUseCase_throws() throws Exception { 14517 Person person = new Person.Builder().setName("caller").build(); 14518 Notification n = new Notification.Builder(mContext, "test") 14519 .setStyle(Notification.CallStyle.forOngoingCall( 14520 person, mActivityIntent)) 14521 .build(); 14522 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14523 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14524 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14525 14526 try { 14527 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14528 r.getSbn().getId(), r.getSbn().getTag(), r, false, false); 14529 assertFalse("CallStyle should not be allowed without a valid use case", true); 14530 } catch (IllegalArgumentException error) { 14531 assertThat(error.getMessage()).contains("CallStyle"); 14532 } 14533 } 14534 14535 @Test 14536 public void checkCallStyleNotification_allowedForFgs() throws Exception { 14537 Person person = new Person.Builder().setName("caller").build(); 14538 Notification n = new Notification.Builder(mContext, "test") 14539 .setFlag(FLAG_FOREGROUND_SERVICE, true) 14540 .setStyle(Notification.CallStyle.forOngoingCall( 14541 person, mActivityIntent)) 14542 .build(); 14543 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14544 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14545 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14546 14547 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14548 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14549 } 14550 14551 private Notification createBigPictureNotification(boolean isBigPictureStyle, boolean hasImage, 14552 boolean isImageBitmap) { 14553 Notification.Builder builder = new Notification.Builder(mContext) 14554 .setSmallIcon(android.R.drawable.sym_def_app_icon); 14555 Notification.BigPictureStyle style = new Notification.BigPictureStyle(); 14556 14557 if (isBigPictureStyle && hasImage) { 14558 if (isImageBitmap) { 14559 style = style.bigPicture(Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888)); 14560 } else { 14561 style = style.bigPicture(Icon.createWithResource(mContext, R.drawable.btn_plus)); 14562 } 14563 } 14564 if (isBigPictureStyle) { 14565 builder.setStyle(style); 14566 } 14567 14568 Notification notification = builder.setChannelId(TEST_CHANNEL_ID).build(); 14569 14570 return notification; 14571 } 14572 14573 private NotificationRecord createBigPictureRecord(boolean isBigPictureStyle, boolean hasImage, 14574 boolean isImageBitmap, boolean isExpired) { 14575 long timePostedMs = System.currentTimeMillis(); 14576 if (isExpired) { 14577 timePostedMs -= BITMAP_DURATION.toMillis(); 14578 } 14579 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14580 createBigPictureNotification(isBigPictureStyle, hasImage, isImageBitmap), 14581 UserHandle.getUserHandleForUid(mUid), null, timePostedMs); 14582 14583 return new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14584 } 14585 14586 private void addRecordAndRemoveBitmaps(NotificationRecord record) { 14587 mService.addNotification(record); 14588 mInternalService.removeBitmaps(); 14589 waitForIdle(); 14590 } 14591 14592 @Test 14593 public void testRemoveBitmaps_canRemoveRevokedDelegate() throws Exception { 14594 Notification n = createBigPictureNotification(true, true, true); 14595 long timePostedMs = System.currentTimeMillis(); 14596 timePostedMs -= BITMAP_DURATION.toMillis(); 14597 14598 when(mPermissionHelper.hasPermission(UID_O)).thenReturn(true); 14599 when(mPackageManagerInternal.isSameApp(PKG_O, UID_O, UserHandle.getUserId(UID_O))) 14600 .thenReturn(true); 14601 mService.mPreferencesHelper.createNotificationChannel(PKG_O, UID_O, 14602 mTestNotificationChannel, true /* fromTargetApp */, false, UID_O, 14603 false); 14604 mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice( 14605 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 14606 14607 StatusBarNotification sbn = new StatusBarNotification(PKG_O, "old.delegate", 8, "tag", 14608 UID_O, 0, n, UserHandle.getUserHandleForUid(UID_O), null, timePostedMs); 14609 14610 mService.addNotification(new NotificationRecord(mContext, sbn, mTestNotificationChannel)); 14611 mInternalService.removeBitmaps(); 14612 14613 waitForIdle(); 14614 14615 verify(mWorkerHandler, times(1)) 14616 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14617 } 14618 14619 @Test 14620 public void testRemoveBitmaps_notBigPicture_noRepost() { 14621 addRecordAndRemoveBitmaps( 14622 createBigPictureRecord( 14623 /* isBigPictureStyle= */ false, 14624 /* hasImage= */ false, 14625 /* isImageBitmap= */ false, 14626 /* isExpired= */ false)); 14627 verify(mWorkerHandler, never()) 14628 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14629 } 14630 14631 @Test 14632 public void testRemoveBitmaps_bigPictureNoImage_noRepost() { 14633 addRecordAndRemoveBitmaps( 14634 createBigPictureRecord( 14635 /* isBigPictureStyle= */ true, 14636 /* hasImage= */ false, 14637 /* isImageBitmap= */ false, 14638 /* isExpired= */ false)); 14639 verify(mWorkerHandler, never()) 14640 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14641 } 14642 14643 @Test 14644 public void testRemoveBitmaps_notExpired_noRepost() { 14645 addRecordAndRemoveBitmaps( 14646 createBigPictureRecord( 14647 /* isBigPictureStyle= */ true, 14648 /* hasImage= */ true, 14649 /* isImageBitmap= */ true, 14650 /* isExpired= */ false)); 14651 verify(mWorkerHandler, never()) 14652 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14653 } 14654 14655 @Test 14656 public void testRemoveBitmaps_bitmapExpired_repost() { 14657 addRecordAndRemoveBitmaps( 14658 createBigPictureRecord( 14659 /* isBigPictureStyle= */ true, 14660 /* hasImage= */ true, 14661 /* isImageBitmap= */ true, 14662 /* isExpired= */ true)); 14663 verify(mWorkerHandler, times(1)) 14664 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14665 } 14666 14667 @Test 14668 public void testRemoveBitmaps_bitmapExpired_bitmapGone() { 14669 NotificationRecord record = createBigPictureRecord( 14670 /* isBigPictureStyle= */ true, 14671 /* hasImage= */ true, 14672 /* isImageBitmap= */ true, 14673 /* isExpired= */ true); 14674 addRecordAndRemoveBitmaps(record); 14675 assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE)).isTrue(); 14676 final Parcelable picture = record.getNotification().extras.getParcelable(EXTRA_PICTURE); 14677 assertThat(picture).isNull(); 14678 } 14679 14680 @Test 14681 public void testRemoveBitmaps_bitmapExpired_silent() { 14682 NotificationRecord record = createBigPictureRecord( 14683 /* isBigPictureStyle= */ true, 14684 /* hasImage= */ true, 14685 /* isImageBitmap= */ true, 14686 /* isExpired= */ true); 14687 addRecordAndRemoveBitmaps(record); 14688 assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0); 14689 } 14690 14691 @Test 14692 public void testRemoveBitmaps_iconExpired_repost() { 14693 addRecordAndRemoveBitmaps( 14694 createBigPictureRecord( 14695 /* isBigPictureStyle= */ true, 14696 /* hasImage= */ true, 14697 /* isImageBitmap= */ false, 14698 /* isExpired= */ true)); 14699 verify(mWorkerHandler, times(1)) 14700 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14701 } 14702 14703 @Test 14704 public void testRemoveBitmaps_iconExpired_iconGone() { 14705 NotificationRecord record = createBigPictureRecord( 14706 /* isBigPictureStyle= */ true, 14707 /* hasImage= */ true, 14708 /* isImageBitmap= */ false, 14709 /* isExpired= */ true); 14710 addRecordAndRemoveBitmaps(record); 14711 assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE_ICON)).isTrue(); 14712 final Parcelable pictureIcon = 14713 record.getNotification().extras.getParcelable(EXTRA_PICTURE_ICON); 14714 assertThat(pictureIcon).isNull(); 14715 } 14716 14717 @Test 14718 public void testRemoveBitmaps_iconExpired_silent() { 14719 NotificationRecord record = createBigPictureRecord( 14720 /* isBigPictureStyle= */ true, 14721 /* hasImage= */ true, 14722 /* isImageBitmap= */ false, 14723 /* isExpired= */ true); 14724 addRecordAndRemoveBitmaps(record); 14725 assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0); 14726 } 14727 14728 @Test 14729 public void checkCallStyleNotification_allowedForByForegroundService() throws Exception { 14730 Person person = new Person.Builder().setName("caller").build(); 14731 Notification n = new Notification.Builder(mContext, "test") 14732 // Without FLAG_FOREGROUND_SERVICE. 14733 //.setFlag(FLAG_FOREGROUND_SERVICE, true) 14734 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14735 .build(); 14736 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14737 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14738 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14739 14740 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14741 r.getSbn().getId(), r.getSbn().getTag(), r, false, 14742 true /* byForegroundService */)).isTrue(); 14743 } 14744 14745 @Test 14746 public void checkCallStyleNotification_allowedForUij() throws Exception { 14747 Person person = new Person.Builder().setName("caller").build(); 14748 Notification n = new Notification.Builder(mContext, "test") 14749 .setFlag(FLAG_USER_INITIATED_JOB, true) 14750 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14751 .build(); 14752 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14753 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14754 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14755 14756 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14757 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14758 } 14759 14760 @Test 14761 public void checkCallStyleNotification_allowedForFsiAllowed() throws Exception { 14762 Person person = new Person.Builder().setName("caller").build(); 14763 Notification n = new Notification.Builder(mContext, "test") 14764 .setFullScreenIntent(mActivityIntent, true) 14765 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14766 .build(); 14767 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14768 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14769 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14770 14771 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14772 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14773 } 14774 14775 @Test 14776 public void checkCallStyleNotification_allowedForFsiDenied() throws Exception { 14777 Person person = new Person.Builder().setName("caller").build(); 14778 Notification n = new Notification.Builder(mContext, "test") 14779 .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true) 14780 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14781 .build(); 14782 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14783 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14784 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14785 14786 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14787 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14788 } 14789 14790 @Test 14791 public void fixSystemNotification_withOnGoingFlag_shouldBeDismissible() 14792 throws Exception { 14793 final ApplicationInfo ai = new ApplicationInfo(); 14794 ai.packageName = "pkg"; 14795 ai.uid = mUid; 14796 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 14797 14798 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14799 .thenReturn(ai); 14800 when(mAppOpsManager.checkOpNoThrow( 14801 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 14802 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 14803 // Given: a notification from an app on the system partition has the flag 14804 // FLAG_ONGOING_EVENT set 14805 Notification n = new Notification.Builder(mContext, "test") 14806 .setOngoing(true) 14807 .build(); 14808 14809 // When: fix the notification with NotificationManagerService 14810 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14811 14812 // Then: the notification's flag FLAG_NO_DISMISS should not be set 14813 assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14814 } 14815 14816 @Test 14817 public void fixMediaNotification_withOnGoingFlag_shouldBeNonDismissible() 14818 throws Exception { 14819 // Given: a media notification has the flag FLAG_ONGOING_EVENT set 14820 Notification n = new Notification.Builder(mContext, "test") 14821 .setOngoing(true) 14822 .setStyle(new Notification.MediaStyle() 14823 .setMediaSession(mock(MediaSession.Token.class))) 14824 .build(); 14825 14826 // When: fix the notification with NotificationManagerService 14827 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14828 14829 // Then: the notification's flag FLAG_NO_DISMISS should be set 14830 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14831 } 14832 14833 @Test 14834 public void fixSystemNotification_defaultSearchSelectior_withOnGoingFlag_nondismissible() 14835 throws Exception { 14836 final ApplicationInfo ai = new ApplicationInfo(); 14837 ai.packageName = SEARCH_SELECTOR_PKG; 14838 ai.uid = mUid; 14839 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 14840 14841 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14842 .thenReturn(ai); 14843 when(mAppOpsManager.checkOpNoThrow( 14844 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 14845 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 14846 // Given: a notification from an app on the system partition has the flag 14847 // FLAG_ONGOING_EVENT set 14848 Notification n = new Notification.Builder(mContext, "test") 14849 .setOngoing(true) 14850 .build(); 14851 14852 // When: fix the notification with NotificationManagerService 14853 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14854 14855 // Then: the notification's flag FLAG_NO_DISMISS should be set 14856 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14857 } 14858 14859 @Test 14860 public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible() 14861 throws Exception { 14862 final ApplicationInfo ai = new ApplicationInfo(); 14863 ai.packageName = ADSERVICES_APK_PKG; 14864 ai.uid = mUid; 14865 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 14866 14867 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14868 .thenReturn(ai); 14869 when(mAppOpsManager.checkOpNoThrow( 14870 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 14871 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 14872 // Given: a notification from an app on the system partition has the flag 14873 // FLAG_ONGOING_EVENT set 14874 Notification n = new Notification.Builder(mContext, "test") 14875 .setOngoing(true) 14876 .build(); 14877 14878 // When: fix the notification with NotificationManagerService 14879 mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, 14880 true); 14881 14882 // Then: the notification's flag FLAG_NO_DISMISS should be set 14883 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14884 } 14885 14886 @Test 14887 public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible() 14888 throws Exception { 14889 // Given: a call notification has the flag FLAG_ONGOING_EVENT set 14890 Person person = new Person.Builder() 14891 .setName("caller") 14892 .build(); 14893 Notification n = new Notification.Builder(mContext, "test") 14894 .setOngoing(true) 14895 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14896 .build(); 14897 14898 // When: fix the notification with NotificationManagerService 14899 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14900 14901 // Then: the notification's flag FLAG_NO_DISMISS should be set 14902 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14903 } 14904 14905 14906 @Test 14907 public void fixNonExemptNotification_withOnGoingFlag_shouldBeDismissible() throws Exception { 14908 // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set 14909 Notification n = new Notification.Builder(mContext, "test") 14910 .setOngoing(true) 14911 .build(); 14912 14913 // When: fix the notification with NotificationManagerService 14914 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14915 14916 // Then: the notification's flag FLAG_NO_DISMISS should not be set 14917 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 14918 } 14919 14920 @Test 14921 public void fixNonExemptNotification_withNoDismissFlag_shouldBeDismissible() 14922 throws Exception { 14923 // Given: a non-exempt notification has the flag FLAG_NO_DISMISS set (even though this is 14924 // not allowed) 14925 Notification n = new Notification.Builder(mContext, "test") 14926 .build(); 14927 n.flags |= Notification.FLAG_NO_DISMISS; 14928 14929 // When: fix the notification with NotificationManagerService 14930 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14931 14932 // Then: the notification's flag FLAG_NO_DISMISS should be cleared 14933 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 14934 } 14935 14936 @Test 14937 public void fixMediaNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception { 14938 // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set 14939 Notification n = new Notification.Builder(mContext, "test") 14940 .setOngoing(false) 14941 .setStyle(new Notification.MediaStyle() 14942 .setMediaSession(mock(MediaSession.Token.class))) 14943 .build(); 14944 14945 // When: fix the notification with NotificationManagerService 14946 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14947 14948 // Then: the notification's flag FLAG_NO_DISMISS should not be set 14949 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 14950 } 14951 14952 @Test 14953 public void fixMediaNotification_withoutOnGoingFlag_withNoDismissFlag_shouldBeDismissible() 14954 throws Exception { 14955 // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set, 14956 // but has the flag FLAG_NO_DISMISS set 14957 Notification n = new Notification.Builder(mContext, "test") 14958 .setOngoing(false) 14959 .setStyle(new Notification.MediaStyle() 14960 .setMediaSession(mock(MediaSession.Token.class))) 14961 .build(); 14962 n.flags |= Notification.FLAG_NO_DISMISS; 14963 14964 // When: fix the notification with NotificationManagerService 14965 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14966 14967 // Then: the notification's flag FLAG_NO_DISMISS should be cleared 14968 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 14969 } 14970 14971 @Test 14972 public void fixNonExempt_Notification_withoutOnGoingFlag_shouldBeDismissible() 14973 throws Exception { 14974 // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set 14975 Notification n = new Notification.Builder(mContext, "test") 14976 .setOngoing(false) 14977 .build(); 14978 14979 // When: fix the notification with NotificationManagerService 14980 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14981 14982 // Then: the notification's flag FLAG_NO_DISMISS should not be set 14983 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 14984 } 14985 14986 @Test 14987 public void fixOrganizationAdminNotification_withOnGoingFlag_shouldBeNonDismissible() 14988 throws Exception { 14989 when(mDevicePolicyManager.isActiveDeviceOwner(mUid)).thenReturn(true); 14990 // Given: a notification has the flag FLAG_ONGOING_EVENT set 14991 Notification n = new Notification.Builder(mContext, "test") 14992 .setOngoing(true) 14993 .build(); 14994 14995 // When: fix the notification with NotificationManagerService 14996 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14997 14998 // Then: the notification's flag FLAG_NO_DISMISS should be set 14999 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15000 } 15001 15002 @Test 15003 public void fixExemptAppOpNotification_withFlag_shouldBeNonDismissible() 15004 throws Exception { 15005 final ApplicationInfo ai = new ApplicationInfo(); 15006 ai.packageName = mPkg; 15007 ai.uid = mUid; 15008 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 15009 15010 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 15011 .thenReturn(ai); 15012 when(mAppOpsManager.checkOpNoThrow( 15013 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 15014 mPkg)).thenReturn(AppOpsManager.MODE_ALLOWED); 15015 // Given: a notification has the flag FLAG_ONGOING_EVENT set 15016 Notification n = new Notification.Builder(mContext, "test") 15017 .setOngoing(true) 15018 .build(); 15019 15020 // When: fix the notification with NotificationManagerService 15021 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15022 15023 // Then: the notification's flag FLAG_NO_DISMISS should be set 15024 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15025 } 15026 15027 @Test 15028 public void fixExemptAppOpNotification_withoutAppOpsFlag_shouldBeDismissible() 15029 throws Exception { 15030 when(mAppOpsManager.checkOpNoThrow( 15031 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 15032 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED); 15033 // Given: a notification has the flag FLAG_ONGOING_EVENT set 15034 Notification n = new Notification.Builder(mContext, "test") 15035 .setOngoing(true) 15036 .build(); 15037 15038 // When: fix the notification with NotificationManagerService 15039 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15040 15041 // Then: the notification's flag FLAG_NO_DISMISS should not be set 15042 assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15043 } 15044 15045 @Test 15046 public void testCancelAllNotifications_IgnoreUserInitiatedJob() throws Exception { 15047 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15048 .thenReturn(true); 15049 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15050 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15051 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15052 "testCancelAllNotifications_IgnoreUserInitiatedJob", 15053 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15054 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 15055 waitForIdle(); 15056 StatusBarNotification[] notifs = 15057 mBinderService.getActiveNotifications(sbn.getPackageName()); 15058 assertEquals(1, notifs.length); 15059 assertEquals(1, mService.getNotificationRecordCount()); 15060 } 15061 15062 @Test 15063 public void testCancelAllNotifications_UijFlag_NoUij_Allowed() throws Exception { 15064 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15065 .thenReturn(false); 15066 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15067 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15068 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15069 "testCancelAllNotifications_UijFlag_NoUij_Allowed", 15070 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15071 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 15072 waitForIdle(); 15073 StatusBarNotification[] notifs = 15074 mBinderService.getActiveNotifications(sbn.getPackageName()); 15075 assertEquals(0, notifs.length); 15076 } 15077 15078 @Test 15079 public void testCancelAllNotificationsOtherPackage_IgnoresUijNotification() throws Exception { 15080 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15081 .thenReturn(true); 15082 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15083 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15084 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15085 "testCancelAllNotifications_IgnoreOtherPackages", 15086 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15087 mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); 15088 waitForIdle(); 15089 StatusBarNotification[] notifs = 15090 mBinderService.getActiveNotifications(sbn.getPackageName()); 15091 assertEquals(1, notifs.length); 15092 assertEquals(1, mService.getNotificationRecordCount()); 15093 } 15094 15095 @Test 15096 public void testRemoveUserInitiatedJobFlag_ImmediatelyAfterEnqueue() throws Exception { 15097 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15098 .thenReturn(true); 15099 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 15100 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15101 .build(); 15102 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, 15103 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15104 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15105 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null, 15106 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15107 mInternalService.removeUserInitiatedJobFlagFromNotification(mPkg, sbn.getId(), 15108 sbn.getUserId()); 15109 waitForIdle(); 15110 StatusBarNotification[] notifs = 15111 mBinderService.getActiveNotifications(sbn.getPackageName()); 15112 assertFalse(notifs[0].getNotification().isUserInitiatedJob()); 15113 } 15114 15115 @Test 15116 public void testCancelAfterSecondEnqueueDoesNotSpecifyUserInitiatedJobFlag() throws Exception { 15117 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15118 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_USER_INITIATED_JOB; 15119 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 15120 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15121 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; 15122 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 15123 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15124 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 15125 sbn.getUserId()); 15126 waitForIdle(); 15127 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 15128 assertEquals(0, mService.getNotificationRecordCount()); 15129 } 15130 15131 @Test 15132 public void testCancelNotificationWithTag_fromApp_cannotCancelUijChild() throws Exception { 15133 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15134 .thenReturn(true); 15135 mService.isSystemUid = false; 15136 mService.isSystemAppId = false; 15137 final NotificationRecord parent = generateNotificationRecord( 15138 mTestNotificationChannel, 1, "group", true); 15139 final NotificationRecord child = generateNotificationRecord( 15140 mTestNotificationChannel, 2, "group", false); 15141 final NotificationRecord child2 = generateNotificationRecord( 15142 mTestNotificationChannel, 3, "group", false); 15143 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15144 mService.addNotification(parent); 15145 mService.addNotification(child); 15146 mService.addNotification(child2); 15147 mService.getBinderService().cancelNotificationWithTag( 15148 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 15149 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 15150 waitForIdle(); 15151 StatusBarNotification[] notifs = 15152 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15153 assertEquals(1, notifs.length); 15154 } 15155 15156 @Test 15157 public void testCancelNotificationWithTag_fromApp_cannotCancelUijParent() throws Exception { 15158 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15159 .thenReturn(true); 15160 mService.isSystemUid = false; 15161 mService.isSystemAppId = false; 15162 final NotificationRecord parent = generateNotificationRecord( 15163 mTestNotificationChannel, 1, "group", true); 15164 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15165 final NotificationRecord child = generateNotificationRecord( 15166 mTestNotificationChannel, 2, "group", false); 15167 final NotificationRecord child2 = generateNotificationRecord( 15168 mTestNotificationChannel, 3, "group", false); 15169 mService.addNotification(parent); 15170 mService.addNotification(child); 15171 mService.addNotification(child2); 15172 mService.getBinderService().cancelNotificationWithTag( 15173 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 15174 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 15175 waitForIdle(); 15176 StatusBarNotification[] notifs = 15177 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15178 assertEquals(3, notifs.length); 15179 } 15180 15181 @Test 15182 public void testCancelAllNotificationsFromApp_cannotCancelUijChild() throws Exception { 15183 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15184 .thenReturn(true); 15185 mService.isSystemUid = false; 15186 mService.isSystemAppId = false; 15187 final NotificationRecord parent = generateNotificationRecord( 15188 mTestNotificationChannel, 1, "group", true); 15189 final NotificationRecord child = generateNotificationRecord( 15190 mTestNotificationChannel, 2, "group", false); 15191 final NotificationRecord child2 = generateNotificationRecord( 15192 mTestNotificationChannel, 3, "group", false); 15193 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15194 final NotificationRecord newGroup = generateNotificationRecord( 15195 mTestNotificationChannel, 4, "group2", false); 15196 mService.addNotification(parent); 15197 mService.addNotification(child); 15198 mService.addNotification(child2); 15199 mService.addNotification(newGroup); 15200 mService.getBinderService().cancelAllNotifications( 15201 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 15202 waitForIdle(); 15203 StatusBarNotification[] notifs = 15204 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15205 assertEquals(1, notifs.length); 15206 } 15207 15208 @Test 15209 public void testCancelAllNotifications_fromApp_cannotCancelUijParent() throws Exception { 15210 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15211 .thenReturn(true); 15212 mService.isSystemUid = false; 15213 mService.isSystemAppId = false; 15214 final NotificationRecord parent = generateNotificationRecord( 15215 mTestNotificationChannel, 1, "group", true); 15216 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15217 final NotificationRecord child = generateNotificationRecord( 15218 mTestNotificationChannel, 2, "group", false); 15219 final NotificationRecord child2 = generateNotificationRecord( 15220 mTestNotificationChannel, 3, "group", false); 15221 final NotificationRecord newGroup = generateNotificationRecord( 15222 mTestNotificationChannel, 4, "group2", false); 15223 mService.addNotification(parent); 15224 mService.addNotification(child); 15225 mService.addNotification(child2); 15226 mService.addNotification(newGroup); 15227 mService.getBinderService().cancelAllNotifications( 15228 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 15229 waitForIdle(); 15230 StatusBarNotification[] notifs = 15231 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15232 assertEquals(1, notifs.length); 15233 } 15234 15235 @Test 15236 public void testCancelNotificationsFromListener_clearAll_GroupWithUijParent() throws Exception { 15237 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15238 .thenReturn(true); 15239 final NotificationRecord parent = generateNotificationRecord( 15240 mTestNotificationChannel, 1, "group", true); 15241 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15242 final NotificationRecord child = generateNotificationRecord( 15243 mTestNotificationChannel, 2, "group", false); 15244 final NotificationRecord child2 = generateNotificationRecord( 15245 mTestNotificationChannel, 3, "group", false); 15246 final NotificationRecord newGroup = generateNotificationRecord( 15247 mTestNotificationChannel, 4, "group2", false); 15248 mService.addNotification(parent); 15249 mService.addNotification(child); 15250 mService.addNotification(child2); 15251 mService.addNotification(newGroup); 15252 mService.getBinderService().cancelNotificationsFromListener(null, null); 15253 waitForIdle(); 15254 StatusBarNotification[] notifs = 15255 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15256 assertEquals(0, notifs.length); 15257 } 15258 15259 @Test 15260 public void testCancelNotificationsFromListener_clearAll_GroupWithUijChild() throws Exception { 15261 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15262 .thenReturn(true); 15263 final NotificationRecord parent = generateNotificationRecord( 15264 mTestNotificationChannel, 1, "group", true); 15265 final NotificationRecord child = generateNotificationRecord( 15266 mTestNotificationChannel, 2, "group", false); 15267 final NotificationRecord child2 = generateNotificationRecord( 15268 mTestNotificationChannel, 3, "group", false); 15269 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15270 final NotificationRecord newGroup = generateNotificationRecord( 15271 mTestNotificationChannel, 4, "group2", false); 15272 mService.addNotification(parent); 15273 mService.addNotification(child); 15274 mService.addNotification(child2); 15275 mService.addNotification(newGroup); 15276 mService.getBinderService().cancelNotificationsFromListener(null, null); 15277 waitForIdle(); 15278 StatusBarNotification[] notifs = 15279 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15280 assertEquals(0, notifs.length); 15281 } 15282 15283 @Test 15284 public void testCancelNotificationsFromListener_clearAll_Uij() throws Exception { 15285 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15286 .thenReturn(true); 15287 final NotificationRecord child2 = generateNotificationRecord( 15288 mTestNotificationChannel, 3, null, false); 15289 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15290 mService.addNotification(child2); 15291 mService.getBinderService().cancelNotificationsFromListener(null, null); 15292 waitForIdle(); 15293 StatusBarNotification[] notifs = 15294 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 15295 assertEquals(0, notifs.length); 15296 } 15297 15298 @Test 15299 public void testCancelNotificationsFromListener_byKey_GroupWithUijParent() throws Exception { 15300 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15301 .thenReturn(true); 15302 final NotificationRecord parent = generateNotificationRecord( 15303 mTestNotificationChannel, 1, "group", true); 15304 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15305 final NotificationRecord child = generateNotificationRecord( 15306 mTestNotificationChannel, 2, "group", false); 15307 final NotificationRecord child2 = generateNotificationRecord( 15308 mTestNotificationChannel, 3, "group", false); 15309 final NotificationRecord newGroup = generateNotificationRecord( 15310 mTestNotificationChannel, 4, "group2", false); 15311 mService.addNotification(parent); 15312 mService.addNotification(child); 15313 mService.addNotification(child2); 15314 mService.addNotification(newGroup); 15315 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 15316 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 15317 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15318 waitForIdle(); 15319 StatusBarNotification[] notifs = 15320 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15321 assertEquals(0, notifs.length); 15322 } 15323 15324 @Test 15325 public void testCancelNotificationsFromListener_byKey_GroupWithUijChild() throws Exception { 15326 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15327 .thenReturn(true); 15328 final NotificationRecord parent = generateNotificationRecord( 15329 mTestNotificationChannel, 1, "group", true); 15330 final NotificationRecord child = generateNotificationRecord( 15331 mTestNotificationChannel, 2, "group", false); 15332 final NotificationRecord child2 = generateNotificationRecord( 15333 mTestNotificationChannel, 3, "group", false); 15334 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15335 final NotificationRecord newGroup = generateNotificationRecord( 15336 mTestNotificationChannel, 4, "group2", false); 15337 mService.addNotification(parent); 15338 mService.addNotification(child); 15339 mService.addNotification(child2); 15340 mService.addNotification(newGroup); 15341 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 15342 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 15343 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15344 waitForIdle(); 15345 StatusBarNotification[] notifs = 15346 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15347 assertEquals(0, notifs.length); 15348 } 15349 15350 @Test 15351 public void testCancelNotificationsFromListener_byKey_Uij() throws Exception { 15352 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15353 .thenReturn(true); 15354 final NotificationRecord child = generateNotificationRecord( 15355 mTestNotificationChannel, 3, null, false); 15356 child.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15357 mService.addNotification(child); 15358 String[] keys = {child.getSbn().getKey()}; 15359 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15360 waitForIdle(); 15361 StatusBarNotification[] notifs = 15362 mBinderService.getActiveNotifications(child.getSbn().getPackageName()); 15363 assertEquals(0, notifs.length); 15364 } 15365 15366 @Test 15367 public void testUserInitiatedCancelAllWithGroup_UserInitiatedFlag() throws Exception { 15368 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15369 .thenReturn(true); 15370 final NotificationRecord parent = generateNotificationRecord( 15371 mTestNotificationChannel, 1, "group", true); 15372 final NotificationRecord child = generateNotificationRecord( 15373 mTestNotificationChannel, 2, "group", false); 15374 final NotificationRecord child2 = generateNotificationRecord( 15375 mTestNotificationChannel, 3, "group", false); 15376 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15377 final NotificationRecord newGroup = generateNotificationRecord( 15378 mTestNotificationChannel, 4, "group2", false); 15379 mService.addNotification(parent); 15380 mService.addNotification(child); 15381 mService.addNotification(child2); 15382 mService.addNotification(newGroup); 15383 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId()); 15384 waitForIdle(); 15385 StatusBarNotification[] notifs = 15386 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15387 assertEquals(0, notifs.length); 15388 } 15389 15390 @Test 15391 public void testDeleteChannelGroupChecksForUijs() throws Exception { 15392 when(mCompanionMgr.getAssociations(mPkg, UserHandle.getUserId(mUid))) 15393 .thenReturn(singletonList(mock(AssociationInfo.class))); 15394 CountDownLatch latch = new CountDownLatch(2); 15395 mService.createNotificationChannelGroup(mPkg, mUid, 15396 new NotificationChannelGroup("group", "group"), true, false); 15397 new Thread(() -> { 15398 NotificationChannel notificationChannel = new NotificationChannel("id", "id", 15399 NotificationManager.IMPORTANCE_HIGH); 15400 notificationChannel.setGroup("group"); 15401 ParceledListSlice<NotificationChannel> pls = 15402 new ParceledListSlice(ImmutableList.of(notificationChannel)); 15403 try { 15404 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 15405 } catch (RemoteException e) { 15406 throw new RuntimeException(e); 15407 } 15408 latch.countDown(); 15409 }).start(); 15410 new Thread(() -> { 15411 try { 15412 synchronized (this) { 15413 wait(5000); 15414 } 15415 mService.createNotificationChannelGroup(mPkg, mUid, 15416 new NotificationChannelGroup("new", "new group"), true, false); 15417 NotificationChannel notificationChannel = 15418 new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH); 15419 notificationChannel.setGroup("new"); 15420 ParceledListSlice<NotificationChannel> pls = 15421 new ParceledListSlice(ImmutableList.of(notificationChannel)); 15422 try { 15423 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 15424 mBinderService.deleteNotificationChannelGroup(mPkg, "group"); 15425 } catch (RemoteException e) { 15426 throw new RuntimeException(e); 15427 } 15428 } catch (Exception e) { 15429 e.printStackTrace(); 15430 } 15431 latch.countDown(); 15432 }).start(); 15433 15434 latch.await(); 15435 verify(mJsi).isNotificationChannelAssociatedWithAnyUserInitiatedJobs( 15436 anyString(), anyInt(), anyString()); 15437 } 15438 15439 @Test 15440 public void testRemoveUserInitiatedJobFlagFromNotification_enqueued() { 15441 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15442 .thenReturn(true); 15443 Notification n = new Notification.Builder(mContext, "").build(); 15444 n.flags |= FLAG_USER_INITIATED_JOB; 15445 15446 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 15447 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15448 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15449 15450 mService.addEnqueuedNotification(r); 15451 15452 mInternalService.removeUserInitiatedJobFlagFromNotification( 15453 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15454 15455 waitForIdle(); 15456 15457 verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); 15458 } 15459 15460 @Test 15461 public void testRemoveUserInitiatedJobFlagFromNotification_posted() { 15462 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15463 .thenReturn(true); 15464 Notification n = new Notification.Builder(mContext, "").build(); 15465 n.flags |= FLAG_USER_INITIATED_JOB; 15466 15467 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 15468 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15469 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15470 15471 mService.addNotification(r); 15472 15473 mInternalService.removeUserInitiatedJobFlagFromNotification( 15474 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15475 15476 waitForIdle(); 15477 15478 ArgumentCaptor<NotificationRecord> captor = 15479 ArgumentCaptor.forClass(NotificationRecord.class); 15480 verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); 15481 15482 assertEquals(0, captor.getValue().getNotification().flags); 15483 } 15484 15485 @Test 15486 public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_enqueued() { 15487 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15488 Notification n = new Notification.Builder(mContext, "").build(); 15489 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 15490 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15491 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15492 mService.addEnqueuedNotification(r); 15493 } 15494 Notification n = new Notification.Builder(mContext, "").build(); 15495 n.flags |= FLAG_USER_INITIATED_JOB; 15496 15497 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 15498 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 15499 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15500 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15501 15502 mService.addEnqueuedNotification(r); 15503 15504 mInternalService.removeUserInitiatedJobFlagFromNotification( 15505 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15506 15507 waitForIdle(); 15508 15509 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 15510 mService.getNotificationRecordCount()); 15511 } 15512 15513 @Test 15514 public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_posted() { 15515 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15516 .thenReturn(true); 15517 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15518 Notification n = new Notification.Builder(mContext, "").build(); 15519 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 15520 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15521 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15522 mService.addNotification(r); 15523 } 15524 Notification n = new Notification.Builder(mContext, "").build(); 15525 n.flags |= FLAG_USER_INITIATED_JOB; 15526 15527 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 15528 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 15529 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15530 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15531 15532 mService.addNotification(r); 15533 15534 mInternalService.removeUserInitiatedJobFlagFromNotification( 15535 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15536 15537 waitForIdle(); 15538 15539 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 15540 mService.getNotificationRecordCount()); 15541 } 15542 15543 @Test 15544 public void testCanPostUijWhenOverLimit() throws RemoteException { 15545 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15546 .thenReturn(true); 15547 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15548 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 15549 i, null, false).getSbn(); 15550 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCanPostUijWhenOverLimit", 15551 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15552 } 15553 15554 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15555 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15556 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15557 "testCanPostUijWhenOverLimit - uij over limit!", 15558 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15559 15560 waitForIdle(); 15561 15562 StatusBarNotification[] notifs = 15563 mBinderService.getActiveNotifications(sbn.getPackageName()); 15564 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 15565 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 15566 mService.getNotificationRecordCount()); 15567 } 15568 15569 @Test 15570 public void testCannotPostNonUijWhenOverLimit() throws RemoteException { 15571 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15572 .thenReturn(true); 15573 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15574 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 15575 i, null, false).getSbn(); 15576 mBinderService.enqueueNotificationWithTag( 15577 mPkg, 15578 mPkg, 15579 "testCannotPostNonUijWhenOverLimit", 15580 sbn.getId(), 15581 sbn.getNotification(), 15582 sbn.getUserId()); 15583 waitForIdle(); 15584 } 15585 15586 final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 15587 100, null, false).getSbn(); 15588 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15589 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15590 "testCannotPostNonUijWhenOverLimit - uij over limit!", 15591 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15592 15593 final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel, 15594 101, null, false).getSbn(); 15595 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15596 "testCannotPostNonUijWhenOverLimit - non uij over limit!", 15597 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId()); 15598 15599 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15600 .thenReturn(false); 15601 final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel, 15602 101, null, false).getSbn(); 15603 sbn3.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15604 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15605 "testCannotPostNonUijWhenOverLimit - fake uij over limit!", 15606 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId()); 15607 15608 waitForIdle(); 15609 15610 StatusBarNotification[] notifs = 15611 mBinderService.getActiveNotifications(sbn.getPackageName()); 15612 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 15613 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 15614 mService.getNotificationRecordCount()); 15615 } 15616 15617 @Test 15618 public void fixNotification_withUijFlag_butIsNotUij() throws Exception { 15619 final ApplicationInfo applicationInfo = new ApplicationInfo(); 15620 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 15621 .thenReturn(applicationInfo); 15622 15623 Notification n = new Notification.Builder(mContext, "test") 15624 .setFlag(FLAG_USER_INITIATED_JOB, true) 15625 .build(); 15626 15627 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15628 assertFalse(n.isUserInitiatedJob()); 15629 } 15630 15631 @Test 15632 public void enqueue_updatesEnqueueRate() throws Exception { 15633 Notification n = generateNotificationRecord(null).getNotification(); 15634 15635 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 15636 // Don't waitForIdle() here. We want to verify the "intermediate" state. 15637 15638 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15639 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15640 verify(mUsageStats, never()).registerPostedByApp(any()); 15641 15642 waitForIdle(); 15643 } 15644 15645 @Test 15646 public void enqueue_withPost_updatesEnqueueRateAndPost() throws Exception { 15647 Notification n = generateNotificationRecord(null).getNotification(); 15648 15649 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 15650 waitForIdle(); 15651 15652 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15653 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15654 verify(mUsageStats).registerPostedByApp(any()); 15655 } 15656 15657 @Test 15658 public void enqueueNew_whenOverEnqueueRate_accepts() throws Exception { 15659 Notification n = generateNotificationRecord(null).getNotification(); 15660 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 15661 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f); 15662 15663 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 15664 waitForIdle(); 15665 15666 assertThat(mService.mNotificationsByKey).hasSize(1); 15667 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15668 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15669 verify(mUsageStats).registerPostedByApp(any()); 15670 } 15671 15672 @Test 15673 public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception { 15674 // Post the first version. 15675 Notification original = generateNotificationRecord(null).getNotification(); 15676 original.when = System.currentTimeMillis(); 15677 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); 15678 waitForIdle(); 15679 assertThat(mService.mNotificationList).hasSize(1); 15680 assertThat(mService.mNotificationList.get(0).getNotification().when) 15681 .isEqualTo(original.when); 15682 15683 reset(mUsageStats); 15684 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 15685 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE - 1f); 15686 15687 // Post the update. 15688 Notification update = generateNotificationRecord(null).getNotification(); 15689 update.when = System.currentTimeMillis() + 111; 15690 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); 15691 waitForIdle(); 15692 15693 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15694 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15695 verify(mUsageStats, never()).registerPostedByApp(any()); 15696 verify(mUsageStats).registerUpdatedByApp(any(), any()); 15697 assertThat(mService.mNotificationList).hasSize(1); 15698 assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when); 15699 } 15700 15701 @Test 15702 public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception { 15703 // Post the first version. 15704 Notification original = generateNotificationRecord(null).getNotification(); 15705 original.when = System.currentTimeMillis(); 15706 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); 15707 waitForIdle(); 15708 assertThat(mService.mNotificationList).hasSize(1); 15709 assertThat(mService.mNotificationList.get(0).getNotification().when) 15710 .isEqualTo(original.when); 15711 15712 reset(mUsageStats); 15713 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 15714 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f); 15715 15716 // Post the update. 15717 Notification update = generateNotificationRecord(null).getNotification(); 15718 update.when = System.currentTimeMillis() + 111; 15719 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); 15720 waitForIdle(); 15721 15722 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15723 verify(mUsageStats, never()).registerEnqueuedByAppAndAccepted(any()); 15724 verify(mUsageStats, never()).registerPostedByApp(any()); 15725 verify(mUsageStats, never()).registerUpdatedByApp(any(), any()); 15726 assertThat(mService.mNotificationList).hasSize(1); 15727 assertThat(mService.mNotificationList.get(0).getNotification().when) 15728 .isEqualTo(original.when); // old 15729 } 15730 15731 @Test 15732 public void enqueueNotification_acceptsCorrectToken() throws RemoteException { 15733 Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15734 .setContentIntent(createPendingIntent("content")) 15735 .build(); 15736 Notification received = parcelAndUnparcel(sent, Notification.CREATOR); 15737 assertThat(received.getAllowlistToken()).isEqualTo( 15738 NotificationManagerService.ALLOWLIST_TOKEN); 15739 15740 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 15741 parcelAndUnparcel(received, Notification.CREATOR), mUserId); 15742 waitForIdle(); 15743 15744 assertThat(mService.mNotificationList).hasSize(1); 15745 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 15746 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 15747 } 15748 15749 @Test 15750 public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException { 15751 Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15752 .setContentIntent(createPendingIntent("content")) 15753 .build(); 15754 assertThat(receivedWithoutParceling.getAllowlistToken()).isNull(); 15755 15756 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 15757 parcelAndUnparcel(receivedWithoutParceling, Notification.CREATOR), mUserId); 15758 waitForIdle(); 15759 15760 assertThat(mService.mNotificationList).hasSize(1); 15761 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 15762 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 15763 } 15764 15765 @Test 15766 public void enqueueNotification_directlyThroughRunnable_populatesAllowlistToken() { 15767 Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15768 .setContentIntent(createPendingIntent("content")) 15769 .build(); 15770 NotificationRecord record = new NotificationRecord( 15771 mContext, 15772 new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 44, receivedWithoutParceling, 15773 mUser, "groupKey", 0), 15774 mTestNotificationChannel); 15775 assertThat(record.getNotification().getAllowlistToken()).isNull(); 15776 15777 mWorkerHandler.post( 15778 mService.new EnqueueNotificationRunnable(mUserId, record, false, false, 15779 mPostNotificationTrackerFactory.newTracker(null))); 15780 waitForIdle(); 15781 15782 assertThat(mService.mNotificationList).hasSize(1); 15783 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 15784 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 15785 } 15786 15787 @Test 15788 public void enqueueNotification_rejectsOtherToken() throws RemoteException { 15789 Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15790 .setContentIntent(createPendingIntent("content")) 15791 .build(); 15792 sent.overrideAllowlistToken(new Binder()); 15793 Notification received = parcelAndUnparcel(sent, Notification.CREATOR); 15794 assertThat(received.getAllowlistToken()).isEqualTo(sent.getAllowlistToken()); 15795 15796 assertThrows(SecurityException.class, () -> 15797 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 15798 parcelAndUnparcel(received, Notification.CREATOR), mUserId)); 15799 waitForIdle(); 15800 15801 assertThat(mService.mNotificationList).isEmpty(); 15802 } 15803 15804 @Test 15805 public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents() 15806 throws RemoteException { 15807 Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15808 .setContentIntent(createPendingIntent("content")) 15809 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) 15810 .setContentIntent(createPendingIntent("public")) 15811 .build()) 15812 .build(); 15813 sentFromApp.publicVersion.overrideAllowlistToken(new Binder()); 15814 15815 // Instead of using the normal parceling, assume the caller parcels it by hand, including a 15816 // null token in the outer notification (as would be expected, and as is verified by 15817 // enqueue) but trying to sneak in a different one in the inner notification, hoping it gets 15818 // propagated to the PendingIntents. 15819 Parcel parcelSentFromApp = Parcel.obtain(); 15820 writeNotificationToParcelCustom(parcelSentFromApp, sentFromApp, new ArraySet<>( 15821 Lists.newArrayList(sentFromApp.contentIntent, 15822 sentFromApp.publicVersion.contentIntent))); 15823 15824 // Use the unparceling as received in enqueueNotificationWithTag() 15825 parcelSentFromApp.setDataPosition(0); 15826 Notification receivedByNms = new Notification(parcelSentFromApp); 15827 15828 // Verify that all the pendingIntents have the correct token. 15829 assertThat(receivedByNms.contentIntent.getWhitelistToken()).isEqualTo( 15830 NotificationManagerService.ALLOWLIST_TOKEN); 15831 assertThat(receivedByNms.publicVersion.contentIntent.getWhitelistToken()).isEqualTo( 15832 NotificationManagerService.ALLOWLIST_TOKEN); 15833 } 15834 15835 /** 15836 * Replicates the behavior of {@link Notification#writeToParcel} but excluding the 15837 * "always use the same allowlist token as the root notification" parts. 15838 */ 15839 private static void writeNotificationToParcelCustom(Parcel parcel, Notification notif, 15840 ArraySet<PendingIntent> allPendingIntents) { 15841 int flags = 0; 15842 parcel.writeInt(1); // version? 15843 15844 parcel.writeStrongBinder(notif.getAllowlistToken()); 15845 parcel.writeLong(notif.when); 15846 parcel.writeLong(notif.creationTime); 15847 if (notif.getSmallIcon() != null) { 15848 parcel.writeInt(1); 15849 notif.getSmallIcon().writeToParcel(parcel, 0); 15850 } else { 15851 parcel.writeInt(0); 15852 } 15853 parcel.writeInt(notif.number); 15854 if (notif.contentIntent != null) { 15855 parcel.writeInt(1); 15856 notif.contentIntent.writeToParcel(parcel, 0); 15857 } else { 15858 parcel.writeInt(0); 15859 } 15860 if (notif.deleteIntent != null) { 15861 parcel.writeInt(1); 15862 notif.deleteIntent.writeToParcel(parcel, 0); 15863 } else { 15864 parcel.writeInt(0); 15865 } 15866 if (notif.tickerText != null) { 15867 parcel.writeInt(1); 15868 TextUtils.writeToParcel(notif.tickerText, parcel, flags); 15869 } else { 15870 parcel.writeInt(0); 15871 } 15872 if (notif.tickerView != null) { 15873 parcel.writeInt(1); 15874 notif.tickerView.writeToParcel(parcel, 0); 15875 } else { 15876 parcel.writeInt(0); 15877 } 15878 if (notif.contentView != null) { 15879 parcel.writeInt(1); 15880 notif.contentView.writeToParcel(parcel, 0); 15881 } else { 15882 parcel.writeInt(0); 15883 } 15884 if (notif.getLargeIcon() != null) { 15885 parcel.writeInt(1); 15886 notif.getLargeIcon().writeToParcel(parcel, 0); 15887 } else { 15888 parcel.writeInt(0); 15889 } 15890 15891 parcel.writeInt(notif.defaults); 15892 parcel.writeInt(notif.flags); 15893 15894 if (notif.sound != null) { 15895 parcel.writeInt(1); 15896 notif.sound.writeToParcel(parcel, 0); 15897 } else { 15898 parcel.writeInt(0); 15899 } 15900 parcel.writeInt(notif.audioStreamType); 15901 15902 if (notif.audioAttributes != null) { 15903 parcel.writeInt(1); 15904 notif.audioAttributes.writeToParcel(parcel, 0); 15905 } else { 15906 parcel.writeInt(0); 15907 } 15908 15909 parcel.writeLongArray(notif.vibrate); 15910 parcel.writeInt(notif.ledARGB); 15911 parcel.writeInt(notif.ledOnMS); 15912 parcel.writeInt(notif.ledOffMS); 15913 parcel.writeInt(notif.iconLevel); 15914 15915 if (notif.fullScreenIntent != null) { 15916 parcel.writeInt(1); 15917 notif.fullScreenIntent.writeToParcel(parcel, 0); 15918 } else { 15919 parcel.writeInt(0); 15920 } 15921 15922 parcel.writeInt(notif.priority); 15923 15924 parcel.writeString8(notif.category); 15925 15926 parcel.writeString8(notif.getGroup()); 15927 15928 parcel.writeString8(notif.getSortKey()); 15929 15930 parcel.writeBundle(notif.extras); // null ok 15931 15932 parcel.writeTypedArray(notif.actions, 0); // null ok 15933 15934 if (notif.bigContentView != null) { 15935 parcel.writeInt(1); 15936 notif.bigContentView.writeToParcel(parcel, 0); 15937 } else { 15938 parcel.writeInt(0); 15939 } 15940 15941 if (notif.headsUpContentView != null) { 15942 parcel.writeInt(1); 15943 notif.headsUpContentView.writeToParcel(parcel, 0); 15944 } else { 15945 parcel.writeInt(0); 15946 } 15947 15948 parcel.writeInt(notif.visibility); 15949 15950 if (notif.publicVersion != null) { 15951 parcel.writeInt(1); 15952 writeNotificationToParcelCustom(parcel, notif.publicVersion, new ArraySet<>()); 15953 } else { 15954 parcel.writeInt(0); 15955 } 15956 15957 parcel.writeInt(notif.color); 15958 15959 if (notif.getChannelId() != null) { 15960 parcel.writeInt(1); 15961 parcel.writeString8(notif.getChannelId()); 15962 } else { 15963 parcel.writeInt(0); 15964 } 15965 parcel.writeLong(notif.getTimeoutAfter()); 15966 15967 if (notif.getShortcutId() != null) { 15968 parcel.writeInt(1); 15969 parcel.writeString8(notif.getShortcutId()); 15970 } else { 15971 parcel.writeInt(0); 15972 } 15973 15974 if (notif.getLocusId() != null) { 15975 parcel.writeInt(1); 15976 notif.getLocusId().writeToParcel(parcel, 0); 15977 } else { 15978 parcel.writeInt(0); 15979 } 15980 15981 parcel.writeInt(notif.getBadgeIconType()); 15982 15983 if (notif.getSettingsText() != null) { 15984 parcel.writeInt(1); 15985 TextUtils.writeToParcel(notif.getSettingsText(), parcel, flags); 15986 } else { 15987 parcel.writeInt(0); 15988 } 15989 15990 parcel.writeInt(notif.getGroupAlertBehavior()); 15991 15992 if (notif.getBubbleMetadata() != null) { 15993 parcel.writeInt(1); 15994 notif.getBubbleMetadata().writeToParcel(parcel, 0); 15995 } else { 15996 parcel.writeInt(0); 15997 } 15998 15999 parcel.writeBoolean(notif.getAllowSystemGeneratedContextualActions()); 16000 16001 parcel.writeInt(Notification.FOREGROUND_SERVICE_DEFAULT); // no getter for mFgsDeferBehavior 16002 16003 // mUsesStandardHeader is not written because it should be recomputed in listeners 16004 16005 parcel.writeArraySet(allPendingIntents); 16006 } 16007 16008 @Test 16009 @SuppressWarnings("unchecked") 16010 public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException { 16011 Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) 16012 .setContentIntent(createPendingIntent("content")) 16013 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) 16014 .setContentIntent(createPendingIntent("public")) 16015 .build()) 16016 .extend(new Notification.WearableExtender() 16017 .addPage(new Notification.Builder(mContext, TEST_CHANNEL_ID) 16018 .setContentIntent(createPendingIntent("wearPage")) 16019 .build())) 16020 .build(); 16021 // Binder transition: app -> NMS 16022 Notification receivedByNms = parcelAndUnparcel(sentFromApp, Notification.CREATOR); 16023 assertThat(receivedByNms.getAllowlistToken()).isEqualTo( 16024 NotificationManagerService.ALLOWLIST_TOKEN); 16025 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 16026 parcelAndUnparcel(receivedByNms, Notification.CREATOR), mUserId); 16027 waitForIdle(); 16028 assertThat(mService.mNotificationList).hasSize(1); 16029 Notification posted = mService.mNotificationList.get(0).getNotification(); 16030 assertThat(posted.getAllowlistToken()).isEqualTo( 16031 NotificationManagerService.ALLOWLIST_TOKEN); 16032 assertThat(posted.contentIntent.getWhitelistToken()).isEqualTo( 16033 NotificationManagerService.ALLOWLIST_TOKEN); 16034 16035 ParceledListSlice<StatusBarNotification> listSentFromNms = 16036 mBinderService.getAppActiveNotifications(mPkg, mUserId); 16037 // Binder transition: NMS -> app. App doesn't have the allowlist token so clear it 16038 // (having a different one would produce the same effect; the relevant thing is to not let 16039 // out ALLOWLIST_TOKEN). 16040 // Note: for other tests, this is restored by constructing TestableNMS in setup(). 16041 Notification.processAllowlistToken = null; 16042 ParceledListSlice<StatusBarNotification> listReceivedByApp = parcelAndUnparcel( 16043 listSentFromNms, ParceledListSlice.CREATOR); 16044 Notification gottenBackByApp = listReceivedByApp.getList().get(0).getNotification(); 16045 16046 assertThat(gottenBackByApp.getAllowlistToken()).isNull(); 16047 assertThat(gottenBackByApp.contentIntent.getWhitelistToken()).isNull(); 16048 assertThat(gottenBackByApp.publicVersion.getAllowlistToken()).isNull(); 16049 assertThat(gottenBackByApp.publicVersion.contentIntent.getWhitelistToken()).isNull(); 16050 assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() 16051 .get(0).getAllowlistToken()).isNull(); 16052 assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() 16053 .get(0).contentIntent.getWhitelistToken()).isNull(); 16054 } 16055 16056 @Test 16057 public void enqueueNotification_allowlistsPendingIntents() throws RemoteException { 16058 PendingIntent contentIntent = createPendingIntent("content"); 16059 PendingIntent actionIntent1 = createPendingIntent("action1"); 16060 PendingIntent actionIntent2 = createPendingIntent("action2"); 16061 Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID) 16062 .setContentIntent(contentIntent) 16063 .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build()) 16064 .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build()) 16065 .build(); 16066 16067 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 16068 parcelAndUnparcel(n, Notification.CREATOR), mUserId); 16069 16070 verify(mAmi, times(3)).setPendingIntentAllowlistDuration( 16071 any(), any(), anyLong(), 16072 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED), 16073 eq(REASON_NOTIFICATION_SERVICE), any()); 16074 verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(), 16075 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER)); 16076 contentIntent.cancel(); 16077 actionIntent2.cancel(); 16078 actionIntent1.cancel(); 16079 } 16080 16081 @Test 16082 public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion() 16083 throws RemoteException { 16084 PendingIntent contentIntent = createPendingIntent("content"); 16085 PendingIntent actionIntent = createPendingIntent("action"); 16086 PendingIntent publicContentIntent = createPendingIntent("publicContent"); 16087 PendingIntent publicActionIntent = createPendingIntent("publicAction"); 16088 Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID) 16089 .setContentIntent(contentIntent) 16090 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build()) 16091 .setPublicVersion(new Notification.Builder(mContext, "channel") 16092 .setContentIntent(publicContentIntent) 16093 .addAction(new Notification.Action.Builder( 16094 null, "publicAction", publicActionIntent).build()) 16095 .build()) 16096 .build(); 16097 16098 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 16099 parcelAndUnparcel(source, Notification.CREATOR), mUserId); 16100 16101 verify(mAmi, times(4)).setPendingIntentAllowlistDuration( 16102 any(), any(), anyLong(), 16103 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED), 16104 eq(REASON_NOTIFICATION_SERVICE), any()); 16105 verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(), 16106 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER)); 16107 contentIntent.cancel(); 16108 publicContentIntent.cancel(); 16109 actionIntent.cancel(); 16110 publicActionIntent.cancel(); 16111 } 16112 16113 @Test 16114 @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL) 16115 public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() { 16116 mService.mZenModeHelper = mock(ZenModeHelper.class); 16117 mService.setPreferencesHelper(mPreferencesHelper); 16118 16119 UserInfo prevUser = new UserInfo(); 16120 prevUser.id = 10; 16121 UserInfo newUser = new UserInfo(); 16122 newUser.id = 20; 16123 16124 mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser)); 16125 16126 InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper); 16127 inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20)); 16128 inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd(); 16129 inOrder.verifyNoMoreInteractions(); 16130 } 16131 16132 @Test 16133 @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL) 16134 public void onUserSwitched_broadcast_updatesZenModeAndChannelsBypassingDnd() { 16135 Intent intent = new Intent(Intent.ACTION_USER_SWITCHED); 16136 intent.putExtra(Intent.EXTRA_USER_HANDLE, 20); 16137 mService.mZenModeHelper = mock(ZenModeHelper.class); 16138 mService.setPreferencesHelper(mPreferencesHelper); 16139 16140 mUserIntentReceiver.onReceive(mContext, intent); 16141 16142 InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper); 16143 inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20)); 16144 inOrder.verify(mPreferencesHelper).syncChannelsBypassingDnd(); 16145 inOrder.verifyNoMoreInteractions(); 16146 } 16147 16148 @Test 16149 public void isNotificationPolicyAccessGranted_invalidPackage() throws Exception { 16150 final String notReal = "NOT REAL"; 16151 final var checker = mService.permissionChecker; 16152 16153 when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( 16154 PackageManager.NameNotFoundException.class); 16155 16156 assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse(); 16157 verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt()); 16158 verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean()); 16159 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt()); 16160 verify(mListeners, never()).isComponentEnabledForPackage(any()); 16161 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16162 } 16163 16164 @Test 16165 public void isNotificationPolicyAccessGranted_hasPermission() throws Exception { 16166 final String packageName = "target"; 16167 final int uid = 123; 16168 final var checker = mService.permissionChecker; 16169 16170 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16171 when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true)) 16172 .thenReturn(PackageManager.PERMISSION_GRANTED); 16173 16174 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16175 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16176 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16177 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16178 verify(mListeners, never()).isComponentEnabledForPackage(any()); 16179 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16180 } 16181 16182 @Test 16183 public void isNotificationPolicyAccessGranted_isPackageAllowed() throws Exception { 16184 final String packageName = "target"; 16185 final int uid = 123; 16186 final var checker = mService.permissionChecker; 16187 16188 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16189 when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt())) 16190 .thenReturn(true); 16191 16192 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16193 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16194 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16195 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16196 verify(mListeners, never()).isComponentEnabledForPackage(any()); 16197 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16198 } 16199 16200 @Test 16201 public void isNotificationPolicyAccessGranted_isComponentEnabled() throws Exception { 16202 final String packageName = "target"; 16203 final int uid = 123; 16204 final var checker = mService.permissionChecker; 16205 16206 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16207 when(mListeners.isComponentEnabledForPackage(packageName)).thenReturn(true); 16208 16209 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16210 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16211 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16212 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16213 verify(mListeners).isComponentEnabledForPackage(packageName); 16214 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16215 } 16216 16217 @Test 16218 public void isNotificationPolicyAccessGranted_isDeviceOwner() throws Exception { 16219 final String packageName = "target"; 16220 final int uid = 123; 16221 final var checker = mService.permissionChecker; 16222 16223 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16224 when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true); 16225 16226 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16227 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16228 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16229 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16230 verify(mListeners).isComponentEnabledForPackage(packageName); 16231 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16232 } 16233 16234 /** 16235 * b/292163859 16236 */ 16237 @Test 16238 public void isNotificationPolicyAccessGranted_callerIsDeviceOwner() throws Exception { 16239 final String packageName = "target"; 16240 final int uid = 123; 16241 final int callingUid = Binder.getCallingUid(); 16242 final var checker = mService.permissionChecker; 16243 16244 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16245 when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true); 16246 16247 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 16248 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16249 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16250 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16251 verify(mListeners).isComponentEnabledForPackage(packageName); 16252 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16253 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid); 16254 } 16255 16256 @Test 16257 public void isNotificationPolicyAccessGranted_notGranted() throws Exception { 16258 final String packageName = "target"; 16259 final int uid = 123; 16260 final var checker = mService.permissionChecker; 16261 16262 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16263 16264 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 16265 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16266 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16267 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16268 verify(mListeners).isComponentEnabledForPackage(packageName); 16269 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16270 } 16271 16272 @Test 16273 public void testResetDefaultDnd() { 16274 TestableNotificationManagerService service = spy(mService); 16275 UserInfo user = new UserInfo(0, "owner", 0); 16276 when(mUm.getAliveUsers()).thenReturn(List.of(user)); 16277 doReturn(false).when(service).isDNDMigrationDone(anyInt()); 16278 16279 service.resetDefaultDndIfNecessary(); 16280 16281 verify(mConditionProviders, times(1)).removeDefaultFromConfig(user.id); 16282 verify(mConditionProviders, times(1)).resetDefaultFromConfig(); 16283 verify(service, times(1)).allowDndPackages(user.id); 16284 verify(service, times(1)).setDNDMigrationDone(user.id); 16285 } 16286 16287 @Test 16288 public void testProfileUnavailableIntent() throws RemoteException { 16289 mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE, 16290 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 16291 simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE); 16292 verify(mWorkerHandler).post(any(Runnable.class)); 16293 verify(mSnoozeHelper).clearData(anyInt()); 16294 } 16295 16296 16297 @Test 16298 public void testManagedProfileUnavailableIntent() throws RemoteException { 16299 mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE, 16300 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 16301 simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 16302 verify(mWorkerHandler).post(any(Runnable.class)); 16303 verify(mSnoozeHelper).clearData(anyInt()); 16304 } 16305 16306 @Test 16307 @EnableFlags(android.app.Flags.FLAG_MODES_API) 16308 public void setDeviceEffectsApplier_succeeds() throws Exception { 16309 initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY); 16310 16311 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)); 16312 16313 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 16314 // No exception! 16315 } 16316 16317 @Test 16318 @EnableFlags(android.app.Flags.FLAG_MODES_API) 16319 public void setDeviceEffectsApplier_tooLate_throws() throws Exception { 16320 initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); 16321 16322 assertThrows(IllegalStateException.class, () -> 16323 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class))); 16324 } 16325 16326 @Test 16327 @EnableFlags(android.app.Flags.FLAG_MODES_API) 16328 public void setDeviceEffectsApplier_calledTwice_throws() throws Exception { 16329 initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY); 16330 16331 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)); 16332 assertThrows(IllegalStateException.class, () -> 16333 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class))); 16334 } 16335 16336 @Test 16337 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16338 public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException { 16339 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16340 mService.setCallerIsNormalPackage(); 16341 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 16342 mService.mZenModeHelper = zenHelper; 16343 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16344 .thenReturn(true); 16345 16346 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16347 mBinderService.setNotificationPolicy("package", policy, false); 16348 16349 verify(zenHelper).applyGlobalPolicyAsImplicitZenRule(any(), eq("package"), anyInt(), 16350 eq(policy)); 16351 } 16352 16353 @Test 16354 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16355 public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException { 16356 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16357 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16358 mService.mZenModeHelper = zenModeHelper; 16359 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16360 .thenReturn(true); 16361 mService.isSystemUid = true; 16362 16363 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16364 mBinderService.setNotificationPolicy("package", policy, false); 16365 16366 verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt()); 16367 } 16368 16369 @Test 16370 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16371 public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy() 16372 throws RemoteException { 16373 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16374 AssociationRequest.DEVICE_PROFILE_WATCH, true); 16375 } 16376 16377 @Test 16378 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16379 public void setNotificationPolicy_autoCompanionApp_setsGlobalPolicy() 16380 throws RemoteException { 16381 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16382 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true); 16383 } 16384 16385 @Test 16386 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16387 public void setNotificationPolicy_otherCompanionApp_doesNotSetGlobalPolicy() 16388 throws RemoteException { 16389 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16390 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false); 16391 } 16392 16393 private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16394 @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy) 16395 throws RemoteException { 16396 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16397 mService.setCallerIsNormalPackage(); 16398 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16399 mService.mZenModeHelper = zenModeHelper; 16400 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16401 .thenReturn(true); 16402 when(mCompanionMgr.getAssociations(anyString(), anyInt())) 16403 .thenReturn(ImmutableList.of( 16404 new AssociationInfo.Builder(1, mUserId, "package") 16405 .setDisplayName("My connected device") 16406 .setDeviceProfile(deviceProfile) 16407 .build())); 16408 16409 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16410 mBinderService.setNotificationPolicy("package", policy, false); 16411 16412 if (canSetGlobalPolicy) { 16413 verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt()); 16414 } else { 16415 verify(zenModeHelper).applyGlobalPolicyAsImplicitZenRule(any(), anyString(), anyInt(), 16416 eq(policy)); 16417 } 16418 } 16419 16420 @Test 16421 @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16422 public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException { 16423 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16424 mService.setCallerIsNormalPackage(); 16425 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16426 mService.mZenModeHelper = zenModeHelper; 16427 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16428 .thenReturn(true); 16429 16430 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16431 mBinderService.setNotificationPolicy("package", policy, false); 16432 16433 verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt()); 16434 } 16435 16436 @Test 16437 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16438 public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException { 16439 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16440 mService.setCallerIsNormalPackage(); 16441 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 16442 mService.mZenModeHelper = zenHelper; 16443 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16444 .thenReturn(true); 16445 16446 mBinderService.getNotificationPolicy("package"); 16447 16448 verify(zenHelper).getNotificationPolicyFromImplicitZenRule(any(), eq("package")); 16449 } 16450 16451 @Test 16452 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16453 public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException { 16454 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16455 mService.setCallerIsNormalPackage(); 16456 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 16457 mService.mZenModeHelper = zenHelper; 16458 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16459 .thenReturn(true); 16460 16461 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 16462 16463 verify(zenHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("package"), anyInt(), 16464 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 16465 } 16466 16467 @Test 16468 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16469 public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException { 16470 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16471 mService.setCallerIsNormalPackage(); 16472 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16473 mService.mZenModeHelper = zenModeHelper; 16474 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16475 .thenReturn(true); 16476 mService.isSystemUid = true; 16477 16478 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 16479 16480 verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), 16481 eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), eq("package"), anyInt()); 16482 } 16483 16484 @Test 16485 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16486 public void setInterruptionFilter_watchCompanionApp_setsGlobalZen() throws RemoteException { 16487 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16488 AssociationRequest.DEVICE_PROFILE_WATCH, true); 16489 } 16490 16491 @Test 16492 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16493 public void setInterruptionFilter_autoCompanionApp_setsGlobalZen() throws RemoteException { 16494 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16495 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true); 16496 } 16497 16498 @Test 16499 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16500 public void setInterruptionFilter_otherCompanionApp_doesNotSetGlobalZen() 16501 throws RemoteException { 16502 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16503 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false); 16504 } 16505 16506 private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16507 @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy) 16508 throws RemoteException { 16509 mSetFlagsRule.enableFlags(android.app.Flags.FLAG_MODES_API); 16510 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16511 mService.mZenModeHelper = zenModeHelper; 16512 mService.setCallerIsNormalPackage(); 16513 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16514 .thenReturn(true); 16515 when(mCompanionMgr.getAssociations(anyString(), anyInt())) 16516 .thenReturn(ImmutableList.of( 16517 new AssociationInfo.Builder(1, mUserId, "package") 16518 .setDisplayName("My connected device") 16519 .setDeviceProfile(deviceProfile) 16520 .build())); 16521 16522 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 16523 16524 if (canSetGlobalPolicy) { 16525 verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), 16526 eq(null), eq(ZenModeConfig.ORIGIN_APP), anyString(), eq("package"), anyInt()); 16527 } else { 16528 verify(zenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), anyString(), anyInt(), 16529 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 16530 } 16531 } 16532 16533 @Test 16534 @EnableFlags(android.app.Flags.FLAG_MODES_API) 16535 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16536 public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen() 16537 throws Exception { 16538 mService.setCallerIsNormalPackage(); 16539 mService.mZenModeHelper = mock(ZenModeHelper.class); 16540 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 16541 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 16542 info.component = new ComponentName("pkg", "cls"); 16543 16544 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 16545 INTERRUPTION_FILTER_PRIORITY); 16546 16547 verify(mService.mZenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("pkg"), 16548 eq(mUid), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 16549 } 16550 16551 @Test 16552 @EnableFlags(android.app.Flags.FLAG_MODES_API) 16553 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16554 public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen() 16555 throws Exception { 16556 mService.isSystemUid = true; 16557 mService.mZenModeHelper = mock(ZenModeHelper.class); 16558 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 16559 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 16560 info.component = new ComponentName("pkg", "cls"); 16561 16562 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 16563 INTERRUPTION_FILTER_PRIORITY); 16564 16565 verify(mService.mZenModeHelper).setManualZenMode(any(), 16566 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM), 16567 anyString(), eq("pkg"), eq(mUid)); 16568 } 16569 16570 @Test 16571 @DisableFlags(android.app.Flags.FLAG_MODES_API) 16572 public void requestInterruptionFilterFromListener_flagOff_callsRequestFromListener() 16573 throws Exception { 16574 mService.setCallerIsNormalPackage(); 16575 mService.mZenModeHelper = mock(ZenModeHelper.class); 16576 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 16577 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 16578 info.component = new ComponentName("pkg", "cls"); 16579 16580 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 16581 INTERRUPTION_FILTER_PRIORITY); 16582 16583 verify(mService.mZenModeHelper).requestFromListener(eq(info.component), 16584 eq(INTERRUPTION_FILTER_PRIORITY), eq(mUid), /* fromSystemOrSystemUi= */ eq(false)); 16585 } 16586 16587 @Test 16588 @EnableFlags(android.app.Flags.FLAG_MODES_API) 16589 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16590 public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception { 16591 setUpRealZenTest(); 16592 mService.setCallerIsNormalPackage(); 16593 assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); 16594 16595 // Create an implicit zen rule by calling setNotificationPolicy from an app. 16596 mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false); 16597 assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); 16598 Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( 16599 mBinderService.getAutomaticZenRules().entrySet()); 16600 assertThat(rule.getValue().getOwner()).isNull(); 16601 assertThat(rule.getValue().getConfigurationActivity()).isNull(); 16602 16603 // Now try to update said rule (e.g. disable it). Should fail. 16604 // We also validate the exception message because NPE could be thrown by all sorts of test 16605 // issues (e.g. misconfigured mocks). 16606 rule.getValue().setEnabled(false); 16607 NullPointerException e = assertThrows(NullPointerException.class, 16608 () -> mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false)); 16609 assertThat(e.getMessage()).isEqualTo( 16610 "Rule must have a ConditionProviderService and/or configuration activity"); 16611 } 16612 16613 @Test 16614 @EnableFlags(android.app.Flags.FLAG_MODES_API) 16615 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16616 public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception { 16617 setUpRealZenTest(); 16618 mService.setCallerIsNormalPackage(); 16619 assertThat(mBinderService.getAutomaticZenRules()).isEmpty(); 16620 16621 // Create an implicit zen rule by calling setNotificationPolicy from an app. 16622 mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false); 16623 assertThat(mBinderService.getAutomaticZenRules()).hasSize(1); 16624 Map.Entry<String, AutomaticZenRule> rule = getOnlyElement( 16625 mBinderService.getAutomaticZenRules().entrySet()); 16626 assertThat(rule.getValue().getOwner()).isNull(); 16627 assertThat(rule.getValue().getConfigurationActivity()).isNull(); 16628 16629 // Now update said rule from Settings (e.g. disable it). Should work! 16630 mService.isSystemUid = true; 16631 rule.getValue().setEnabled(false); 16632 mBinderService.updateAutomaticZenRule(rule.getKey(), rule.getValue(), false); 16633 16634 Map.Entry<String, AutomaticZenRule> updatedRule = getOnlyElement( 16635 mBinderService.getAutomaticZenRules().entrySet()); 16636 assertThat(updatedRule.getValue().isEnabled()).isFalse(); 16637 } 16638 16639 @Test 16640 @EnableFlags({android.app.Flags.FLAG_MODES_API, android.app.Flags.FLAG_MODES_UI}) 16641 public void setNotificationPolicy_fromSystemApp_appliesPriorityChannelsAllowed() 16642 throws Exception { 16643 setUpRealZenTest(); 16644 // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default"). 16645 mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, 16646 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0), 16647 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID); 16648 16649 // The caller will supply states with "wrong" hasPriorityChannels. 16650 int stateBlockingPriorityChannels = Policy.policyState(false, false); 16651 mBinderService.setNotificationPolicy(mPkg, 16652 new Policy(1, 0, 0, 0, stateBlockingPriorityChannels, 0), false); 16653 16654 // hasPriorityChannels is untouched and allowPriorityChannels was updated. 16655 assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1); 16656 assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo( 16657 Policy.policyState(true, false)); 16658 16659 // Same but setting allowPriorityChannels to true. 16660 int stateAllowingPriorityChannels = Policy.policyState(false, true); 16661 mBinderService.setNotificationPolicy(mPkg, 16662 new Policy(2, 0, 0, 0, stateAllowingPriorityChannels, 0), false); 16663 16664 assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(2); 16665 assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo( 16666 Policy.policyState(true, true)); 16667 } 16668 16669 @Test 16670 @EnableFlags({android.app.Flags.FLAG_MODES_API, android.app.Flags.FLAG_MODES_UI}) 16671 @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16672 public void setNotificationPolicy_fromRegularAppThatCanModifyPolicy_ignoresState() 16673 throws Exception { 16674 setUpRealZenTest(); 16675 // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default"). 16676 mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, 16677 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0), 16678 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID); 16679 mService.setCallerIsNormalPackage(); 16680 16681 mBinderService.setNotificationPolicy(mPkg, 16682 new Policy(1, 0, 0, 0, Policy.policyState(false, false), 0), false); 16683 16684 // Policy was updated but the attempt to change state was ignored (it's a @hide API). 16685 assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1); 16686 assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo( 16687 Policy.policyState(true, true)); 16688 } 16689 16690 /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */ 16691 private void setUpRealZenTest() throws Exception { 16692 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16693 .thenReturn(true); 16694 16695 int iconResId = 79; 16696 String iconResName = "icon_79"; 16697 String pkg = mContext.getPackageName(); 16698 ApplicationInfo appInfoSpy = spy(new ApplicationInfo()); 16699 appInfoSpy.icon = iconResId; 16700 when(appInfoSpy.loadLabel(any())).thenReturn("Test App"); 16701 when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy); 16702 16703 when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName); 16704 when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId); 16705 when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources); 16706 } 16707 16708 @Test 16709 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) 16710 public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception { 16711 Notification n = new Notification.Builder(mContext, "test") 16712 .setFlag(FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true) 16713 .build(); 16714 16715 assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 16716 16717 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 16718 16719 assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0); 16720 } 16721 16722 @Test 16723 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne() 16724 throws RemoteException { 16725 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 16726 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 16727 16728 // Create recent notification. 16729 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 16730 System.currentTimeMillis()); 16731 mService.addNotification(nr1); 16732 16733 // Create old notification. 16734 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 16735 System.currentTimeMillis() - 60000); 16736 mService.addNotification(nr2); 16737 16738 // Cancel specific notifications via listener. 16739 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 16740 mService.getBinderService().cancelNotificationsFromListener(null, keys); 16741 waitForIdle(); 16742 16743 // Notifications should not be active anymore. 16744 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 16745 assertThat(notifications).isEmpty(); 16746 assertEquals(0, mService.getNotificationRecordCount()); 16747 // Ensure cancel event is logged. 16748 verify(mAppOpsManager).noteOpNoThrow( 16749 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null); 16750 } 16751 16752 @Test 16753 public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException { 16754 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 16755 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 16756 16757 // Create old notifications. 16758 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 16759 System.currentTimeMillis() - 60000); 16760 mService.addNotification(nr1); 16761 16762 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 16763 System.currentTimeMillis() - 60000); 16764 mService.addNotification(nr2); 16765 16766 // Cancel specific notifications via listener. 16767 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 16768 mService.getBinderService().cancelNotificationsFromListener(null, keys); 16769 waitForIdle(); 16770 16771 // Notifications should not be active anymore. 16772 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 16773 assertThat(notifications).isEmpty(); 16774 assertEquals(0, mService.getNotificationRecordCount()); 16775 // Ensure cancel event is not logged. 16776 verify(mAppOpsManager, never()).noteOpNoThrow( 16777 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 16778 any(), any()); 16779 } 16780 16781 @Test 16782 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled() 16783 throws RemoteException { 16784 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 16785 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 16786 16787 // Create recent notification. 16788 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 16789 System.currentTimeMillis()); 16790 mService.addNotification(nr1); 16791 16792 // Create old notification. 16793 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 16794 System.currentTimeMillis() - 60000); 16795 mService.addNotification(nr2); 16796 16797 // Cancel specific notifications via listener. 16798 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 16799 mService.getBinderService().cancelNotificationsFromListener(null, keys); 16800 waitForIdle(); 16801 16802 // Notifications should not be active anymore. 16803 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 16804 assertThat(notifications).isEmpty(); 16805 assertEquals(0, mService.getNotificationRecordCount()); 16806 // Ensure cancel event is not logged due to flag being disabled. 16807 verify(mAppOpsManager, never()).noteOpNoThrow( 16808 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 16809 any(), any()); 16810 } 16811 16812 @Test 16813 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll() 16814 throws RemoteException { 16815 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 16816 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 16817 16818 // Create recent notification. 16819 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 16820 System.currentTimeMillis()); 16821 mService.addNotification(nr1); 16822 16823 // Create old notification. 16824 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 16825 System.currentTimeMillis() - 60000); 16826 mService.addNotification(nr2); 16827 16828 // Cancel all notifications via listener. 16829 mService.getBinderService().cancelNotificationsFromListener(null, null); 16830 waitForIdle(); 16831 16832 // Notifications should not be active anymore. 16833 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 16834 assertThat(notifications).isEmpty(); 16835 assertEquals(0, mService.getNotificationRecordCount()); 16836 // Ensure cancel event is logged. 16837 verify(mAppOpsManager).noteOpNoThrow( 16838 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null); 16839 } 16840 16841 @Test 16842 public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException { 16843 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 16844 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 16845 16846 // Create old notifications. 16847 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 16848 System.currentTimeMillis() - 60000); 16849 mService.addNotification(nr1); 16850 16851 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 16852 System.currentTimeMillis() - 60000); 16853 mService.addNotification(nr2); 16854 16855 // Cancel all notifications via listener. 16856 mService.getBinderService().cancelNotificationsFromListener(null, null); 16857 waitForIdle(); 16858 16859 // Notifications should not be active anymore. 16860 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 16861 assertThat(notifications).isEmpty(); 16862 assertEquals(0, mService.getNotificationRecordCount()); 16863 // Ensure cancel event is not logged. 16864 verify(mAppOpsManager, never()).noteOpNoThrow( 16865 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 16866 any(), any()); 16867 } 16868 16869 @Test 16870 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled() 16871 throws RemoteException { 16872 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 16873 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 16874 16875 // Create recent notification. 16876 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 16877 System.currentTimeMillis()); 16878 mService.addNotification(nr1); 16879 16880 // Create old notification. 16881 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 16882 System.currentTimeMillis() - 60000); 16883 mService.addNotification(nr2); 16884 16885 // Cancel all notifications via listener. 16886 mService.getBinderService().cancelNotificationsFromListener(null, null); 16887 waitForIdle(); 16888 16889 // Notifications should not be active anymore. 16890 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 16891 assertThat(notifications).isEmpty(); 16892 assertEquals(0, mService.getNotificationRecordCount()); 16893 // Ensure cancel event is not logged due to flag being disabled. 16894 verify(mAppOpsManager, never()).noteOpNoThrow( 16895 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 16896 any(), any()); 16897 } 16898 16899 @Test 16900 @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) 16901 public void testSetPrivateNotificationsAllowed() throws Exception { 16902 when(mContext.checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) 16903 .thenReturn(PERMISSION_GRANTED); 16904 mBinderService.setPrivateNotificationsAllowed(false); 16905 Intent expected = new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) 16906 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false); 16907 ArgumentCaptor<Intent> actual = ArgumentCaptor.forClass(Intent.class); 16908 verify(mContext).sendBroadcast(actual.capture(), eq(STATUS_BAR_SERVICE)); 16909 16910 assertEquals(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED, actual.getValue().getAction()); 16911 assertFalse(actual.getValue().getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true)); 16912 assertFalse(mBinderService.getPrivateNotificationsAllowed()); 16913 } 16914 16915 @Test 16916 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 16917 public void testCallNotificationListener_NotifiedOnPostCallStyle() throws Exception { 16918 ICallNotificationEventCallback listener = mock( 16919 ICallNotificationEventCallback.class); 16920 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 16921 mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.CURRENT, listener); 16922 waitForIdle(); 16923 16924 final UserHandle userHandle = UserHandle.getUserHandleForUid(mUid); 16925 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, userHandle, 16926 "testCallNotificationListener_NotifiedOnPostCallStyle"); 16927 16928 verify(listener, times(1)).onCallNotificationPosted(mPkg, userHandle); 16929 16930 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 16931 r.getSbn().getUserId()); 16932 waitForIdle(); 16933 16934 verify(listener, times(1)).onCallNotificationRemoved(mPkg, userHandle); 16935 } 16936 16937 @Test 16938 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 16939 public void testCallNotificationListener_NotNotifiedOnPostNonCallStyle() throws Exception { 16940 ICallNotificationEventCallback listener = mock( 16941 ICallNotificationEventCallback.class); 16942 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 16943 mBinderService.registerCallNotificationEventListener(mPkg, 16944 UserHandle.getUserHandleForUid(mUid), listener); 16945 waitForIdle(); 16946 16947 Notification.Builder nb = new Notification.Builder(mContext, 16948 mTestNotificationChannel.getId()).setSmallIcon(android.R.drawable.sym_def_app_icon); 16949 final NotificationRecord r = createAndPostNotification(nb, 16950 "testCallNotificationListener_NotNotifiedOnPostNonCallStyle"); 16951 16952 verify(listener, never()).onCallNotificationPosted(anyString(), any()); 16953 16954 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 16955 r.getSbn().getUserId()); 16956 waitForIdle(); 16957 16958 verify(listener, never()).onCallNotificationRemoved(anyString(), any()); 16959 } 16960 16961 @Test 16962 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 16963 public void testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId() 16964 throws Exception { 16965 ICallNotificationEventCallback listener = mock( 16966 ICallNotificationEventCallback.class); 16967 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 16968 mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.ALL, listener); 16969 waitForIdle(); 16970 16971 final UserHandle otherUser = UserHandle.of(2); 16972 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, 16973 otherUser, "testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId"); 16974 16975 verify(listener, times(1)).onCallNotificationPosted(mPkg, otherUser); 16976 16977 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 16978 r.getSbn().getUserId()); 16979 waitForIdle(); 16980 16981 verify(listener, times(1)).onCallNotificationRemoved(mPkg, otherUser); 16982 } 16983 16984 @Test 16985 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 16986 public void testCallNotificationListener_differentPackage_notNotified() throws Exception { 16987 final String packageName = "package"; 16988 ICallNotificationEventCallback listener = mock( 16989 ICallNotificationEventCallback.class); 16990 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 16991 mBinderService.registerCallNotificationEventListener(packageName, UserHandle.ALL, listener); 16992 waitForIdle(); 16993 16994 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, 16995 UserHandle.of(mUserId), 16996 "testCallNotificationListener_differentPackage_notNotified"); 16997 16998 verify(listener, never()).onCallNotificationPosted(anyString(), any()); 16999 17000 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 17001 r.getSbn().getUserId()); 17002 waitForIdle(); 17003 17004 verify(listener, never()).onCallNotificationRemoved(anyString(), any()); 17005 } 17006 17007 @Test 17008 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17009 public void rankingTime_newNotification_noisy_matchesSbn() throws Exception { 17010 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId); 17011 17012 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17013 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17014 waitForIdle(); 17015 17016 NotificationRecord posted = mService.mNotificationList.get(0); 17017 long originalPostTime = posted.getSbn().getPostTime(); 17018 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17019 } 17020 17021 @Test 17022 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17023 public void rankingTime_newNotification_silent_matchesSbn() throws Exception { 17024 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17025 NotificationRecord nr = generateNotificationRecord(low, mUserId); 17026 17027 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17028 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17029 waitForIdle(); 17030 17031 NotificationRecord posted = mService.mNotificationList.get(0); 17032 long originalPostTime = posted.getSbn().getPostTime(); 17033 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17034 } 17035 17036 @Test 17037 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17038 public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception { 17039 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17040 NotificationRecord nr = generateNotificationRecord(low, mUserId); 17041 17042 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17043 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17044 waitForIdle(); 17045 NotificationRecord posted = mService.mNotificationList.get(0); 17046 long originalPostTime = posted.getSbn().getPostTime(); 17047 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17048 17049 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17050 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17051 waitForIdle(); 17052 assertThat(mService.mNotificationList.get(0).getRankingTimeMs()) 17053 .isEqualTo(originalPostTime); 17054 } 17055 17056 @Test 17057 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17058 public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception { 17059 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17060 NotificationRecord nr = generateNotificationRecord(low, 0, mUserId); 17061 17062 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17063 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17064 waitForIdle(); 17065 NotificationRecord posted = mService.mNotificationList.get(0); 17066 long originalPostTime = posted.getSbn().getPostTime(); 17067 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17068 17069 NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar"); 17070 // no attention helper mocked behavior needed because this does not make noise 17071 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17072 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(), 17073 nrUpdate.getSbn().getUserId()); 17074 waitForIdle(); 17075 17076 posted = mService.mNotificationList.get(0); 17077 assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime); 17078 assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime()); 17079 } 17080 17081 @Test 17082 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17083 public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception { 17084 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17085 NotificationRecord nr = generateNotificationRecord(low, mUserId); 17086 17087 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17088 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17089 waitForIdle(); 17090 NotificationRecord posted = mService.mNotificationList.get(0); 17091 long originalPostTime = posted.getSbn().getPostTime(); 17092 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17093 17094 NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId); 17095 when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() { 17096 public Object answer(InvocationOnMock invocation) { 17097 Object[] args = invocation.getArguments(); 17098 ((NotificationRecord) args[0]).resetRankingTime(); 17099 return 2; // beep 17100 } 17101 }); 17102 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17103 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(), 17104 nrUpdate.getSbn().getUserId()); 17105 waitForIdle(); 17106 posted = mService.mNotificationList.get(0); 17107 assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime); 17108 assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime()); 17109 } 17110 17111 @Test 17112 @EnableFlags(android.app.Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) 17113 public void testRestrictAudioAttributes_listenersGetCorrectAttributes() throws Exception { 17114 NotificationChannel sound = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); 17115 sound.setSound(Uri.EMPTY, new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build()); 17116 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice( 17117 Arrays.asList(sound))); 17118 17119 Notification n = new Notification.Builder(mContext, "a") 17120 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17121 .build(); 17122 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17123 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17124 17125 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 17126 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 17127 waitForIdle(); 17128 17129 ArgumentCaptor<NotificationRecord> captor = 17130 ArgumentCaptor.forClass(NotificationRecord.class); 17131 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17132 captor.capture(), any(), anyBoolean()); 17133 17134 assertThat(captor.getValue().getChannel().getAudioAttributes().getUsage()) 17135 .isEqualTo(USAGE_NOTIFICATION); 17136 } 17137 17138 @Test 17139 @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL) 17140 public void testFixNotification_missingTtl() throws Exception { 17141 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17142 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17143 .build(); 17144 17145 mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 17146 17147 assertThat(n.getTimeoutAfter()).isEqualTo(NOTIFICATION_TTL); 17148 } 17149 17150 @Test 17151 @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL) 17152 public void testFixNotification_doesNotOverwriteTtl() throws Exception { 17153 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17154 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17155 .setTimeoutAfter(20) 17156 .build(); 17157 17158 mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 17159 17160 assertThat(n.getTimeoutAfter()).isEqualTo(20); 17161 } 17162 17163 @Test 17164 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 17165 public void testRejectOldNotification_oldWhen() throws Exception { 17166 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17167 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17168 .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis()) 17169 .build(); 17170 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17171 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17172 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17173 17174 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 17175 .isFalse(); 17176 } 17177 17178 @Test 17179 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 17180 public void testRejectOldNotification_mediumOldWhen() throws Exception { 17181 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17182 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17183 .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis()) 17184 .build(); 17185 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17186 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17187 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17188 17189 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 17190 .isTrue(); 17191 } 17192 17193 @Test 17194 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 17195 public void testRejectOldNotification_zeroWhen() throws Exception { 17196 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17197 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17198 .setWhen(0) 17199 .build(); 17200 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17201 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17202 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17203 17204 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 17205 .isTrue(); 17206 } 17207 17208 @Test 17209 public void testClearUIJFromUninstallingPackage() throws Exception { 17210 NotificationRecord r = 17211 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar"); 17212 mService.addNotification(r); 17213 17214 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())) 17215 .thenThrow(PackageManager.NameNotFoundException.class); 17216 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17217 17218 mInternalService.cancelNotification(mPkg, mPkg, mUid, 0, r.getSbn().getTag(), 17219 r.getSbn().getId(), mUserId); 17220 17221 // no exception 17222 } 17223 17224 @Test 17225 public void testPostFromMissingPackage_throws() throws Exception { 17226 NotificationRecord r = 17227 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar"); 17228 17229 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())) 17230 .thenThrow(PackageManager.NameNotFoundException.class); 17231 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17232 17233 try { 17234 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 17235 r.getSbn().getId(), r.getSbn().getNotification(), 17236 r.getSbn().getUserId()); 17237 fail("Allowed to post a notification for an absent package"); 17238 } catch (SecurityException e) { 17239 // yay 17240 } 17241 } 17242 17243 @Test 17244 public void testGetEffectsSuppressor_noSuppressor() throws Exception { 17245 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17246 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17247 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true); 17248 assertThat(mBinderService.getEffectsSuppressor()).isNull(); 17249 } 17250 17251 @Test 17252 public void testGetEffectsSuppressor_suppressorSameApp() throws Exception { 17253 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17254 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17255 mService.isSystemUid = false; 17256 mService.isSystemAppId = false; 17257 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 17258 HINT_HOST_DISABLE_EFFECTS); 17259 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true); 17260 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); 17261 } 17262 17263 @Test 17264 public void testGetEffectsSuppressor_suppressorDiffApp() throws Exception { 17265 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17266 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17267 mService.isSystemUid = false; 17268 mService.isSystemAppId = false; 17269 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 17270 HINT_HOST_DISABLE_EFFECTS); 17271 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17272 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(null); 17273 } 17274 17275 @Test 17276 public void testGetEffectsSuppressor_suppressorDiffAppSystemCaller() throws Exception { 17277 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17278 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17279 mService.isSystemUid = true; 17280 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 17281 HINT_HOST_DISABLE_EFFECTS); 17282 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17283 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); 17284 } 17285 17286 @Test 17287 @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 17288 public void testApplyAdjustment_keyType_validType() throws Exception { 17289 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 17290 mService.addNotification(r); 17291 NotificationManagerService.WorkerHandler handler = mock( 17292 NotificationManagerService.WorkerHandler.class); 17293 mService.setHandler(handler); 17294 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 17295 when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); 17296 17297 Bundle signals = new Bundle(); 17298 signals.putInt(KEY_TYPE, TYPE_NEWS); 17299 Adjustment adjustment = new Adjustment( 17300 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 17301 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 17302 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17303 17304 waitForIdle(); 17305 17306 r.applyAdjustments(); 17307 17308 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 17309 17310 signals.putInt(KEY_TYPE, TYPE_PROMOTION); 17311 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17312 waitForIdle(); 17313 r.applyAdjustments(); 17314 assertThat(r.getChannel().getId()).isEqualTo(PROMOTIONS_ID); 17315 17316 signals.putInt(KEY_TYPE, TYPE_SOCIAL_MEDIA); 17317 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17318 waitForIdle(); 17319 r.applyAdjustments(); 17320 assertThat(r.getChannel().getId()).isEqualTo(SOCIAL_MEDIA_ID); 17321 17322 signals.putInt(KEY_TYPE, TYPE_CONTENT_RECOMMENDATION); 17323 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17324 waitForIdle(); 17325 r.applyAdjustments(); 17326 assertThat(r.getChannel().getId()).isEqualTo(RECS_ID); 17327 } 17328 17329 @Test 17330 @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION, 17331 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 17332 public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception { 17333 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 17334 mService.addNotification(r); 17335 NotificationManagerService.WorkerHandler handler = mock( 17336 NotificationManagerService.WorkerHandler.class); 17337 mService.setHandler(handler); 17338 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 17339 when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(true); 17340 17341 Bundle signals = new Bundle(); 17342 signals.putInt(KEY_TYPE, TYPE_NEWS); 17343 Adjustment adjustment = new Adjustment( 17344 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 17345 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 17346 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17347 17348 waitForIdle(); 17349 17350 r.applyAdjustments(); 17351 17352 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 17353 17354 // When we block adjustments for this package 17355 when(mAssistants.isTypeAdjustmentAllowedForPackage(anyString())).thenReturn(false); 17356 17357 signals.putInt(KEY_TYPE, TYPE_PROMOTION); 17358 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17359 waitForIdle(); 17360 r.applyAdjustments(); 17361 // Then the adjustment is not applied. 17362 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 17363 } 17364 17365 @Test 17366 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17367 public void testSetCanBePromoted_granted() throws Exception { 17368 // qualifying posted notification 17369 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17370 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17371 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17372 .setColor(Color.WHITE) 17373 .setColorized(true) 17374 .setOngoing(true) 17375 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17376 .build(); 17377 17378 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17379 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17380 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17381 17382 // qualifying enqueued notification 17383 Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17384 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17385 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17386 .setColor(Color.WHITE) 17387 .setColorized(true) 17388 .setOngoing(true) 17389 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17390 .build(); 17391 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0, 17392 n1, UserHandle.getUserHandleForUid(mUid), null, 0); 17393 NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel); 17394 17395 // another package but otherwise would qualify 17396 Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17397 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17398 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17399 .setColor(Color.WHITE) 17400 .setColorized(true) 17401 .setOngoing(true) 17402 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17403 .build(); 17404 StatusBarNotification sbn2 = new StatusBarNotification(PKG_O, PKG_O, 7, null, UID_O, 0, 17405 n2, UserHandle.getUserHandleForUid(UID_O), null, 0); 17406 NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel); 17407 17408 // not-qualifying posted notification 17409 Notification n3 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17410 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17411 .build(); 17412 17413 StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17414 n3, UserHandle.getUserHandleForUid(mUid), null, 0); 17415 NotificationRecord r3 = new NotificationRecord(mContext, sbn3, mTestNotificationChannel); 17416 17417 mService.addNotification(r3); 17418 mService.addNotification(r2); 17419 mService.addNotification(r); 17420 mService.addEnqueuedNotification(r1); 17421 17422 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17423 17424 waitForIdle(); 17425 17426 ArgumentCaptor<NotificationRecord> captor = 17427 ArgumentCaptor.forClass(NotificationRecord.class); 17428 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17429 captor.capture(), any(), anyBoolean()); 17430 17431 // the posted one 17432 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17433 FLAG_PROMOTED_ONGOING)).isTrue(); 17434 // the enqueued one 17435 assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isTrue(); 17436 // the other app 17437 assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17438 // same app, not qualifying 17439 assertThat(mService.hasFlag(r3.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17440 } 17441 17442 @Test 17443 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17444 public void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception { 17445 // qualifying posted notification 17446 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17447 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17448 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17449 .setColor(Color.WHITE) 17450 .setColorized(true) 17451 .setOngoing(true) 17452 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17453 .build(); 17454 17455 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17456 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17457 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17458 17459 mService.addNotification(r); 17460 17461 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17462 waitForIdle(); 17463 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17464 waitForIdle(); 17465 17466 ArgumentCaptor<NotificationRecord> captor = 17467 ArgumentCaptor.forClass(NotificationRecord.class); 17468 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17469 captor.capture(), any(), anyBoolean()); 17470 } 17471 17472 @Test 17473 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17474 public void testSetCanBePromoted_revoked() throws Exception { 17475 // start from true state 17476 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17477 17478 // qualifying posted notification 17479 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17480 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17481 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17482 .setColor(Color.WHITE) 17483 .setColorized(true) 17484 .setOngoing(true) 17485 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post 17486 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17487 .build(); 17488 17489 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17490 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17491 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17492 17493 // qualifying enqueued notification 17494 Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17495 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17496 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17497 .setColor(Color.WHITE) 17498 .setColorized(true) 17499 .setOngoing(true) 17500 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post 17501 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17502 .build(); 17503 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0, 17504 n1, UserHandle.getUserHandleForUid(mUid), null, 0); 17505 NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel); 17506 17507 // doesn't qualify, same package 17508 Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17509 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17510 .build(); 17511 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17512 n2, UserHandle.getUserHandleForUid(UID_O), null, 0); 17513 NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel); 17514 17515 mService.addNotification(r2); 17516 mService.addNotification(r); 17517 mService.addEnqueuedNotification(r1); 17518 17519 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17520 17521 waitForIdle(); 17522 17523 ArgumentCaptor<NotificationRecord> captor = 17524 ArgumentCaptor.forClass(NotificationRecord.class); 17525 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17526 captor.capture(), any(), anyBoolean()); 17527 17528 // the posted one 17529 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17530 FLAG_PROMOTED_ONGOING)).isFalse(); 17531 // the enqueued one 17532 assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17533 // the not qualifying one 17534 assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17535 } 17536 17537 @Test 17538 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17539 public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception { 17540 // start from true state 17541 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17542 17543 // qualifying posted notification 17544 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17545 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17546 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17547 .setColor(Color.WHITE) 17548 .setColorized(true) 17549 .setOngoing(true) 17550 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post 17551 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17552 .build(); 17553 17554 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17555 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17556 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17557 17558 mService.addNotification(r); 17559 17560 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17561 waitForIdle(); 17562 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17563 waitForIdle(); 17564 17565 ArgumentCaptor<NotificationRecord> captor = 17566 ArgumentCaptor.forClass(NotificationRecord.class); 17567 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17568 captor.capture(), any(), anyBoolean()); 17569 } 17570 17571 @Test 17572 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17573 public void testPostPromotableNotification() throws Exception { 17574 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17575 assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isTrue(); 17576 17577 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17578 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17579 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17580 .setColor(Color.WHITE) 17581 .setColorized(true) 17582 .setOngoing(true) 17583 .build(); 17584 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17585 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17586 17587 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 17588 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 17589 waitForIdle(); 17590 17591 ArgumentCaptor<NotificationRecord> captor = 17592 ArgumentCaptor.forClass(NotificationRecord.class); 17593 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17594 captor.capture(), any(), anyBoolean()); 17595 17596 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17597 FLAG_PROMOTED_ONGOING)).isTrue(); 17598 } 17599 17600 @Test 17601 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17602 public void testPostPromotableNotification_noPermission() throws Exception { 17603 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17604 assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isFalse(); 17605 17606 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17607 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17608 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17609 .setColor(Color.WHITE) 17610 .setColorized(true) 17611 .setOngoing(true) 17612 .build(); 17613 17614 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17615 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17616 17617 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 17618 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 17619 waitForIdle(); 17620 17621 ArgumentCaptor<NotificationRecord> captor = 17622 ArgumentCaptor.forClass(NotificationRecord.class); 17623 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17624 captor.capture(), any(), anyBoolean()); 17625 17626 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17627 FLAG_PROMOTED_ONGOING)).isFalse(); 17628 } 17629 17630 @Test 17631 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17632 public void testPostPromotableNotification_unimportantNotification() throws Exception { 17633 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17634 Notification n = new Notification.Builder(mContext, mMinChannel.getId()) 17635 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17636 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17637 .setColor(Color.WHITE) 17638 .setColorized(true) 17639 .setOngoing(true) 17640 .build(); 17641 17642 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17643 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17644 17645 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 17646 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 17647 waitForIdle(); 17648 17649 ArgumentCaptor<NotificationRecord> captor = 17650 ArgumentCaptor.forClass(NotificationRecord.class); 17651 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17652 captor.capture(), any(), anyBoolean()); 17653 17654 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17655 FLAG_PROMOTED_ONGOING)).isFalse(); 17656 } 17657 17658 @Test 17659 @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) 17660 public void testAppCannotUseReservedBundleChannels() throws Exception { 17661 mService.mPreferencesHelper.createReservedChannel(mPkg, mUid, TYPE_NEWS); 17662 NotificationChannel news = mBinderService.getNotificationChannel( 17663 mPkg, mContext.getUserId(), mPkg, NEWS_ID); 17664 assertThat(news).isNotNull(); 17665 17666 NotificationRecord nr = generateNotificationRecord(news); 17667 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 17668 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17669 waitForIdle(); 17670 17671 assertThat(mService.mNotificationList).isEmpty(); 17672 } 17673 } 17674