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_NM_SUMMARIZATION; 28 import static android.app.Flags.FLAG_SORT_SECTION_BY_TIME; 29 import static android.app.Notification.EXTRA_ALLOW_DURING_SETUP; 30 import static android.app.Notification.EXTRA_PICTURE; 31 import static android.app.Notification.EXTRA_PICTURE_ICON; 32 import static android.app.Notification.EXTRA_TEXT; 33 import static android.app.Notification.FLAG_AUTO_CANCEL; 34 import static android.app.Notification.FLAG_BUBBLE; 35 import static android.app.Notification.FLAG_CAN_COLORIZE; 36 import static android.app.Notification.FLAG_FOREGROUND_SERVICE; 37 import static android.app.Notification.FLAG_GROUP_SUMMARY; 38 import static android.app.Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 39 import static android.app.Notification.FLAG_NO_CLEAR; 40 import static android.app.Notification.FLAG_NO_DISMISS; 41 import static android.app.Notification.FLAG_ONGOING_EVENT; 42 import static android.app.Notification.FLAG_ONLY_ALERT_ONCE; 43 import static android.app.Notification.FLAG_PROMOTED_ONGOING; 44 import static android.app.Notification.FLAG_USER_INITIATED_JOB; 45 import static android.app.Notification.GROUP_ALERT_CHILDREN; 46 import static android.app.Notification.VISIBILITY_PRIVATE; 47 import static android.app.NotificationChannel.DEFAULT_CHANNEL_ID; 48 import static android.app.NotificationChannel.NEWS_ID; 49 import static android.app.NotificationChannel.PROMOTIONS_ID; 50 import static android.app.NotificationChannel.RECS_ID; 51 import static android.app.NotificationChannel.SOCIAL_MEDIA_ID; 52 import static android.app.NotificationChannel.USER_LOCKED_ALLOW_BUBBLE; 53 import static android.app.NotificationManager.ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED; 54 import static android.app.NotificationManager.ACTION_EFFECTS_SUPPRESSOR_CHANGED; 55 import static android.app.NotificationManager.ACTION_INTERRUPTION_FILTER_CHANGED; 56 import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ACTIVATED; 57 import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; 58 import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; 59 import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; 60 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_ID; 61 import static android.app.NotificationManager.EXTRA_AUTOMATIC_ZEN_RULE_STATUS; 62 import static android.app.NotificationManager.EXTRA_BLOCKED_STATE; 63 import static android.app.NotificationManager.IMPORTANCE_DEFAULT; 64 import static android.app.NotificationManager.IMPORTANCE_HIGH; 65 import static android.app.NotificationManager.IMPORTANCE_LOW; 66 import static android.app.NotificationManager.IMPORTANCE_MAX; 67 import static android.app.NotificationManager.IMPORTANCE_MIN; 68 import static android.app.NotificationManager.IMPORTANCE_NONE; 69 import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY; 70 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CALLS; 71 import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_CONVERSATIONS; 72 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT; 73 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; 74 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 75 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; 76 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST; 77 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; 78 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF; 79 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON; 80 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR; 81 import static android.app.PendingIntent.FLAG_IMMUTABLE; 82 import static android.app.PendingIntent.FLAG_MUTABLE; 83 import static android.app.PendingIntent.FLAG_ONE_SHOT; 84 import static android.app.StatusBarManager.ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED; 85 import static android.app.StatusBarManager.EXTRA_KM_PRIVATE_NOTIFS_ALLOWED; 86 import static android.app.backup.NotificationLoggingConstants.DATA_TYPE_ZEN_CONFIG; 87 import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; 88 import static android.content.pm.PackageManager.FEATURE_TELECOM; 89 import static android.content.pm.PackageManager.FEATURE_WATCH; 90 import static android.content.pm.PackageManager.PERMISSION_DENIED; 91 import static android.content.pm.PackageManager.PERMISSION_GRANTED; 92 import static android.media.AudioAttributes.USAGE_MEDIA; 93 import static android.media.AudioAttributes.USAGE_NOTIFICATION; 94 import static android.os.Build.VERSION_CODES.O_MR1; 95 import static android.os.Build.VERSION_CODES.P; 96 import static android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE; 97 import static android.os.PowerManager.PARTIAL_WAKE_LOCK; 98 import static android.os.PowerWhitelistManager.REASON_NOTIFICATION_SERVICE; 99 import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED; 100 import static android.os.UserHandle.USER_SYSTEM; 101 import static android.os.UserManager.USER_TYPE_FULL_SECONDARY; 102 import static android.os.UserManager.USER_TYPE_FULL_SYSTEM; 103 import static android.os.UserManager.USER_TYPE_PROFILE_CLONE; 104 import static android.os.UserManager.USER_TYPE_PROFILE_MANAGED; 105 import static android.os.UserManager.USER_TYPE_PROFILE_PRIVATE; 106 import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; 107 import static android.service.notification.Adjustment.KEY_CONTEXTUAL_ACTIONS; 108 import static android.service.notification.Adjustment.KEY_IMPORTANCE; 109 import static android.service.notification.Adjustment.KEY_SUMMARIZATION; 110 import static android.service.notification.Adjustment.KEY_TEXT_REPLIES; 111 import static android.service.notification.Adjustment.KEY_TYPE; 112 import static android.service.notification.Adjustment.KEY_USER_SENTIMENT; 113 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION; 114 import static android.service.notification.Adjustment.TYPE_NEWS; 115 import static android.service.notification.Adjustment.TYPE_PROMOTION; 116 import static android.service.notification.Adjustment.TYPE_SOCIAL_MEDIA; 117 import static android.service.notification.Condition.SOURCE_CONTEXT; 118 import static android.service.notification.Condition.SOURCE_USER_ACTION; 119 import static android.service.notification.Condition.STATE_TRUE; 120 import static android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION; 121 import static android.service.notification.Flags.FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT; 122 import static android.service.notification.Flags.FLAG_NOTIFICATION_FORCE_GROUPING; 123 import static android.service.notification.Flags.FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION; 124 import static android.service.notification.Flags.FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS; 125 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ALERTING; 126 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_CONVERSATIONS; 127 import static android.service.notification.NotificationListenerService.FLAG_FILTER_TYPE_ONGOING; 128 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_CALL_EFFECTS; 129 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_EFFECTS; 130 import static android.service.notification.NotificationListenerService.HINT_HOST_DISABLE_NOTIFICATION_EFFECTS; 131 import static android.service.notification.NotificationListenerService.REASON_APP_CANCEL; 132 import static android.service.notification.NotificationListenerService.REASON_CANCEL; 133 import static android.service.notification.NotificationListenerService.REASON_LOCKDOWN; 134 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE; 135 import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL; 136 import static android.view.Display.DEFAULT_DISPLAY; 137 import static android.view.Display.INVALID_DISPLAY; 138 import static android.view.WindowManager.LayoutParams.TYPE_TOAST; 139 140 import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN; 141 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER; 142 import static com.android.server.am.PendingIntentRecord.FLAG_BROADCAST_SENDER; 143 import static com.android.server.am.PendingIntentRecord.FLAG_SERVICE_SENDER; 144 import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL; 145 import static com.android.server.notification.Flags.FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER; 146 import static com.android.server.notification.Flags.FLAG_REJECT_OLD_NOTIFICATIONS; 147 import static com.android.server.notification.GroupHelper.AUTOGROUP_KEY; 148 import static com.android.server.notification.NotificationManagerService.BITMAP_DURATION; 149 import static com.android.server.notification.NotificationManagerService.DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE; 150 import static com.android.server.notification.NotificationManagerService.NOTIFICATION_TTL; 151 import static com.android.server.notification.NotificationManagerService.TAG; 152 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_ADJUSTED; 153 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_POSTED; 154 import static com.android.server.notification.NotificationRecordLogger.NotificationReportedEvent.NOTIFICATION_UPDATED; 155 156 import static com.google.common.collect.Iterables.getOnlyElement; 157 import static com.google.common.truth.Truth.assertThat; 158 import static com.google.common.truth.Truth.assertWithMessage; 159 160 import static junit.framework.Assert.assertEquals; 161 import static junit.framework.Assert.assertFalse; 162 import static junit.framework.Assert.assertNotNull; 163 import static junit.framework.Assert.assertNotSame; 164 import static junit.framework.Assert.assertNull; 165 import static junit.framework.Assert.assertSame; 166 import static junit.framework.Assert.assertTrue; 167 import static junit.framework.Assert.fail; 168 169 import static org.junit.Assert.assertNotEquals; 170 import static org.junit.Assert.assertThrows; 171 import static org.mockito.ArgumentMatchers.argThat; 172 import static org.mockito.ArgumentMatchers.isNull; 173 import static org.mockito.ArgumentMatchers.anyBoolean; 174 import static org.mockito.ArgumentMatchers.anyLong; 175 import static org.mockito.ArgumentMatchers.anyString; 176 import static org.mockito.ArgumentMatchers.eq; 177 import static org.mockito.Mockito.any; 178 import static org.mockito.Mockito.anyInt; 179 import static org.mockito.Mockito.atLeastOnce; 180 import static org.mockito.Mockito.clearInvocations; 181 import static org.mockito.Mockito.doAnswer; 182 import static org.mockito.Mockito.doNothing; 183 import static org.mockito.Mockito.doReturn; 184 import static org.mockito.Mockito.doThrow; 185 import static org.mockito.Mockito.inOrder; 186 import static org.mockito.Mockito.mock; 187 import static org.mockito.Mockito.never; 188 import static org.mockito.Mockito.reset; 189 import static org.mockito.Mockito.spy; 190 import static org.mockito.Mockito.timeout; 191 import static org.mockito.Mockito.times; 192 import static org.mockito.Mockito.verify; 193 import static org.mockito.Mockito.verifyNoMoreInteractions; 194 import static org.mockito.Mockito.when; 195 196 import static java.util.Collections.emptyList; 197 import static java.util.Collections.singletonList; 198 199 import android.Manifest; 200 import android.annotation.Nullable; 201 import android.annotation.SuppressLint; 202 import android.annotation.UserIdInt; 203 import android.app.ActivityManager; 204 import android.app.ActivityManagerInternal; 205 import android.app.AlarmManager; 206 import android.app.AppOpsManager; 207 import android.app.AutomaticZenRule; 208 import android.app.IActivityManager; 209 import android.app.ICallNotificationEventCallback; 210 import android.app.INotificationManager; 211 import android.app.ITransientNotification; 212 import android.app.IUriGrantsManager; 213 import android.app.Notification; 214 import android.app.Notification.MessagingStyle.Message; 215 import android.app.NotificationChannel; 216 import android.app.NotificationChannelGroup; 217 import android.app.NotificationManager; 218 import android.app.NotificationManager.Policy; 219 import android.app.PendingIntent; 220 import android.app.Person; 221 import android.app.RemoteInput; 222 import android.app.RemoteInputHistoryItem; 223 import android.app.StatsManager; 224 import android.app.ZenBypassingApp; 225 import android.app.admin.DevicePolicyManagerInternal; 226 import android.app.backup.BackupRestoreEventLogger; 227 import android.app.job.JobScheduler; 228 import android.app.role.RoleManager; 229 import android.app.usage.UsageStatsManagerInternal; 230 import android.companion.AssociationInfo; 231 import android.companion.AssociationRequest; 232 import android.companion.ICompanionDeviceManager; 233 import android.compat.testing.PlatformCompatChangeRule; 234 import android.content.BroadcastReceiver; 235 import android.content.ComponentName; 236 import android.content.ContentUris; 237 import android.content.Context; 238 import android.content.IIntentSender; 239 import android.content.Intent; 240 import android.content.IntentFilter; 241 import android.content.pm.ActivityInfo; 242 import android.content.pm.ApplicationInfo; 243 import android.content.pm.IPackageManager; 244 import android.content.pm.LauncherApps; 245 import android.content.pm.ModuleInfo; 246 import android.content.pm.PackageManager; 247 import android.content.pm.PackageManagerInternal; 248 import android.content.pm.ParceledListSlice; 249 import android.content.pm.ResolveInfo; 250 import android.content.pm.ShortcutInfo; 251 import android.content.pm.ShortcutServiceInternal; 252 import android.content.pm.UserInfo; 253 import android.content.pm.VersionedPackage; 254 import android.content.res.Resources; 255 import android.graphics.Bitmap; 256 import android.graphics.Color; 257 import android.graphics.drawable.Icon; 258 import android.media.AudioAttributes; 259 import android.media.AudioManager; 260 import android.media.session.MediaSession; 261 import android.net.Uri; 262 import android.os.Binder; 263 import android.os.Build; 264 import android.os.Bundle; 265 import android.os.Handler; 266 import android.os.IBinder; 267 import android.os.Looper; 268 import android.os.Parcel; 269 import android.os.Parcelable; 270 import android.os.PowerManager; 271 import android.os.PowerManager.WakeLock; 272 import android.os.Process; 273 import android.os.RemoteException; 274 import android.os.SystemClock; 275 import android.os.UserHandle; 276 import android.os.UserManager; 277 import android.os.WorkSource; 278 import android.permission.PermissionManager; 279 import android.platform.test.annotations.DisableFlags; 280 import android.platform.test.annotations.EnableFlags; 281 import android.platform.test.annotations.RequiresFlagsEnabled; 282 import android.platform.test.flag.junit.FlagsParameterization; 283 import android.platform.test.flag.junit.SetFlagsRule; 284 import android.platform.test.rule.LimitDevicesRule; 285 import android.provider.MediaStore; 286 import android.provider.Settings; 287 import android.service.notification.Adjustment; 288 import android.service.notification.Condition; 289 import android.service.notification.ConversationChannelWrapper; 290 import android.service.notification.DeviceEffectsApplier; 291 import android.service.notification.INotificationListener; 292 import android.service.notification.NotificationListenerFilter; 293 import android.service.notification.NotificationListenerService; 294 import android.service.notification.NotificationRankingUpdate; 295 import android.service.notification.NotificationStats; 296 import android.service.notification.StatusBarNotification; 297 import android.service.notification.ZenModeConfig; 298 import android.service.notification.ZenPolicy; 299 import android.telecom.TelecomManager; 300 import android.testing.TestWithLooperRule; 301 import android.testing.TestableContentResolver; 302 import android.testing.TestableLooper; 303 import android.testing.TestableLooper.RunWithLooper; 304 import android.testing.TestablePermissions; 305 import android.testing.TestableResources; 306 import android.text.Html; 307 import android.text.TextUtils; 308 import android.util.ArrayMap; 309 import android.util.ArraySet; 310 import android.util.AtomicFile; 311 import android.util.Log; 312 import android.util.Pair; 313 import android.util.Xml; 314 import android.view.accessibility.AccessibilityManager; 315 import android.widget.RemoteViews; 316 317 import androidx.test.InstrumentationRegistry; 318 import androidx.test.filters.SmallTest; 319 320 import com.android.internal.R; 321 import com.android.internal.config.sysui.TestableFlagResolver; 322 import com.android.internal.logging.InstanceId; 323 import com.android.internal.logging.InstanceIdSequence; 324 import com.android.internal.logging.InstanceIdSequenceFake; 325 import com.android.internal.messages.nano.SystemMessageProto; 326 import com.android.internal.statusbar.NotificationVisibility; 327 import com.android.internal.widget.LockPatternUtils; 328 import com.android.modules.utils.TypedXmlPullParser; 329 import com.android.modules.utils.TypedXmlSerializer; 330 import com.android.server.DeviceIdleInternal; 331 import com.android.server.LocalServices; 332 import com.android.server.SystemService; 333 import com.android.server.SystemService.TargetUser; 334 import com.android.server.UiServiceTestCase; 335 import com.android.server.job.JobSchedulerInternal; 336 import com.android.server.lights.LightsManager; 337 import com.android.server.lights.LogicalLight; 338 import com.android.server.notification.GroupHelper.NotificationAttributes; 339 import com.android.server.notification.NotificationManagerService.NotificationAssistants; 340 import com.android.server.notification.NotificationManagerService.NotificationListeners; 341 import com.android.server.notification.NotificationManagerService.PostNotificationTracker; 342 import com.android.server.notification.NotificationManagerService.PostNotificationTrackerFactory; 343 import com.android.server.pm.PackageManagerService; 344 import com.android.server.pm.UserManagerInternal; 345 import com.android.server.policy.PermissionPolicyInternal; 346 import com.android.server.statusbar.StatusBarManagerInternal; 347 import com.android.server.uri.UriGrantsManagerInternal; 348 import com.android.server.utils.quota.MultiRateLimiter; 349 import com.android.server.wm.ActivityTaskManagerInternal; 350 import com.android.server.wm.WindowManagerInternal; 351 352 import com.google.android.collect.Lists; 353 import com.google.common.collect.ImmutableList; 354 import com.google.common.collect.Iterables; 355 356 import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges; 357 import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges; 358 359 import org.junit.After; 360 import org.junit.Assert; 361 import org.junit.Before; 362 import org.junit.ClassRule; 363 import org.junit.Rule; 364 import org.junit.Test; 365 import org.junit.rules.TestRule; 366 import org.junit.runner.RunWith; 367 import org.mockito.ArgumentCaptor; 368 import org.mockito.ArgumentMatcher; 369 import org.mockito.InOrder; 370 import org.mockito.Mock; 371 import org.mockito.Mockito; 372 import org.mockito.MockitoAnnotations; 373 import org.mockito.invocation.InvocationOnMock; 374 import org.mockito.stubbing.Answer; 375 376 import platform.test.runner.parameterized.ParameterizedAndroidJunit4; 377 import platform.test.runner.parameterized.Parameters; 378 379 import java.io.BufferedInputStream; 380 import java.io.BufferedOutputStream; 381 import java.io.ByteArrayInputStream; 382 import java.io.ByteArrayOutputStream; 383 import java.io.File; 384 import java.io.FileOutputStream; 385 import java.time.Duration; 386 import java.util.ArrayList; 387 import java.util.Arrays; 388 import java.util.HashSet; 389 import java.util.List; 390 import java.util.Map; 391 import java.util.concurrent.CountDownLatch; 392 import java.util.function.Consumer; 393 394 @SmallTest 395 @RunWith(ParameterizedAndroidJunit4.class) 396 @RunWithLooper 397 @SuppressLint("GuardedBy") // It's ok for this test to access guarded methods from the service. 398 public class NotificationManagerServiceTest extends UiServiceTestCase { 399 private static final String TEST_CHANNEL_ID = "NotificationManagerServiceTestChannelId"; 400 private static final String TEST_PACKAGE = "The.name.is.Package.Test.Package"; 401 private static final String PKG_NO_CHANNELS = "com.example.no.channels"; 402 private static final int TEST_TASK_ID = 1; 403 private static final int UID_HEADLESS = 1_000_000; 404 private static final int TOAST_DURATION = 2_000; 405 private static final int SECONDARY_DISPLAY_ID = 42; 406 private static final int TEST_PROFILE_USERHANDLE = 12; 407 private static final long DELAY_FORCE_REGROUP_TIME = 3000; 408 409 private static final String ACTION_NOTIFICATION_TIMEOUT = 410 NotificationManagerService.class.getSimpleName() + ".TIMEOUT"; 411 private static final String EXTRA_KEY = "key"; 412 private static final String SCHEME_TIMEOUT = "timeout"; 413 private static final String REDACTED_TEXT = "redacted text"; 414 415 private static final AutomaticZenRule SOME_ZEN_RULE = 416 new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 417 .setOwner(new ComponentName("pkg", "cls")) 418 .build(); 419 420 @ClassRule 421 public static final LimitDevicesRule sLimitDevicesRule = new LimitDevicesRule(); 422 423 @Rule 424 public TestRule compatChangeRule = new PlatformCompatChangeRule(); 425 426 private TestableNotificationManagerService mService; 427 private INotificationManager mBinderService; 428 private NotificationManagerInternal mInternalService; 429 private ShortcutHelper mShortcutHelper; 430 @Mock 431 private IPackageManager mPackageManager; 432 @Mock 433 private PackageManager mPackageManagerClient; 434 @Mock 435 private PackageManagerInternal mPackageManagerInternal; 436 @Mock 437 private PermissionPolicyInternal mPermissionPolicyInternal; 438 @Mock 439 private WindowManagerInternal mWindowManagerInternal; 440 @Mock 441 private PermissionHelper mPermissionHelper; 442 private NotificationChannelLoggerFake mLogger = new NotificationChannelLoggerFake(); 443 @Rule(order = Integer.MAX_VALUE) 444 public TestWithLooperRule mlooperRule = new TestWithLooperRule(); 445 private TestableLooper mTestableLooper; 446 @Mock 447 private RankingHelper mRankingHelper; 448 @Mock private PreferencesHelper mPreferencesHelper; 449 AtomicFile mPolicyFile; 450 File mFile; 451 @Mock 452 private NotificationUsageStats mUsageStats; 453 @Mock 454 private UsageStatsManagerInternal mAppUsageStats; 455 @Mock 456 private AudioManager mAudioManager; 457 @Mock 458 private LauncherApps mLauncherApps; 459 @Mock 460 private ShortcutServiceInternal mShortcutServiceInternal; 461 @Mock 462 private UserManager mUserManager; 463 @Mock 464 ActivityManager mActivityManager; 465 @Mock 466 TelecomManager mTelecomManager; 467 @Mock 468 Resources mResources; 469 @Mock 470 RankingHandler mRankingHandler; 471 @Mock 472 ActivityManagerInternal mAmi; 473 @Mock 474 JobSchedulerInternal mJsi; 475 @Mock 476 private Looper mMainLooper; 477 @Mock 478 private NotificationManager mMockNm; 479 @Mock 480 private PermissionManager mPermissionManager; 481 @Mock 482 private DevicePolicyManagerInternal mDevicePolicyManager; 483 @Mock 484 private PowerManager mPowerManager; 485 @Mock 486 private LightsManager mLightsManager; 487 private final ArrayList<WakeLock> mAcquiredWakeLocks = new ArrayList<>(); 488 private final TestPostNotificationTrackerFactory mPostNotificationTrackerFactory = 489 new TestPostNotificationTrackerFactory(); 490 491 private PendingIntent mActivityIntent; 492 private PendingIntent mActivityIntentImmutable; 493 494 private static final int MAX_POST_DELAY = 1000; 495 496 private NotificationChannel mTestNotificationChannel = new NotificationChannel( 497 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 498 499 NotificationChannel mSilentChannel = new NotificationChannel("low", "low", IMPORTANCE_LOW); 500 501 NotificationChannel mMinChannel = new NotificationChannel("min", "min", IMPORTANCE_MIN); 502 503 private final NotificationChannel mParentChannel = 504 new NotificationChannel(PARENT_CHANNEL_ID, "parentName", IMPORTANCE_DEFAULT); 505 private final NotificationChannel mConversationChannel = 506 new NotificationChannel( 507 CONVERSATION_CHANNEL_ID, "conversationName", IMPORTANCE_DEFAULT); 508 509 private static final String PARENT_CHANNEL_ID = "parentChannelId"; 510 private static final String CONVERSATION_CHANNEL_ID = "conversationChannelId"; 511 private static final String CONVERSATION_ID = "conversationId"; 512 513 private static final int NOTIFICATION_LOCATION_UNKNOWN = 0; 514 515 private static final String VALID_CONVO_SHORTCUT_ID = "shortcut"; 516 private static final String SEARCH_SELECTOR_PKG = "searchSelector"; 517 private static final String ADSERVICES_MODULE_PKG = "com.android.adservices"; 518 private static final String ADSERVICES_APK_PKG = "com.android.adservices.api"; 519 520 @Mock 521 private NotificationListeners mListeners; 522 @Mock 523 private NotificationListenerFilter mNlf; 524 @Mock private NotificationAssistants mAssistants; 525 @Mock private ConditionProviders mConditionProviders; 526 private ManagedServices.ManagedServiceInfo mListener; 527 @Mock private ICompanionDeviceManager mCompanionMgr; 528 @Mock SnoozeHelper mSnoozeHelper; 529 @Mock GroupHelper mGroupHelper; 530 @Mock 531 IBinder mPermOwner; 532 @Mock 533 IActivityManager mAm; 534 @Mock 535 ActivityTaskManagerInternal mAtm; 536 @Mock 537 IUriGrantsManager mUgm; 538 @Mock 539 UriGrantsManagerInternal mUgmInternal; 540 @Mock 541 AppOpsManager mAppOpsManager; 542 private AppOpsManager.OnOpChangedListener mOnPermissionChangeListener; 543 @Mock 544 private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback 545 mNotificationAssistantAccessGrantedCallback; 546 @Mock 547 UserManager mUm; 548 @Mock 549 UserManagerInternal mUmInternal; 550 @Mock 551 NotificationHistoryManager mHistoryManager; 552 @Mock 553 StatsManager mStatsManager; 554 @Mock 555 AlarmManager mAlarmManager; 556 @Mock JobScheduler mJobScheduler; 557 @Mock 558 MultiRateLimiter mToastRateLimiter; 559 BroadcastReceiver mPackageIntentReceiver; 560 BroadcastReceiver mUserIntentReceiver; 561 BroadcastReceiver mNotificationTimeoutReceiver; 562 NotificationRecordLoggerFake mNotificationRecordLogger = new NotificationRecordLoggerFake(); 563 TestableNotificationManagerService.StrongAuthTrackerFake mStrongAuthTracker; 564 565 TestableFlagResolver mTestFlagResolver = new TestableFlagResolver(); 566 @Rule 567 public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); 568 private InstanceIdSequence mNotificationInstanceIdSequence = new InstanceIdSequenceFake( 569 1 << 30); 570 @Mock 571 StatusBarManagerInternal mStatusBar; 572 573 @Mock 574 NotificationAttentionHelper mAttentionHelper; 575 576 private NotificationManagerService.WorkerHandler mWorkerHandler; 577 private Handler mBroadcastsHandler; 578 579 private class TestableToastCallback extends ITransientNotification.Stub { 580 @Override show(IBinder windowToken)581 public void show(IBinder windowToken) { 582 } 583 584 @Override hide()585 public void hide() { 586 } 587 } 588 589 private class TestPostNotificationTrackerFactory implements PostNotificationTrackerFactory { 590 591 private final List<PostNotificationTracker> mCreatedTrackers = new ArrayList<>(); 592 593 @Override newTracker(@ullable WakeLock optionalWakeLock)594 public PostNotificationTracker newTracker(@Nullable WakeLock optionalWakeLock) { 595 PostNotificationTracker tracker = PostNotificationTrackerFactory.super.newTracker( 596 optionalWakeLock); 597 mCreatedTrackers.add(tracker); 598 return tracker; 599 } 600 } 601 602 @Parameters(name = "{0}") getParams()603 public static List<FlagsParameterization> getParams() { 604 return FlagsParameterization.allCombinationsOf(); 605 } 606 NotificationManagerServiceTest(FlagsParameterization flags)607 public NotificationManagerServiceTest(FlagsParameterization flags) { 608 mSetFlagsRule.setFlagsParameterization(flags); 609 } 610 611 @Before setUp()612 public void setUp() throws Exception { 613 // Shell permisssions will override permissions of our app, so add all necessary permissions 614 // for this test here: 615 InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity( 616 "android.permission.WRITE_ALLOWLISTED_DEVICE_CONFIG", 617 "android.permission.READ_DEVICE_CONFIG", 618 "android.permission.READ_CONTACTS"); 619 620 MockitoAnnotations.initMocks(this); 621 622 DeviceIdleInternal deviceIdleInternal = mock(DeviceIdleInternal.class); 623 when(deviceIdleInternal.getNotificationAllowlistDuration()).thenReturn(3000L); 624 625 LocalServices.removeServiceForTest(UserManagerInternal.class); 626 LocalServices.addService(UserManagerInternal.class, mUmInternal); 627 LocalServices.removeServiceForTest(UriGrantsManagerInternal.class); 628 LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal); 629 LocalServices.removeServiceForTest(WindowManagerInternal.class); 630 LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal); 631 LocalServices.removeServiceForTest(StatusBarManagerInternal.class); 632 LocalServices.addService(StatusBarManagerInternal.class, mStatusBar); 633 LocalServices.removeServiceForTest(DeviceIdleInternal.class); 634 LocalServices.addService(DeviceIdleInternal.class, deviceIdleInternal); 635 LocalServices.removeServiceForTest(ActivityManagerInternal.class); 636 LocalServices.addService(ActivityManagerInternal.class, mAmi); 637 LocalServices.removeServiceForTest(JobSchedulerInternal.class); 638 LocalServices.addService(JobSchedulerInternal.class, mJsi); 639 LocalServices.removeServiceForTest(PackageManagerInternal.class); 640 LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal); 641 LocalServices.removeServiceForTest(PermissionPolicyInternal.class); 642 LocalServices.addService(PermissionPolicyInternal.class, mPermissionPolicyInternal); 643 LocalServices.removeServiceForTest(ShortcutServiceInternal.class); 644 LocalServices.addService(ShortcutServiceInternal.class, mShortcutServiceInternal); 645 mContext.addMockSystemService(Context.ALARM_SERVICE, mAlarmManager); 646 mContext.addMockSystemService(NotificationManager.class, mMockNm); 647 mContext.addMockSystemService(RoleManager.class, mock(RoleManager.class)); 648 mContext.addMockSystemService(Context.LAUNCHER_APPS_SERVICE, mLauncherApps); 649 mContext.addMockSystemService(Context.USER_SERVICE, mUm); 650 mContext.addMockSystemService(Context.ACCESSIBILITY_SERVICE, 651 mock(AccessibilityManager.class)); 652 653 doNothing().when(mContext).sendBroadcast(any(), anyString()); 654 doNothing().when(mContext).sendBroadcastAsUser(any(), any()); 655 doNothing().when(mContext).sendBroadcastAsUser(any(), any(), any()); 656 doNothing().when(mContext).sendBroadcastMultiplePermissions(any(), any(), any(), any()); 657 doReturn(mContext).when(mContext).createContextAsUser(eq(mUser), anyInt()); 658 659 TestableContentResolver cr = mock(TestableContentResolver.class); 660 when(mContext.getContentResolver()).thenReturn(cr); 661 doNothing().when(cr).registerContentObserver(any(), anyBoolean(), any(), anyInt()); 662 663 when(mAppOpsManager.checkOpNoThrow( 664 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 665 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED); 666 667 // Use this testable looper. 668 mTestableLooper = TestableLooper.get(this); 669 // MockPackageManager - default returns ApplicationInfo with matching calling UID 670 mContext.setMockPackageManager(mPackageManagerClient); 671 672 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())) 673 .thenAnswer((Answer<ApplicationInfo>) invocation -> { 674 Object[] args = invocation.getArguments(); 675 return getApplicationInfo((String) args[0], mUid); 676 }); 677 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 678 .thenAnswer((Answer<ApplicationInfo>) invocation -> { 679 Object[] args = invocation.getArguments(); 680 return getApplicationInfo((String) args[0], mUid); 681 }); 682 when(mPackageManagerClient.getPackageUidAsUser(any(), anyInt())).thenReturn(mUid); 683 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenAnswer( 684 (Answer<Boolean>) invocation -> { 685 // TODO: b/317957802 - This is overly broad and basically makes ANY 686 // isSameApp() check pass, requiring Mockito.reset() for meaningful 687 // tests! Make it more precise. 688 Object[] args = invocation.getArguments(); 689 return (int) args[1] == mUid; 690 }); 691 when(mLightsManager.getLight(anyInt())).thenReturn(mock(LogicalLight.class)); 692 when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); 693 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(false); 694 when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner); 695 when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{mPkg}); 696 when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{mPkg}); 697 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())) 698 .thenReturn(INVALID_TASK_ID); 699 mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class)); 700 when(mUm.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId}); 701 when(mUmInternal.getProfileIds(eq(mUserId), anyBoolean())).thenReturn(new int[]{mUserId}); 702 when(mAmi.getCurrentUserId()).thenReturn(mUserId); 703 704 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(true); 705 706 ActivityManager.AppTask task = mock(ActivityManager.AppTask.class); 707 List<ActivityManager.AppTask> taskList = new ArrayList<>(); 708 ActivityManager.RecentTaskInfo taskInfo = new ActivityManager.RecentTaskInfo(); 709 taskInfo.taskId = TEST_TASK_ID; 710 when(task.getTaskInfo()).thenReturn(taskInfo); 711 taskList.add(task); 712 when(mAtm.getAppTasks(anyString(), anyInt())).thenReturn(taskList); 713 714 // write to a test file; the system file isn't readable from tests 715 mFile = new File(mContext.getCacheDir(), "test.xml"); 716 mFile.createNewFile(); 717 final String preupgradeXml = "<notification-policy></notification-policy>"; 718 mPolicyFile = new AtomicFile(mFile); 719 FileOutputStream fos = mPolicyFile.startWrite(); 720 fos.write(preupgradeXml.getBytes()); 721 mPolicyFile.finishWrite(fos); 722 723 // Setup managed services 724 when(mNlf.isTypeAllowed(anyInt())).thenReturn(true); 725 when(mNlf.isPackageAllowed(any())).thenReturn(true); 726 when(mNlf.isPackageAllowed(null)).thenReturn(true); 727 when(mListeners.getNotificationListenerFilter(any())).thenReturn(mNlf); 728 mListener = mListeners.new ManagedServiceInfo( 729 null, new ComponentName(mPkg, "test_class"), 730 mUserId, true, null, 0, 123); 731 ComponentName defaultComponent = ComponentName.unflattenFromString("config/device"); 732 ArraySet<ComponentName> components = new ArraySet<>(); 733 components.add(defaultComponent); 734 when(mListeners.getDefaultComponents()).thenReturn(components); 735 when(mConditionProviders.getDefaultPackages()) 736 .thenReturn(new ArraySet<>(Arrays.asList("config"))); 737 when(mAssistants.getDefaultComponents()).thenReturn(components); 738 when(mAssistants.queryPackageForServices( 739 anyString(), anyInt(), anyInt())).thenReturn(components); 740 when(mListeners.checkServiceTokenLocked(null)).thenReturn(mListener); 741 ManagedServices.Config listenerConfig = new ManagedServices.Config(); 742 listenerConfig.xmlTag = NotificationListeners.TAG_ENABLED_NOTIFICATION_LISTENERS; 743 when(mListeners.getConfig()).thenReturn(listenerConfig); 744 ManagedServices.Config assistantConfig = new ManagedServices.Config(); 745 assistantConfig.xmlTag = NotificationAssistants.TAG_ENABLED_NOTIFICATION_ASSISTANTS; 746 when(mAssistants.getConfig()).thenReturn(assistantConfig); 747 ManagedServices.Config dndConfig = new ManagedServices.Config(); 748 dndConfig.xmlTag = ConditionProviders.TAG_ENABLED_DND_APPS; 749 when(mConditionProviders.getConfig()).thenReturn(dndConfig); 750 751 when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true); 752 753 // Use the real PowerManager to back up the mock w.r.t. creating WakeLocks. 754 // This is because 1) we need a mock to verify() calls and tracking the created WakeLocks, 755 // but 2) PowerManager and WakeLock perform their own checks (e.g. correct arguments, don't 756 // call release twice, etc) and we want the test to fail if such misuse happens, too. 757 PowerManager realPowerManager = mContext.getSystemService(PowerManager.class); 758 when(mPowerManager.newWakeLock(anyInt(), anyString())).then( 759 (Answer<WakeLock>) invocation -> { 760 WakeLock wl = realPowerManager.newWakeLock(invocation.getArgument(0), 761 invocation.getArgument(1)); 762 mAcquiredWakeLocks.add(wl); 763 return wl; 764 }); 765 766 // TODO (b/291907312): remove feature flag 767 // NOTE: Prefer using the @EnableFlags annotation where possible. Do not add any android.app 768 // flags here. 769 mSetFlagsRule.disableFlags( 770 Flags.FLAG_POLITE_NOTIFICATIONS, Flags.FLAG_AUTOGROUP_SUMMARY_ICON_UPDATE); 771 772 mActivityIntent = spy(PendingIntent.getActivity(mContext, 0, 773 new Intent().setPackage(mPkg), PendingIntent.FLAG_MUTABLE)); 774 mActivityIntentImmutable = spy(PendingIntent.getActivity(mContext, 0, 775 new Intent().setPackage(mPkg), FLAG_IMMUTABLE)); 776 777 initNMS(); 778 } 779 initNMS()780 private void initNMS() throws Exception { 781 initNMS(SystemService.PHASE_BOOT_COMPLETED); 782 } 783 initNMS(int upToBootPhase)784 private void initNMS(int upToBootPhase) throws Exception { 785 mService = new TestableNotificationManagerService(mContext, mNotificationRecordLogger, 786 mNotificationInstanceIdSequence); 787 788 // apps allowed as convos 789 mService.setStringArrayResourceValue(PKG_O); 790 791 TestableResources tr = mContext.getOrCreateTestableResources(); 792 tr.addOverride(com.android.internal.R.string.config_defaultSearchSelectorPackageName, 793 SEARCH_SELECTOR_PKG); 794 tr.addOverride(R.array.config_notificationDefaultUnsupportedAdjustments, 795 new String[] {KEY_TYPE}); 796 797 doAnswer(invocation -> { 798 mOnPermissionChangeListener = invocation.getArgument(2); 799 return null; 800 }).when(mAppOpsManager).startWatchingMode(eq(AppOpsManager.OP_POST_NOTIFICATION), any(), 801 any()); 802 when(mUmInternal.isUserInitialized(anyInt())).thenReturn(true); 803 804 mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper())); 805 mBroadcastsHandler = new Handler(mTestableLooper.getLooper()); 806 807 mService.init(mWorkerHandler, mRankingHandler, mBroadcastsHandler, mPackageManager, 808 mPackageManagerClient, mLightsManager, mListeners, mAssistants, mConditionProviders, 809 mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, 810 mGroupHelper, mAm, mAtm, mAppUsageStats, mDevicePolicyManager, mUgm, mUgmInternal, 811 mAppOpsManager, mUm, mHistoryManager, mStatsManager, mAmi, mToastRateLimiter, 812 mPermissionHelper, mock(UsageStatsManagerInternal.class), mTelecomManager, mLogger, 813 mTestFlagResolver, mPermissionManager, mPowerManager, 814 mPostNotificationTrackerFactory); 815 816 mService.setAttentionHelper(mAttentionHelper); 817 mService.setLockPatternUtils(mock(LockPatternUtils.class)); 818 819 // make sure PreferencesHelper doesn't try to interact with any real caches 820 PreferencesHelper prefHelper = spy(mService.mPreferencesHelper); 821 doNothing().when(prefHelper).invalidateNotificationChannelCache(); 822 doNothing().when(prefHelper).invalidateNotificationChannelGroupCache(); 823 mService.setPreferencesHelper(prefHelper); 824 825 // Return first true for RoleObserver main-thread check 826 when(mMainLooper.isCurrentThread()).thenReturn(true).thenReturn(false); 827 ModuleInfo moduleInfo = new ModuleInfo(); 828 moduleInfo.setApexModuleName(ADSERVICES_MODULE_PKG); 829 moduleInfo.setApkInApexPackageNames(List.of(ADSERVICES_APK_PKG)); 830 when(mPackageManagerClient.getInstalledModules(anyInt())) 831 .thenReturn(List.of(moduleInfo)); 832 if (upToBootPhase >= SystemService.PHASE_SYSTEM_SERVICES_READY) { 833 mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY, mMainLooper); 834 } 835 836 Mockito.reset(mHistoryManager); 837 verify(mHistoryManager, never()).onBootPhaseAppsCanStart(); 838 839 if (upToBootPhase >= SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) { 840 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 841 verify(mHistoryManager).onBootPhaseAppsCanStart(); 842 } 843 844 mStrongAuthTracker = mService.new StrongAuthTrackerFake(mContext); 845 mService.setStrongAuthTracker(mStrongAuthTracker); 846 847 mShortcutHelper = mService.getShortcutHelper(); 848 mShortcutHelper.setLauncherApps(mLauncherApps); 849 mShortcutHelper.setShortcutServiceInternal(mShortcutServiceInternal); 850 mShortcutHelper.setUserManager(mUserManager); 851 852 // Capture PackageIntentReceiver 853 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = 854 ArgumentCaptor.forClass(BroadcastReceiver.class); 855 ArgumentCaptor<IntentFilter> intentFilterCaptor = 856 ArgumentCaptor.forClass(IntentFilter.class); 857 858 verify(mContext, atLeastOnce()).registerReceiverAsUser(broadcastReceiverCaptor.capture(), 859 any(), intentFilterCaptor.capture(), any(), any()); 860 verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(), 861 intentFilterCaptor.capture(), anyInt()); 862 verify(mContext, atLeastOnce()).registerReceiver(broadcastReceiverCaptor.capture(), 863 intentFilterCaptor.capture()); 864 List<BroadcastReceiver> broadcastReceivers = broadcastReceiverCaptor.getAllValues(); 865 List<IntentFilter> intentFilters = intentFilterCaptor.getAllValues(); 866 867 for (int i = 0; i < intentFilters.size(); i++) { 868 final IntentFilter filter = intentFilters.get(i); 869 if (filter.hasAction(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED) 870 && filter.hasAction(Intent.ACTION_PACKAGES_UNSUSPENDED) 871 && filter.hasAction(Intent.ACTION_PACKAGES_SUSPENDED)) { 872 mPackageIntentReceiver = broadcastReceivers.get(i); 873 } 874 if (filter.hasAction(Intent.ACTION_USER_STOPPED) 875 || filter.hasAction(Intent.ACTION_USER_SWITCHED) 876 || filter.hasAction(Intent.ACTION_PROFILE_UNAVAILABLE) 877 || filter.hasAction(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE)) { 878 // There may be multiple receivers, get the NMS one 879 if (broadcastReceivers.get(i).toString().contains( 880 NotificationManagerService.class.getName())) { 881 mUserIntentReceiver = broadcastReceivers.get(i); 882 } 883 } 884 if (filter.hasAction(ACTION_NOTIFICATION_TIMEOUT) 885 && filter.hasDataScheme(SCHEME_TIMEOUT)) { 886 mNotificationTimeoutReceiver = broadcastReceivers.get(i); 887 } 888 } 889 assertNotNull("package intent receiver should exist", mPackageIntentReceiver); 890 assertNotNull("User receiver should exist", mUserIntentReceiver); 891 if (!Flags.allNotifsNeedTtl()) { 892 assertNotNull("Notification timeout receiver should exist", 893 mNotificationTimeoutReceiver); 894 } 895 896 // Pretend the shortcut exists 897 List<ShortcutInfo> shortcutInfos = new ArrayList<>(); 898 shortcutInfos.add(createMockConvoShortcut()); 899 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); 900 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 901 anyString(), anyInt(), any())).thenReturn(true); 902 when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(true); 903 mockIsUserVisible(DEFAULT_DISPLAY, true); 904 mockIsVisibleBackgroundUsersSupported(false); 905 906 // Set the testable bubble extractor 907 RankingHelper rankingHelper = mService.getRankingHelper(); 908 BubbleExtractor extractor = rankingHelper.findExtractor(BubbleExtractor.class); 909 extractor.setActivityManager(mActivityManager); 910 911 // Tests call directly into the Binder. 912 mBinderService = mService.getBinderService(); 913 mInternalService = mService.getInternalService(); 914 915 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice( 916 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 917 mBinderService.createNotificationChannels(PKG_P, new ParceledListSlice( 918 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 919 mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice( 920 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 921 assertNotNull(mBinderService.getNotificationChannel( 922 mPkg, mContext.getUserId(), mPkg, TEST_CHANNEL_ID)); 923 assertNotNull(mBinderService.getNotificationChannel( 924 mPkg, mContext.getUserId(), mPkg, mSilentChannel.getId())); 925 assertNotNull(mBinderService.getNotificationChannel( 926 mPkg, mContext.getUserId(), mPkg, mMinChannel.getId())); 927 clearInvocations(mRankingHandler); 928 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 929 930 var checker = mock(TestableNotificationManagerService.ComponentPermissionChecker.class); 931 mService.permissionChecker = checker; 932 when(checker.check(anyString(), anyInt(), anyInt(), anyBoolean())) 933 .thenReturn(PackageManager.PERMISSION_DENIED); 934 } 935 936 @After assertNotificationRecordLoggerCallsValid()937 public void assertNotificationRecordLoggerCallsValid() { 938 waitForIdle(); // Finish async work, including all logging calls done by Runnables. 939 for (NotificationRecordLoggerFake.CallRecord call : mNotificationRecordLogger.getCalls()) { 940 if (call.wasLogged) { 941 assertNotNull(call.event); 942 if (call.event == NOTIFICATION_POSTED || call.event == NOTIFICATION_UPDATED) { 943 assertThat(call.postDurationMillisLogged).isGreaterThan(0); 944 } else { 945 assertThat(call.postDurationMillisLogged).isNull(); 946 } 947 } 948 } 949 assertThat(mNotificationRecordLogger.getPendingLogs()).isEmpty(); 950 } 951 952 @After assertAllTrackersFinishedOrCancelled()953 public void assertAllTrackersFinishedOrCancelled() { 954 waitForIdle(); // Finish async work. 955 // Verify that no trackers were left dangling. 956 for (PostNotificationTracker tracker : mPostNotificationTrackerFactory.mCreatedTrackers) { 957 assertThat(tracker.isOngoing()).isFalse(); 958 } 959 mPostNotificationTrackerFactory.mCreatedTrackers.clear(); 960 } 961 962 @After assertAllWakeLocksReleased()963 public void assertAllWakeLocksReleased() { 964 waitForIdle(); // Finish async work. 965 for (WakeLock wakeLock : mAcquiredWakeLocks) { 966 assertThat(wakeLock.isHeld()).isFalse(); 967 } 968 } 969 970 @After tearDown()971 public void tearDown() throws Exception { 972 if (mFile != null) mFile.delete(); 973 974 if (mActivityIntent != null) { 975 mActivityIntent.cancel(); 976 } 977 978 mService.clearNotifications(); 979 if (mTestableLooper != null) { 980 mTestableLooper.processAllMessages(); 981 } 982 983 try { 984 mService.onDestroy(); 985 } catch (IllegalStateException | IllegalArgumentException e) { 986 Log.e(TAG, "failed to destroy", e); 987 // can throw if a broadcast receiver was never registered 988 } 989 990 InstrumentationRegistry.getInstrumentation() 991 .getUiAutomation().dropShellPermissionIdentity(); 992 if (mWorkerHandler != null) { 993 // Remove scheduled messages that would be processed when the test is already done, and 994 // could cause issues, for example, messages that remove/cancel shown toasts (this causes 995 // problematic interactions with mocks when they're no longer working as expected). 996 mWorkerHandler.removeCallbacksAndMessages(null); 997 } 998 if (mBroadcastsHandler != null) { 999 mBroadcastsHandler.removeCallbacksAndMessages(null); 1000 } 1001 1002 if (mTestableLooper != null) { 1003 // Must remove static reference to this test object to prevent leak (b/261039202) 1004 mTestableLooper.remove(this); 1005 } 1006 } 1007 createMockConvoShortcut()1008 private ShortcutInfo createMockConvoShortcut() { 1009 ShortcutInfo info = mock(ShortcutInfo.class); 1010 when(info.getPackage()).thenReturn(mPkg); 1011 when(info.getId()).thenReturn(VALID_CONVO_SHORTCUT_ID); 1012 when(info.getUserId()).thenReturn(USER_SYSTEM); 1013 when(info.isLongLived()).thenReturn(true); 1014 when(info.isEnabled()).thenReturn(true); 1015 return info; 1016 } 1017 simulatePackageSuspendBroadcast(boolean suspend, String pkg, int uid)1018 private void simulatePackageSuspendBroadcast(boolean suspend, String pkg, 1019 int uid) { 1020 // mimics receive broadcast that package is (un)suspended 1021 // but does not actually (un)suspend the package 1022 final Bundle extras = new Bundle(); 1023 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, 1024 new String[]{pkg}); 1025 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, new int[]{uid}); 1026 1027 final String action = suspend ? Intent.ACTION_PACKAGES_SUSPENDED 1028 : Intent.ACTION_PACKAGES_UNSUSPENDED; 1029 final Intent intent = new Intent(action); 1030 intent.putExtras(extras); 1031 1032 mPackageIntentReceiver.onReceive(getContext(), intent); 1033 } 1034 simulatePackageRemovedBroadcast(String pkg, int uid)1035 private void simulatePackageRemovedBroadcast(String pkg, int uid) { 1036 // mimics receive broadcast that package is removed, but doesn't remove the package. 1037 final Bundle extras = new Bundle(); 1038 extras.putInt(Intent.EXTRA_UID, uid); 1039 1040 final Intent intent = new Intent(Intent.ACTION_PACKAGE_REMOVED); 1041 intent.setData(Uri.parse("package:" + pkg)); 1042 intent.putExtras(extras); 1043 1044 mPackageIntentReceiver.onReceive(getContext(), intent); 1045 } 1046 simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids)1047 private void simulatePackageDistractionBroadcast(int flag, String[] pkgs, int[] uids) { 1048 // mimics receive broadcast that package is (un)distracting 1049 // but does not actually register that info with packagemanager 1050 final Bundle extras = new Bundle(); 1051 extras.putStringArray(Intent.EXTRA_CHANGED_PACKAGE_LIST, pkgs); 1052 extras.putInt(Intent.EXTRA_DISTRACTION_RESTRICTIONS, flag); 1053 extras.putIntArray(Intent.EXTRA_CHANGED_UID_LIST, uids); 1054 1055 final Intent intent = new Intent(Intent.ACTION_DISTRACTING_PACKAGES_CHANGED); 1056 intent.putExtras(extras); 1057 1058 mPackageIntentReceiver.onReceive(getContext(), intent); 1059 } 1060 simulateProfileAvailabilityActions(String intentAction)1061 private void simulateProfileAvailabilityActions(String intentAction) { 1062 final Intent intent = new Intent(intentAction); 1063 intent.putExtra(Intent.EXTRA_USER_HANDLE, TEST_PROFILE_USERHANDLE); 1064 mUserIntentReceiver.onReceive(mContext, intent); 1065 } 1066 generateResetComponentValues()1067 private ArrayMap<Boolean, ArrayList<ComponentName>> generateResetComponentValues() { 1068 ArrayMap<Boolean, ArrayList<ComponentName>> changed = new ArrayMap<>(); 1069 changed.put(true, new ArrayList<>()); 1070 changed.put(false, new ArrayList<>()); 1071 return changed; 1072 } getApplicationInfo(String pkg, int uid)1073 private ApplicationInfo getApplicationInfo(String pkg, int uid) { 1074 final ApplicationInfo applicationInfo = new ApplicationInfo(); 1075 applicationInfo.packageName = pkg; 1076 applicationInfo.uid = uid; 1077 applicationInfo.sourceDir = mContext.getApplicationInfo().sourceDir; 1078 switch (pkg) { 1079 case PKG_N_MR1: 1080 applicationInfo.targetSdkVersion = Build.VERSION_CODES.N_MR1; 1081 break; 1082 case PKG_O: 1083 applicationInfo.targetSdkVersion = Build.VERSION_CODES.O; 1084 break; 1085 case PKG_P: 1086 applicationInfo.targetSdkVersion = Build.VERSION_CODES.P; 1087 break; 1088 default: 1089 applicationInfo.targetSdkVersion = Build.VERSION_CODES.CUR_DEVELOPMENT; 1090 break; 1091 } 1092 return applicationInfo; 1093 } 1094 waitForIdle()1095 public void waitForIdle() { 1096 if (mTestableLooper != null) { 1097 mTestableLooper.processAllMessages(); 1098 } 1099 } 1100 setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, int pkgPref, boolean channelEnabled)1101 private void setUpPrefsForBubbles(String pkg, int uid, boolean globalEnabled, 1102 int pkgPref, boolean channelEnabled) { 1103 Settings.Secure.putInt(mContext.getContentResolver(), 1104 Settings.Secure.NOTIFICATION_BUBBLES, globalEnabled ? 1 : 0); 1105 mService.mPreferencesHelper.updateBubblesEnabled(); 1106 assertEquals(globalEnabled, mService.mPreferencesHelper.bubblesEnabled( 1107 mock(UserHandle.class))); 1108 try { 1109 mBinderService.setBubblesAllowed(pkg, uid, pkgPref); 1110 } catch (RemoteException e) { 1111 e.printStackTrace(); 1112 } 1113 mTestNotificationChannel.setAllowBubbles(channelEnabled); 1114 } 1115 setUpPrefsForHistory(@serIdInt int userId, boolean globalEnabled)1116 private void setUpPrefsForHistory(@UserIdInt int userId, boolean globalEnabled) 1117 throws Exception { 1118 initNMS(SystemService.PHASE_ACTIVITY_MANAGER_READY); 1119 1120 // Sets NOTIFICATION_HISTORY_ENABLED setting for calling process uid 1121 Settings.Secure.putIntForUser(mContext.getContentResolver(), 1122 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0, userId); 1123 // Sets NOTIFICATION_HISTORY_ENABLED setting for uid 0 1124 Settings.Secure.putInt(mContext.getContentResolver(), 1125 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, globalEnabled ? 1 : 0); 1126 setUsers(new int[] {0, userId}); 1127 1128 // Forces an update by calling observe on mSettingsObserver, which picks up the settings 1129 // changes above. 1130 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 1131 1132 assertEquals(globalEnabled, Settings.Secure.getIntForUser(mContext.getContentResolver(), 1133 Settings.Secure.NOTIFICATION_HISTORY_ENABLED, 0 /* =def */, userId) != 0); 1134 } 1135 generateSbn(String pkg, int uid, long postTime, int userId)1136 private StatusBarNotification generateSbn(String pkg, int uid, long postTime, int userId) { 1137 Notification.Builder nb = new Notification.Builder(mContext, "a") 1138 .setContentTitle("foo") 1139 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1140 StatusBarNotification sbn = new StatusBarNotification(pkg, pkg, uid, 1141 "tag" + System.currentTimeMillis(), uid, 0, 1142 nb.build(), new UserHandle(userId), null, postTime); 1143 return sbn; 1144 } 1145 generateNotificationRecord(NotificationChannel channel, int id, String groupKey, boolean isSummary)1146 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1147 String groupKey, boolean isSummary) { 1148 return generateNotificationRecord(channel, id, "tag" + System.currentTimeMillis(), groupKey, 1149 isSummary); 1150 } 1151 generateNotificationRecord(NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary)1152 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1153 String tag, String groupKey, boolean isSummary) { 1154 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1155 .setContentTitle("foo") 1156 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1157 .setGroup(groupKey) 1158 .setGroupSummary(isSummary); 1159 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, 1160 tag, mUid, 0, 1161 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1162 return new NotificationRecord(mContext, sbn, channel); 1163 } 1164 generateNotificationRecord(NotificationChannel channel)1165 private NotificationRecord generateNotificationRecord(NotificationChannel channel) { 1166 return generateNotificationRecord(channel, null); 1167 } 1168 generateNotificationRecord(NotificationChannel channel, Notification.TvExtender extender)1169 private NotificationRecord generateNotificationRecord(NotificationChannel channel, 1170 Notification.TvExtender extender) { 1171 if (channel == null) { 1172 channel = mTestNotificationChannel; 1173 } 1174 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1175 .setContentTitle("foo") 1176 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1177 .addAction(new Notification.Action.Builder(null, "test", mActivityIntent).build()) 1178 .addAction(new Notification.Action.Builder( 1179 null, "test", mActivityIntentImmutable).build()); 1180 if (extender != null) { 1181 nb.extend(extender); 1182 } 1183 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 1184 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1185 return new NotificationRecord(mContext, sbn, channel); 1186 } 1187 generateNotificationRecord(NotificationChannel channel, long postTime)1188 private NotificationRecord generateNotificationRecord(NotificationChannel channel, 1189 long postTime) { 1190 final StatusBarNotification sbn = generateSbn(mPkg, mUid, postTime, mUserId); 1191 return new NotificationRecord(mContext, sbn, channel); 1192 } 1193 generateNotificationRecord(NotificationChannel channel, int userId)1194 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int userId) { 1195 return generateNotificationRecord(channel, 1, userId); 1196 } 1197 generateNotificationRecord(NotificationChannel channel, int id, int userId)1198 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1199 int userId) { 1200 return generateNotificationRecord(channel, id, userId, "foo"); 1201 } 1202 generateNotificationRecord(NotificationChannel channel, int id, int userId, String title)1203 private NotificationRecord generateNotificationRecord(NotificationChannel channel, int id, 1204 int userId, String title) { 1205 if (channel == null) { 1206 channel = mTestNotificationChannel; 1207 } 1208 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1209 .setContentTitle(title) 1210 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1211 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0, 1212 nb.build(), new UserHandle(userId), null, 0); 1213 NotificationRecord r = new NotificationRecord(mContext, sbn, channel); 1214 return r; 1215 } 1216 generateMessageBubbleNotifRecord(NotificationChannel channel, String tag)1217 private NotificationRecord generateMessageBubbleNotifRecord(NotificationChannel channel, 1218 String tag) { 1219 return generateMessageBubbleNotifRecord(true, channel, 1, tag, null, false, true); 1220 } 1221 generateMessageBubbleNotifRecord(boolean addMetadata, NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, boolean mutable)1222 private NotificationRecord generateMessageBubbleNotifRecord(boolean addMetadata, 1223 NotificationChannel channel, int id, String tag, String groupKey, boolean isSummary, 1224 boolean mutable) { 1225 if (channel == null) { 1226 channel = mTestNotificationChannel; 1227 } 1228 if (tag == null) { 1229 tag = "tag"; 1230 } 1231 Notification.Builder nb = getMessageStyleNotifBuilder(addMetadata, groupKey, 1232 isSummary, mutable); 1233 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, id, 1234 tag, mUid, 0, 1235 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1236 return new NotificationRecord(mContext, sbn, channel); 1237 } 1238 generateRedactedSbn(NotificationChannel channel, int id, int userId)1239 private StatusBarNotification generateRedactedSbn(NotificationChannel channel, int id, 1240 int userId) { 1241 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1242 .setContentTitle("foo") 1243 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1244 .setContentText(REDACTED_TEXT); 1245 return new StatusBarNotification(mPkg, mPkg, id, "tag", mUid, 0, 1246 nb.build(), new UserHandle(userId), null, 0); 1247 } 1248 getSignalExtractorSideEffects()1249 private Map<String, Answer> getSignalExtractorSideEffects() { 1250 Map<String, Answer> answers = new ArrayMap<>(); 1251 1252 answers.put("override group key", invocationOnMock -> { 1253 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1254 .setOverrideGroupKey("bananas"); 1255 return null; 1256 }); 1257 answers.put("override people", invocationOnMock -> { 1258 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1259 .setPeopleOverride(new ArrayList<>()); 1260 return null; 1261 }); 1262 answers.put("snooze criteria", invocationOnMock -> { 1263 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1264 .setSnoozeCriteria(new ArrayList<>()); 1265 return null; 1266 }); 1267 answers.put("notification channel", invocationOnMock -> { 1268 ((NotificationRecord) invocationOnMock.getArguments()[0]) 1269 .updateNotificationChannel(new NotificationChannel("a", "", IMPORTANCE_LOW)); 1270 return null; 1271 }); 1272 answers.put("badging", invocationOnMock -> { 1273 NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0]; 1274 r.setShowBadge(!r.canShowBadge()); 1275 return null; 1276 }); 1277 answers.put("bubbles", invocationOnMock -> { 1278 NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0]; 1279 r.setAllowBubble(!r.canBubble()); 1280 return null; 1281 }); 1282 answers.put("package visibility", invocationOnMock -> { 1283 ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride( 1284 Notification.VISIBILITY_SECRET); 1285 return null; 1286 }); 1287 1288 return answers; 1289 } 1290 getMessageStyleNotifBuilder(boolean addBubbleMetadata, String groupKey, boolean isSummary, boolean mutable)1291 private Notification.Builder getMessageStyleNotifBuilder(boolean addBubbleMetadata, 1292 String groupKey, boolean isSummary, boolean mutable) { 1293 // Give it a person 1294 Person person = new Person.Builder() 1295 .setName("bubblebot") 1296 .build(); 1297 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 1298 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 1299 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 1300 mutable ? mActivityIntent : mActivityIntentImmutable).addRemoteInput(remoteInput) 1301 .build(); 1302 // Make it messaging style 1303 Notification.Builder nb = new Notification.Builder(mContext, 1304 mTestNotificationChannel.getId()) 1305 .setContentTitle("foo") 1306 .setStyle(new Notification.MessagingStyle(person) 1307 .setConversationTitle("Bubble Chat") 1308 .addMessage("Hello?", 1309 SystemClock.currentThreadTimeMillis() - 300000, person) 1310 .addMessage("Is it me you're looking for?", 1311 SystemClock.currentThreadTimeMillis(), person) 1312 ) 1313 .setActions(replyAction) 1314 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1315 .setShortcutId(VALID_CONVO_SHORTCUT_ID) 1316 .setGroupSummary(isSummary); 1317 if (groupKey != null) { 1318 nb.setGroup(groupKey); 1319 } 1320 if (addBubbleMetadata) { 1321 nb.setBubbleMetadata(getBubbleMetadata()); 1322 } 1323 return nb; 1324 } 1325 getBubbleMetadata()1326 private Notification.BubbleMetadata getBubbleMetadata() { 1327 ActivityInfo info = new ActivityInfo(); 1328 info.resizeMode = RESIZE_MODE_RESIZEABLE; 1329 ResolveInfo ri = new ResolveInfo(); 1330 ri.activityInfo = info; 1331 when(mPackageManagerClient.resolveActivityAsUser(any(), anyInt(), anyInt())).thenReturn(ri); 1332 1333 return new Notification.BubbleMetadata.Builder( 1334 mActivityIntent, 1335 Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon)) 1336 .build(); 1337 } 1338 addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel)1339 private NotificationRecord addGroupWithBubblesAndValidateAdded(boolean summaryAutoCancel) 1340 throws RemoteException { 1341 1342 String groupKey = "BUBBLE_GROUP"; 1343 1344 // Notification that has bubble metadata 1345 NotificationRecord nrBubble = generateMessageBubbleNotifRecord(true /* addMetadata */, 1346 mTestNotificationChannel, 1 /* id */, "tag", groupKey, false /* isSummary */, 1347 true); 1348 1349 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrBubble.getSbn().getTag(), 1350 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(), 1351 nrBubble.getSbn().getUserId()); 1352 waitForIdle(); 1353 1354 // Make sure we are a bubble 1355 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 1356 assertEquals(1, notifsAfter.length); 1357 assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0); 1358 1359 // Notification without bubble metadata 1360 NotificationRecord nrPlain = generateMessageBubbleNotifRecord(false /* addMetadata */, 1361 mTestNotificationChannel, 2 /* id */, "tag", groupKey, false /* isSummary */, 1362 true); 1363 1364 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrPlain.getSbn().getTag(), 1365 nrPlain.getSbn().getId(), nrPlain.getSbn().getNotification(), 1366 nrPlain.getSbn().getUserId()); 1367 waitForIdle(); 1368 1369 notifsAfter = mBinderService.getActiveNotifications(mPkg); 1370 assertEquals(2, notifsAfter.length); 1371 1372 // Summary notification for both of those 1373 NotificationRecord nrSummary = generateMessageBubbleNotifRecord(false /* addMetadata */, 1374 mTestNotificationChannel, 3 /* id */, "tag", groupKey, true /* isSummary */, 1375 true); 1376 1377 if (summaryAutoCancel) { 1378 nrSummary.getNotification().flags |= FLAG_AUTO_CANCEL; 1379 } 1380 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nrSummary.getSbn().getTag(), 1381 nrSummary.getSbn().getId(), nrSummary.getSbn().getNotification(), 1382 nrSummary.getSbn().getUserId()); 1383 waitForIdle(); 1384 1385 notifsAfter = mBinderService.getActiveNotifications(mPkg); 1386 assertEquals(3, notifsAfter.length); 1387 1388 return nrSummary; 1389 } 1390 createAndPostCallStyleNotification(String packageName, UserHandle userHandle, String testName)1391 private NotificationRecord createAndPostCallStyleNotification(String packageName, 1392 UserHandle userHandle, String testName) throws Exception { 1393 Person person = new Person.Builder().setName("caller").build(); 1394 Notification.Builder nb = new Notification.Builder(mContext, 1395 mTestNotificationChannel.getId()) 1396 .setFlag(FLAG_USER_INITIATED_JOB, true) 1397 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 1398 .setSmallIcon(android.R.drawable.sym_def_app_icon); 1399 StatusBarNotification sbn = new StatusBarNotification(packageName, packageName, 1, 1400 testName, mUid, 0, nb.build(), userHandle, null, 0); 1401 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 1402 1403 mService.addEnqueuedNotification(r); 1404 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1405 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)).run(); 1406 waitForIdle(); 1407 1408 return mService.findNotificationLocked( 1409 packageName, r.getSbn().getTag(), r.getSbn().getId(), r.getSbn().getUserId()); 1410 } 1411 createAndPostNotification(Notification.Builder nb, String testName)1412 private NotificationRecord createAndPostNotification(Notification.Builder nb, String testName) 1413 throws RemoteException { 1414 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, testName, mUid, 0, 1415 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1416 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 1417 1418 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1419 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 1420 waitForIdle(); 1421 1422 return mService.findNotificationLocked( 1423 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 1424 } 1425 parcelAndUnparcel(T source, Parcelable.Creator<T> creator)1426 private static <T extends Parcelable> T parcelAndUnparcel(T source, 1427 Parcelable.Creator<T> creator) { 1428 Parcel parcel = Parcel.obtain(); 1429 source.writeToParcel(parcel, 0); 1430 parcel.setDataPosition(0); 1431 return creator.createFromParcel(parcel); 1432 } 1433 createPendingIntent(String action)1434 private PendingIntent createPendingIntent(String action) { 1435 return PendingIntent.getActivity(mContext, 0, 1436 new Intent(action).setPackage(mContext.getPackageName()), 1437 PendingIntent.FLAG_MUTABLE); 1438 } 1439 allowTestPackageToToast()1440 private void allowTestPackageToToast() throws Exception { 1441 assertWithMessage("toast queue").that(mService.mToastQueue).isEmpty(); 1442 mService.isSystemUid = false; 1443 mService.isSystemAppId = false; 1444 setToastRateIsWithinQuota(true); 1445 setIfPackageHasPermissionToAvoidToastRateLimiting(TEST_PACKAGE, false); 1446 // package is not suspended 1447 when(mPackageManager.isPackageSuspendedForUser(TEST_PACKAGE, mUserId)) 1448 .thenReturn(false); 1449 } 1450 enqueueToast(String testPackage, ITransientNotification callback)1451 private boolean enqueueToast(String testPackage, ITransientNotification callback) 1452 throws RemoteException { 1453 return enqueueToast((INotificationManager) mService.mService, testPackage, new Binder(), 1454 callback); 1455 } 1456 enqueueToast(INotificationManager service, String testPackage, IBinder token, ITransientNotification callback)1457 private boolean enqueueToast(INotificationManager service, String testPackage, 1458 IBinder token, ITransientNotification callback) throws RemoteException { 1459 return service.enqueueToast(testPackage, token, callback, TOAST_DURATION, /* isUiContext= */ 1460 true, DEFAULT_DISPLAY); 1461 } 1462 enqueueTextToast(String testPackage, CharSequence text)1463 private boolean enqueueTextToast(String testPackage, CharSequence text) throws RemoteException { 1464 return enqueueTextToast(testPackage, text, /* isUiContext= */ true, DEFAULT_DISPLAY); 1465 } 1466 enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, int displayId)1467 private boolean enqueueTextToast(String testPackage, CharSequence text, boolean isUiContext, 1468 int displayId) throws RemoteException { 1469 return ((INotificationManager) mService.mService).enqueueTextToast(testPackage, 1470 new Binder(), text, TOAST_DURATION, isUiContext, displayId, 1471 /* textCallback= */ null); 1472 } 1473 mockIsVisibleBackgroundUsersSupported(boolean supported)1474 private void mockIsVisibleBackgroundUsersSupported(boolean supported) { 1475 when(mUm.isVisibleBackgroundUsersSupported()).thenReturn(supported); 1476 } 1477 mockIsUserVisible(int displayId, boolean visible)1478 private void mockIsUserVisible(int displayId, boolean visible) { 1479 when(mUmInternal.isUserVisible(mUserId, displayId)).thenReturn(visible); 1480 } 1481 mockDisplayAssignedToUser(int displayId)1482 private void mockDisplayAssignedToUser(int displayId) { 1483 when(mUmInternal.getMainDisplayAssignedToUser(mUserId)).thenReturn(displayId); 1484 } 1485 verifyToastShownForTestPackage(String text, int displayId)1486 private void verifyToastShownForTestPackage(String text, int displayId) { 1487 verify(mStatusBar).showToast(eq(mUid), eq(TEST_PACKAGE), any(), eq(text), any(), 1488 eq(TOAST_DURATION), any(), eq(displayId)); 1489 } 1490 1491 @Test 1492 @DisableFlags(FLAG_ALL_NOTIFS_NEED_TTL) testLimitTimeOutBroadcast()1493 public void testLimitTimeOutBroadcast() { 1494 NotificationChannel channel = new NotificationChannel("id", "name", 1495 NotificationManager.IMPORTANCE_HIGH); 1496 Notification.Builder nb = new Notification.Builder(mContext, channel.getId()) 1497 .setContentTitle("foo") 1498 .setSmallIcon(android.R.drawable.sym_def_app_icon) 1499 .setTimeoutAfter(1); 1500 1501 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 1502 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 1503 NotificationRecord r = new NotificationRecord(mContext, sbn, channel); 1504 1505 mService.scheduleTimeoutLocked(r); 1506 ArgumentCaptor<PendingIntent> captor = ArgumentCaptor.forClass(PendingIntent.class); 1507 verify(mAlarmManager).setExactAndAllowWhileIdle(anyInt(), anyLong(), captor.capture()); 1508 assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, 1509 captor.getValue().getIntent().getPackage()); 1510 1511 mService.cancelScheduledTimeoutLocked(r); 1512 verify(mAlarmManager).cancel(captor.capture()); 1513 assertEquals(PackageManagerService.PLATFORM_PACKAGE_NAME, 1514 captor.getValue().getIntent().getPackage()); 1515 } 1516 1517 @Test testDefaultAssistant_overrideDefault()1518 public void testDefaultAssistant_overrideDefault() { 1519 final int userId = mContext.getUserId(); 1520 final String testComponent = "package/class"; 1521 final List<UserInfo> userInfos = new ArrayList<>(); 1522 userInfos.add(new UserInfo(userId, "", 0)); 1523 final ArraySet<ComponentName> validAssistants = new ArraySet<>(); 1524 validAssistants.add(ComponentName.unflattenFromString(testComponent)); 1525 when(mActivityManager.isLowRamDevice()).thenReturn(false); 1526 when(mAssistants.queryPackageForServices(isNull(), anyInt(), anyInt())) 1527 .thenReturn(validAssistants); 1528 when(mAssistants.getDefaultComponents()).thenReturn(validAssistants); 1529 when(mUm.getEnabledProfiles(anyInt())).thenReturn(userInfos); 1530 1531 mService.setDefaultAssistantForUser(userId); 1532 1533 verify(mAssistants).setPackageOrComponentEnabled( 1534 eq(testComponent), eq(userId), eq(true), eq(true), eq(false)); 1535 } 1536 1537 @Test testCreateNotificationChannels_SingleChannel()1538 public void testCreateNotificationChannels_SingleChannel() throws Exception { 1539 final NotificationChannel channel = 1540 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1541 mBinderService.createNotificationChannels(mPkg, 1542 new ParceledListSlice(Arrays.asList(channel))); 1543 final NotificationChannel createdChannel = 1544 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1545 assertTrue(createdChannel != null); 1546 } 1547 1548 @Test testCreateNotificationChannels_NullChannelThrowsException()1549 public void testCreateNotificationChannels_NullChannelThrowsException() throws Exception { 1550 try { 1551 mBinderService.createNotificationChannels(mPkg, 1552 new ParceledListSlice(Arrays.asList((Object[])null))); 1553 fail("Exception should be thrown immediately."); 1554 } catch (NullPointerException e) { 1555 // pass 1556 } 1557 } 1558 1559 @Test testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog()1560 public void testCreateNotificationChannels_FirstChannelWithFgndTaskStartsPermDialog() 1561 throws Exception { 1562 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1563 final NotificationChannel channel = 1564 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1565 mBinderService.createNotificationChannels(PKG_NO_CHANNELS, 1566 new ParceledListSlice(Arrays.asList(channel))); 1567 verify(mWorkerHandler).post(eq(new NotificationManagerService 1568 .ShowNotificationPermissionPromptRunnable(PKG_NO_CHANNELS, 1569 mUserId, TEST_TASK_ID, mPermissionPolicyInternal))); 1570 } 1571 1572 @Test testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog()1573 public void testCreateNotificationChannels_SecondChannelWithFgndTaskDoesntStartPermDialog() 1574 throws Exception { 1575 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1576 assertTrue(mBinderService.getNumNotificationChannelsForPackage(mPkg, mUid, true) > 0); 1577 1578 final NotificationChannel channel = 1579 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1580 mBinderService.createNotificationChannels(mPkg, 1581 new ParceledListSlice(Arrays.asList(channel))); 1582 verify(mWorkerHandler, never()).post(any( 1583 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class)); 1584 } 1585 1586 @Test testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog()1587 public void testCreateNotificationChannels_FirstChannelWithBgndTaskDoesntStartPermDialog() 1588 throws Exception { 1589 reset(mPermissionPolicyInternal); 1590 when(mAtm.getTaskToShowPermissionDialogOn(anyString(), anyInt())).thenReturn(TEST_TASK_ID); 1591 1592 final NotificationChannel channel = 1593 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1594 mBinderService.createNotificationChannels(mPkg, 1595 new ParceledListSlice(Arrays.asList(channel))); 1596 1597 verify(mWorkerHandler, never()).post(any( 1598 NotificationManagerService.ShowNotificationPermissionPromptRunnable.class)); 1599 } 1600 1601 @Test testCreateNotificationChannels_TwoChannels()1602 public void testCreateNotificationChannels_TwoChannels() throws Exception { 1603 final NotificationChannel channel1 = 1604 new NotificationChannel("id1", "name", IMPORTANCE_DEFAULT); 1605 final NotificationChannel channel2 = 1606 new NotificationChannel("id2", "name", IMPORTANCE_DEFAULT); 1607 mBinderService.createNotificationChannels(mPkg, 1608 new ParceledListSlice(Arrays.asList(channel1, channel2))); 1609 assertTrue(mBinderService.getNotificationChannel( 1610 mPkg, mContext.getUserId(), mPkg, "id1") != null); 1611 assertTrue(mBinderService.getNotificationChannel( 1612 mPkg, mContext.getUserId(), mPkg, "id2") != null); 1613 } 1614 1615 @Test testCreateNotificationChannels_SecondCreateDoesNotChangeImportance()1616 public void testCreateNotificationChannels_SecondCreateDoesNotChangeImportance() 1617 throws Exception { 1618 final NotificationChannel channel = 1619 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1620 mBinderService.createNotificationChannels(mPkg, 1621 new ParceledListSlice(Arrays.asList(channel))); 1622 1623 // Recreating the channel doesn't throw, but ignores importance. 1624 final NotificationChannel dupeChannel = 1625 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1626 mBinderService.createNotificationChannels(mPkg, 1627 new ParceledListSlice(Arrays.asList(dupeChannel))); 1628 final NotificationChannel createdChannel = 1629 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1630 assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance()); 1631 } 1632 1633 @Test testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance()1634 public void testCreateNotificationChannels_SecondCreateAllowedToDowngradeImportance() 1635 throws Exception { 1636 final NotificationChannel channel = 1637 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1638 mBinderService.createNotificationChannels(mPkg, 1639 new ParceledListSlice(Arrays.asList(channel))); 1640 1641 // Recreating with a lower importance is allowed to modify the channel. 1642 final NotificationChannel dupeChannel = 1643 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); 1644 mBinderService.createNotificationChannels(mPkg, 1645 new ParceledListSlice(Arrays.asList(dupeChannel))); 1646 final NotificationChannel createdChannel = 1647 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1648 assertEquals(NotificationManager.IMPORTANCE_LOW, createdChannel.getImportance()); 1649 } 1650 1651 @Test testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated()1652 public void testCreateNotificationChannels_CannotDowngradeImportanceIfAlreadyUpdated() 1653 throws Exception { 1654 final NotificationChannel channel = 1655 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1656 mBinderService.createNotificationChannels(mPkg, 1657 new ParceledListSlice(Arrays.asList(channel))); 1658 1659 // The user modifies importance directly, can no longer be changed by the app. 1660 final NotificationChannel updatedChannel = 1661 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1662 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, updatedChannel); 1663 1664 // Recreating with a lower importance leaves channel unchanged. 1665 final NotificationChannel dupeChannel = 1666 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_LOW); 1667 mBinderService.createNotificationChannels(mPkg, 1668 new ParceledListSlice(Arrays.asList(dupeChannel))); 1669 final NotificationChannel createdChannel = 1670 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1671 assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance()); 1672 } 1673 1674 @Test testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond()1675 public void testCreateNotificationChannels_IdenticalChannelsInListIgnoresSecond() 1676 throws Exception { 1677 final NotificationChannel channel1 = 1678 new NotificationChannel("id", "name", IMPORTANCE_DEFAULT); 1679 final NotificationChannel channel2 = 1680 new NotificationChannel("id", "name", IMPORTANCE_HIGH); 1681 mBinderService.createNotificationChannels(mPkg, 1682 new ParceledListSlice(Arrays.asList(channel1, channel2))); 1683 final NotificationChannel createdChannel = 1684 mBinderService.getNotificationChannel(mPkg, mContext.getUserId(), mPkg, "id"); 1685 assertEquals(IMPORTANCE_DEFAULT, createdChannel.getImportance()); 1686 } 1687 1688 @Test testBlockedNotifications_suspended()1689 public void testBlockedNotifications_suspended() throws Exception { 1690 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true); 1691 1692 NotificationChannel channel = new NotificationChannel("id", "name", 1693 IMPORTANCE_HIGH); 1694 NotificationRecord r = generateNotificationRecord(channel); 1695 1696 // isBlocked is only used for user blocking, not app suspension 1697 assertFalse(mService.isRecordBlockedLocked(r)); 1698 } 1699 1700 @Test testBlockedNotifications_blockedChannel()1701 public void testBlockedNotifications_blockedChannel() throws Exception { 1702 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1703 1704 NotificationChannel channel = new NotificationChannel("id", "name", 1705 NotificationManager.IMPORTANCE_NONE); 1706 NotificationRecord r = generateNotificationRecord(channel); 1707 assertTrue(mService.isRecordBlockedLocked(r)); 1708 1709 mBinderService.createNotificationChannels( 1710 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1711 final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1712 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1713 "testBlockedNotifications_blockedChannel", 1714 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1715 waitForIdle(); 1716 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1717 } 1718 1719 @Test testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()1720 public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService() 1721 throws Exception { 1722 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1723 when(mAmi.applyForegroundServiceNotification( 1724 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1725 1726 NotificationChannel channel = new NotificationChannel("blocked", "name", 1727 NotificationManager.IMPORTANCE_NONE); 1728 mBinderService.createNotificationChannels( 1729 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1730 1731 final StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1732 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1733 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1734 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1735 waitForIdle(); 1736 assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1737 assertEquals(IMPORTANCE_LOW, 1738 mService.getNotificationRecord(sbn.getKey()).getImportance()); 1739 assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel( 1740 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1741 } 1742 1743 @Test testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()1744 public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService() 1745 throws Exception { 1746 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1747 when(mAmi.applyForegroundServiceNotification( 1748 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1749 1750 NotificationChannel channel = 1751 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH); 1752 mBinderService.createNotificationChannels( 1753 mPkg, new ParceledListSlice(Arrays.asList(channel))); 1754 1755 NotificationChannel update = 1756 new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE); 1757 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update); 1758 waitForIdle(); 1759 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1760 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1761 1762 StatusBarNotification sbn = generateNotificationRecord(channel).getSbn(); 1763 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1764 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 1765 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1766 waitForIdle(); 1767 // The first time a foreground service notification is shown, we allow the channel 1768 // to be updated to allow it to be seen. 1769 assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1770 assertEquals(IMPORTANCE_LOW, 1771 mService.getNotificationRecord(sbn.getKey()).getImportance()); 1772 assertEquals(IMPORTANCE_LOW, mBinderService.getNotificationChannel( 1773 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1774 mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId()); 1775 waitForIdle(); 1776 1777 update = new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE); 1778 update.setUserVisibleTaskShown(true); 1779 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, update); 1780 waitForIdle(); 1781 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1782 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1783 1784 sbn = generateNotificationRecord(channel).getSbn(); 1785 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1786 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1787 "testEnqueuedBlockedNotifications_userBlockedChannelForegroundService", 1788 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1789 waitForIdle(); 1790 // The second time it is shown, we keep the user's preference. 1791 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1792 assertNull(mService.getNotificationRecord(sbn.getKey())); 1793 assertEquals(IMPORTANCE_NONE, mBinderService.getNotificationChannel( 1794 mPkg, mContext.getUserId(), mPkg, channel.getId()).getImportance()); 1795 } 1796 1797 @Test testBlockedNotifications_blockedChannelGroup()1798 public void testBlockedNotifications_blockedChannelGroup() throws Exception { 1799 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1800 mService.setPreferencesHelper(mPreferencesHelper); 1801 when(mPreferencesHelper.isGroupBlocked(anyString(), anyInt(), anyString())). 1802 thenReturn(true); 1803 1804 NotificationChannel channel = new NotificationChannel("id", "name", 1805 NotificationManager.IMPORTANCE_HIGH); 1806 channel.setGroup("something"); 1807 NotificationRecord r = generateNotificationRecord(channel); 1808 assertTrue(mService.isRecordBlockedLocked(r)); 1809 } 1810 1811 @Test testEnqueuedBlockedNotifications_blockedApp()1812 public void testEnqueuedBlockedNotifications_blockedApp() throws Exception { 1813 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1814 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1815 1816 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1817 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1818 "testEnqueuedBlockedNotifications_blockedApp", 1819 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1820 waitForIdle(); 1821 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1822 } 1823 1824 @Test testEnqueuedBlockedNotifications_blockedAppForegroundService()1825 public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception { 1826 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1827 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1828 when(mAmi.applyForegroundServiceNotification( 1829 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 1830 1831 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1832 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 1833 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1834 "testEnqueuedBlockedNotifications_blockedAppForegroundService", 1835 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1836 waitForIdle(); 1837 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 1838 assertNull(mService.getNotificationRecord(sbn.getKey())); 1839 } 1840 1841 /** 1842 * Confirm an application with the SEND_CATEGORY_CAR_NOTIFICATIONS permission on automotive 1843 * devices can use car categories. 1844 */ 1845 @Test testEnqueuedRestrictedNotifications_hasPermission()1846 public void testEnqueuedRestrictedNotifications_hasPermission() throws Exception { 1847 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1848 .thenReturn(true); 1849 // SEND_CATEGORY_CAR_NOTIFICATIONS is a system-level permission that this test cannot 1850 // obtain. Mocking out enforce permission call to ensure notifications can be created when 1851 // permitted. 1852 doNothing().when(mContext).enforceCallingPermission( 1853 eq("android.permission.SEND_CATEGORY_CAR_NOTIFICATIONS"), anyString()); 1854 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1855 Notification.CATEGORY_CAR_WARNING, 1856 Notification.CATEGORY_CAR_INFORMATION); 1857 int id = 0; 1858 for (String category: categories) { 1859 final StatusBarNotification sbn = 1860 generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn(); 1861 sbn.getNotification().category = category; 1862 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1863 "testEnqueuedRestrictedNotifications_asSystem", 1864 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1865 } 1866 waitForIdle(); 1867 assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length); 1868 } 1869 1870 1871 /** 1872 * Confirm restricted notification categories only apply to automotive. 1873 */ 1874 @Test testEnqueuedRestrictedNotifications_notAutomotive()1875 public void testEnqueuedRestrictedNotifications_notAutomotive() throws Exception { 1876 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1877 .thenReturn(false); 1878 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1879 Notification.CATEGORY_CAR_WARNING, 1880 Notification.CATEGORY_CAR_INFORMATION); 1881 int id = 0; 1882 for (String category: categories) { 1883 final StatusBarNotification sbn = 1884 generateNotificationRecord(mTestNotificationChannel, ++id, "", false).getSbn(); 1885 sbn.getNotification().category = category; 1886 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1887 "testEnqueuedRestrictedNotifications_notAutomotive", 1888 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1889 } 1890 waitForIdle(); 1891 assertEquals(categories.size(), mBinderService.getActiveNotifications(mPkg).length); 1892 } 1893 1894 /** 1895 * Confirm if an application tries to use the car categories on a automotive device without the 1896 * SEND_CATEGORY_CAR_NOTIFICATIONS permission that a security exception will be thrown. 1897 */ 1898 @Test testEnqueuedRestrictedNotifications_noPermission()1899 public void testEnqueuedRestrictedNotifications_noPermission() throws Exception { 1900 when(mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE, 0)) 1901 .thenReturn(true); 1902 List<String> categories = Arrays.asList(Notification.CATEGORY_CAR_EMERGENCY, 1903 Notification.CATEGORY_CAR_WARNING, 1904 Notification.CATEGORY_CAR_INFORMATION); 1905 for (String category: categories) { 1906 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 1907 sbn.getNotification().category = category; 1908 try { 1909 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 1910 "testEnqueuedRestrictedNotifications_badUser", 1911 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 1912 fail("Calls from non system apps should not allow use of restricted categories"); 1913 } catch (SecurityException e) { 1914 // pass 1915 } 1916 } 1917 waitForIdle(); 1918 assertEquals(0, mBinderService.getActiveNotifications(mPkg).length); 1919 } 1920 1921 @Test testSetNotificationsEnabledForPackage_noChange()1922 public void testSetNotificationsEnabledForPackage_noChange() throws Exception { 1923 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1924 mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, true); 1925 1926 verify(mPermissionHelper, never()).setNotificationPermission( 1927 anyString(), anyInt(), anyBoolean(), anyBoolean()); 1928 } 1929 1930 @Test testSetNotificationsEnabledForPackage()1931 public void testSetNotificationsEnabledForPackage() throws Exception { 1932 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 1933 mBinderService.setNotificationsEnabledForPackage(mContext.getPackageName(), mUid, false); 1934 1935 verify(mPermissionHelper).setNotificationPermission( 1936 mContext.getPackageName(), mUserId, false, true); 1937 1938 verify(mAppOpsManager, never()).setMode(anyInt(), anyInt(), anyString(), anyInt()); 1939 List<NotificationChannelLoggerFake.CallRecord> calls = mLogger.getCalls(); 1940 Assert.assertEquals( 1941 NotificationChannelLogger.NotificationChannelEvent.APP_NOTIFICATIONS_BLOCKED, 1942 calls.get(calls.size() -1).event); 1943 } 1944 1945 @Test testBlockedNotifications_blockedByAssistant()1946 public void testBlockedNotifications_blockedByAssistant() throws Exception { 1947 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1948 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 1949 1950 NotificationChannel channel = new NotificationChannel("id", "name", 1951 NotificationManager.IMPORTANCE_HIGH); 1952 NotificationRecord r = generateNotificationRecord(channel); 1953 mService.addEnqueuedNotification(r); 1954 1955 Bundle bundle = new Bundle(); 1956 bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE); 1957 Adjustment adjustment = new Adjustment( 1958 r.getSbn().getPackageName(), r.getKey(), bundle, "", r.getUser().getIdentifier()); 1959 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 1960 1961 NotificationManagerService.PostNotificationRunnable runnable = 1962 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1963 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 1964 runnable.run(); 1965 waitForIdle(); 1966 1967 verify(mUsageStats, never()).registerPostedByApp(any()); 1968 } 1969 1970 @Test testBlockedNotifications_blockedByUser()1971 public void testBlockedNotifications_blockedByUser() throws Exception { 1972 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 1973 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 1974 1975 NotificationChannel channel = new NotificationChannel("id", "name", 1976 NotificationManager.IMPORTANCE_HIGH); 1977 NotificationRecord r = generateNotificationRecord(channel); 1978 mService.addEnqueuedNotification(r); 1979 1980 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 1981 1982 NotificationManagerService.PostNotificationRunnable runnable = 1983 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 1984 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 1985 runnable.run(); 1986 waitForIdle(); 1987 1988 verify(mUsageStats).registerBlocked(any()); 1989 verify(mUsageStats, never()).registerPostedByApp(any()); 1990 } 1991 1992 @Test testEnqueueNotificationInternal_noChannel()1993 public void testEnqueueNotificationInternal_noChannel() throws Exception { 1994 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 1995 NotificationRecord nr = generateNotificationRecord( 1996 new NotificationChannel("did not create", "", IMPORTANCE_DEFAULT)); 1997 1998 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 1999 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 2000 waitForIdle(); 2001 2002 verify(mPermissionHelper).hasPermission(mUid); 2003 verify(mPermissionHelper, never()).hasPermission(Process.SYSTEM_UID); 2004 2005 reset(mPermissionHelper); 2006 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 2007 2008 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 2009 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 2010 waitForIdle(); 2011 2012 verify(mPermissionHelper).hasPermission(mUid); 2013 assertThat(mService.mChannelToastsSent).contains(mUid); 2014 } 2015 2016 @Test testEnqueueNotification_appBlocked()2017 public void testEnqueueNotification_appBlocked() throws Exception { 2018 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 2019 2020 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2021 "testEnqueueNotification_appBlocked", 0, 2022 generateNotificationRecord(null).getNotification(), mUserId); 2023 waitForIdle(); 2024 verify(mWorkerHandler, never()).post( 2025 any(NotificationManagerService.EnqueueNotificationRunnable.class)); 2026 } 2027 2028 @Test testEnqueueNotificationWithTag_PopulatesGetActiveNotifications()2029 public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception { 2030 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2031 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2032 generateNotificationRecord(null).getNotification(), mUserId); 2033 waitForIdle(); 2034 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 2035 assertEquals(1, notifs.length); 2036 assertEquals(1, mService.getNotificationRecordCount()); 2037 } 2038 2039 @Test testEnqueueNotificationWithTag_WritesExpectedLogs()2040 public void testEnqueueNotificationWithTag_WritesExpectedLogs() throws Exception { 2041 final String tag = "testEnqueueNotificationWithTag_WritesExpectedLog"; 2042 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2043 generateNotificationRecord(null).getNotification(), mUserId); 2044 waitForIdle(); 2045 assertEquals(1, mNotificationRecordLogger.numCalls()); 2046 2047 NotificationRecordLoggerFake.CallRecord call = mNotificationRecordLogger.get(0); 2048 assertTrue(call.wasLogged); 2049 assertEquals(NOTIFICATION_POSTED, call.event); 2050 assertNotNull(call.r); 2051 assertNull(call.old); 2052 assertEquals(0, call.position); 2053 assertEquals(0, call.buzzBeepBlink); 2054 assertEquals(mPkg, call.r.getSbn().getPackageName()); 2055 assertEquals(0, call.r.getSbn().getId()); 2056 assertEquals(tag, call.r.getSbn().getTag()); 2057 assertEquals(1, call.getInstanceId()); // Fake instance IDs are assigned in order 2058 assertThat(call.postDurationMillisLogged).isGreaterThan(0); 2059 } 2060 2061 @Test testEnqueueNotificationWithTag_LogsOnMajorUpdates()2062 public void testEnqueueNotificationWithTag_LogsOnMajorUpdates() throws Exception { 2063 final String tag = "testEnqueueNotificationWithTag_LogsOnMajorUpdates"; 2064 Notification original = new Notification.Builder(mContext, 2065 mTestNotificationChannel.getId()) 2066 .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); 2067 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, original, mUserId); 2068 Notification update = new Notification.Builder(mContext, 2069 mTestNotificationChannel.getId()) 2070 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2071 .setCategory(Notification.CATEGORY_ALARM).build(); 2072 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, update, mUserId); 2073 waitForIdle(); 2074 assertEquals(2, mNotificationRecordLogger.numCalls()); 2075 2076 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2077 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2078 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 2079 assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0); 2080 2081 assertTrue(mNotificationRecordLogger.get(1).wasLogged); 2082 assertEquals(NOTIFICATION_UPDATED, mNotificationRecordLogger.event(1)); 2083 // Instance ID doesn't change on update of an active notification 2084 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 2085 assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isGreaterThan(0); 2086 } 2087 2088 @Test testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate()2089 public void testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate() throws Exception { 2090 final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnMinorUpdate"; 2091 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2092 generateNotificationRecord(null).getNotification(), mUserId); 2093 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2094 generateNotificationRecord(null).getNotification(), mUserId); 2095 waitForIdle(); 2096 assertEquals(2, mNotificationRecordLogger.numCalls()); 2097 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2098 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2099 assertFalse(mNotificationRecordLogger.get(1).wasLogged); 2100 assertNull(mNotificationRecordLogger.event(1)); 2101 } 2102 2103 @Test testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate()2104 public void testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate() throws Exception { 2105 final String tag = "testEnqueueNotificationWithTag_DoesNotLogOnTitleUpdate"; 2106 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, 2107 generateNotificationRecord(null).getNotification(), 2108 mUserId); 2109 final Notification notif = generateNotificationRecord(null).getNotification(); 2110 notif.extras.putString(Notification.EXTRA_TITLE, "Changed title"); 2111 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notif, mUserId); 2112 waitForIdle(); 2113 assertEquals(2, mNotificationRecordLogger.numCalls()); 2114 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2115 assertNull(mNotificationRecordLogger.event(1)); 2116 } 2117 2118 @Test testEnqueueNotificationWithTag_LogsAgainAfterCancel()2119 public void testEnqueueNotificationWithTag_LogsAgainAfterCancel() throws Exception { 2120 final String tag = "testEnqueueNotificationWithTag_LogsAgainAfterCancel"; 2121 Notification notification = new Notification.Builder(mContext, 2122 mTestNotificationChannel.getId()) 2123 .setSmallIcon(android.R.drawable.sym_def_app_icon).build(); 2124 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId); 2125 waitForIdle(); 2126 mBinderService.cancelNotificationWithTag(mPkg, mPkg, tag, 0, mUserId); 2127 waitForIdle(); 2128 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 0, notification, mUserId); 2129 waitForIdle(); 2130 assertEquals(3, mNotificationRecordLogger.numCalls()); 2131 2132 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(0)); 2133 assertTrue(mNotificationRecordLogger.get(0).wasLogged); 2134 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 2135 assertThat(mNotificationRecordLogger.get(0).postDurationMillisLogged).isGreaterThan(0); 2136 2137 assertEquals( 2138 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_APP_CANCEL, 2139 mNotificationRecordLogger.event(1)); 2140 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 2141 // Cancel is not post, so no logged post_duration_millis. 2142 assertThat(mNotificationRecordLogger.get(1).postDurationMillisLogged).isNull(); 2143 2144 assertEquals(NOTIFICATION_POSTED, mNotificationRecordLogger.event(2)); 2145 assertTrue(mNotificationRecordLogger.get(2).wasLogged); 2146 // New instance ID because notification was canceled before re-post 2147 assertEquals(2, mNotificationRecordLogger.get(2).getInstanceId()); 2148 assertThat(mNotificationRecordLogger.get(2).postDurationMillisLogged).isGreaterThan(0); 2149 } 2150 2151 @Test testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed()2152 public void testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed() throws Exception { 2153 when(mAmi.applyForegroundServiceNotification( 2154 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 2155 mContext.getTestablePermissions().setPermission( 2156 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_GRANTED); 2157 2158 final String tag = "testEnqueueNotificationWithTag_FgsAddsFlags_dismissalAllowed"; 2159 2160 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2161 .setContentTitle("foo") 2162 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2163 .setFlag(FLAG_FOREGROUND_SERVICE, true) 2164 .build(); 2165 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, tag, mUid, 0, 2166 n, UserHandle.getUserHandleForUid(mUid), null, 0); 2167 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, tag, 2168 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2169 waitForIdle(); 2170 2171 StatusBarNotification[] notifs = 2172 mBinderService.getActiveNotifications(mPkg); 2173 assertThat(notifs[0].getNotification().flags).isEqualTo( 2174 FLAG_FOREGROUND_SERVICE | FLAG_CAN_COLORIZE | FLAG_NO_CLEAR); 2175 } 2176 2177 @Test testEnqueueNotificationWithTag_nullAction_fixed()2178 public void testEnqueueNotificationWithTag_nullAction_fixed() throws Exception { 2179 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2180 .setContentTitle("foo") 2181 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2182 .addAction(new Notification.Action.Builder(null, "one", null).build()) 2183 .addAction(new Notification.Action.Builder(null, "two", null).build()) 2184 .addAction(new Notification.Action.Builder(null, "three", null).build()) 2185 .build(); 2186 n.actions[1] = null; 2187 2188 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 2189 waitForIdle(); 2190 2191 StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg); 2192 assertThat(posted).hasLength(1); 2193 assertThat(posted[0].getNotification().actions).hasLength(2); 2194 assertThat(posted[0].getNotification().actions[0].title.toString()).isEqualTo("one"); 2195 assertThat(posted[0].getNotification().actions[1].title.toString()).isEqualTo("three"); 2196 } 2197 2198 @Test testEnqueueNotificationWithTag_allNullActions_fixed()2199 public void testEnqueueNotificationWithTag_allNullActions_fixed() throws Exception { 2200 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2201 .setContentTitle("foo") 2202 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2203 .addAction(new Notification.Action.Builder(null, "one", null).build()) 2204 .addAction(new Notification.Action.Builder(null, "two", null).build()) 2205 .build(); 2206 n.actions[0] = null; 2207 n.actions[1] = null; 2208 2209 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 2210 waitForIdle(); 2211 2212 StatusBarNotification[] posted = mBinderService.getActiveNotifications(mPkg); 2213 assertThat(posted).hasLength(1); 2214 assertThat(posted[0].getNotification().actions).isNull(); 2215 } 2216 2217 @Test enqueueNotificationWithTag_usesAndFinishesTracker()2218 public void enqueueNotificationWithTag_usesAndFinishesTracker() throws Exception { 2219 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2220 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2221 generateNotificationRecord(null).getNotification(), mUserId); 2222 2223 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2224 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isTrue(); 2225 2226 waitForIdle(); 2227 2228 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(1); 2229 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2230 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2231 } 2232 2233 @Test enqueueNotificationWithTag_throws_usesAndCancelsTracker()2234 public void enqueueNotificationWithTag_throws_usesAndCancelsTracker() throws Exception { 2235 // Simulate not enqueued due to rejected inputs. 2236 assertThrows(Exception.class, 2237 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2238 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2239 /* notification= */ null, mUserId)); 2240 2241 waitForIdle(); 2242 2243 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2244 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2245 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2246 } 2247 2248 @Test enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker()2249 public void enqueueNotificationWithTag_notEnqueued_usesAndCancelsTracker() throws Exception { 2250 // Simulate not enqueued due to snoozing inputs. 2251 when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any())) 2252 .thenReturn("zzzzzzz"); 2253 2254 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2255 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2256 generateNotificationRecord(null).getNotification(), mUserId); 2257 waitForIdle(); 2258 2259 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2260 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2261 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2262 } 2263 2264 @Test enqueueNotificationWithTag_notPosted_usesAndCancelsTracker()2265 public void enqueueNotificationWithTag_notPosted_usesAndCancelsTracker() throws Exception { 2266 // Simulate not posted due to blocked app. 2267 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 2268 2269 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2270 "testEnqueueNotificationWithTag_PopulatesGetActiveNotifications", 0, 2271 generateNotificationRecord(null).getNotification(), mUserId); 2272 waitForIdle(); 2273 2274 assertThat(mBinderService.getActiveNotifications(mPkg)).hasLength(0); 2275 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers).hasSize(1); 2276 assertThat(mPostNotificationTrackerFactory.mCreatedTrackers.get(0).isOngoing()).isFalse(); 2277 } 2278 2279 @Test enqueueNotification_acquiresAndReleasesWakeLock()2280 public void enqueueNotification_acquiresAndReleasesWakeLock() throws Exception { 2281 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2282 "enqueueNotification_acquiresAndReleasesWakeLock", 0, 2283 generateNotificationRecord(null).getNotification(), mUserId); 2284 2285 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2286 assertThat(mAcquiredWakeLocks).hasSize(1); 2287 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2288 2289 waitForIdle(); 2290 2291 assertThat(mAcquiredWakeLocks).hasSize(1); 2292 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2293 } 2294 2295 @Test enqueueNotification_throws_acquiresAndReleasesWakeLock()2296 public void enqueueNotification_throws_acquiresAndReleasesWakeLock() throws Exception { 2297 // Simulate not enqueued due to rejected inputs. 2298 assertThrows(Exception.class, 2299 () -> mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2300 "enqueueNotification_throws_acquiresAndReleasesWakeLock", 0, 2301 /* notification= */ null, mUserId)); 2302 2303 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2304 assertThat(mAcquiredWakeLocks).hasSize(1); 2305 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2306 } 2307 2308 @Test enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock()2309 public void enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock() throws Exception { 2310 // Simulate not enqueued due to snoozing inputs. 2311 when(mSnoozeHelper.getSnoozeContextForUnpostedNotification(anyInt(), any(), any())) 2312 .thenReturn("zzzzzzz"); 2313 2314 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2315 "enqueueNotification_notEnqueued_acquiresAndReleasesWakeLock", 0, 2316 generateNotificationRecord(null).getNotification(), mUserId); 2317 2318 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2319 assertThat(mAcquiredWakeLocks).hasSize(1); 2320 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2321 2322 waitForIdle(); 2323 2324 assertThat(mAcquiredWakeLocks).hasSize(1); 2325 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2326 } 2327 2328 @Test enqueueNotification_notPosted_acquiresAndReleasesWakeLock()2329 public void enqueueNotification_notPosted_acquiresAndReleasesWakeLock() throws Exception { 2330 // Simulate enqueued but not posted due to missing small icon. 2331 Notification notif = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 2332 .setContentTitle("foo") 2333 .build(); 2334 2335 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2336 "enqueueNotification_notPosted_acquiresAndReleasesWakeLock", 0, 2337 notif, mUserId); 2338 2339 verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2340 assertThat(mAcquiredWakeLocks).hasSize(1); 2341 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isTrue(); 2342 2343 waitForIdle(); 2344 2345 // NLSes were not called. 2346 verify(mListeners, never()).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 2347 2348 assertThat(mAcquiredWakeLocks).hasSize(1); 2349 assertThat(mAcquiredWakeLocks.get(0).isHeld()).isFalse(); 2350 } 2351 2352 @Test enqueueNotification_setsWakeLockWorkSource()2353 public void enqueueNotification_setsWakeLockWorkSource() throws Exception { 2354 // Use a "full" mock for the PowerManager (instead of the one that delegates to the real 2355 // service) so we can return a mocked WakeLock that we can verify() on. 2356 reset(mPowerManager); 2357 WakeLock wakeLock = mock(WakeLock.class); 2358 when(mPowerManager.newWakeLock(anyInt(), anyString())).thenReturn(wakeLock); 2359 2360 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2361 "enqueueNotification_setsWakeLockWorkSource", 0, 2362 generateNotificationRecord(null).getNotification(), mUserId); 2363 waitForIdle(); 2364 2365 InOrder inOrder = inOrder(mPowerManager, wakeLock); 2366 inOrder.verify(mPowerManager).newWakeLock(eq(PARTIAL_WAKE_LOCK), anyString()); 2367 inOrder.verify(wakeLock).setWorkSource(eq(new WorkSource(mUid, mPkg))); 2368 inOrder.verify(wakeLock).acquire(anyLong()); 2369 inOrder.verify(wakeLock).release(); 2370 inOrder.verifyNoMoreInteractions(); 2371 } 2372 2373 @Test testCancelNonexistentNotification()2374 public void testCancelNonexistentNotification() throws Exception { 2375 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2376 "testCancelNonexistentNotification", 0, mUserId); 2377 waitForIdle(); 2378 // The notification record logger doesn't even get called when a nonexistent notification 2379 // is cancelled, because that happens very frequently and is not interesting. 2380 assertEquals(0, mNotificationRecordLogger.numCalls()); 2381 } 2382 2383 @Test testCancelNotificationImmediatelyAfterEnqueue()2384 public void testCancelNotificationImmediatelyAfterEnqueue() throws Exception { 2385 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2386 "testCancelNotificationImmediatelyAfterEnqueue", 0, 2387 generateNotificationRecord(null).getNotification(), mUserId); 2388 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2389 "testCancelNotificationImmediatelyAfterEnqueue", 0, mUserId); 2390 waitForIdle(); 2391 StatusBarNotification[] notifs = 2392 mBinderService.getActiveNotifications(mPkg); 2393 assertEquals(0, notifs.length); 2394 assertEquals(0, mService.getNotificationRecordCount()); 2395 } 2396 2397 @Test testPostCancelPostNotifiesListeners()2398 public void testPostCancelPostNotifiesListeners() throws Exception { 2399 // WHEN a notification is posted 2400 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2401 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), 2402 sbn.getNotification(), sbn.getUserId()); 2403 mTestableLooper.moveTimeForward(1); 2404 // THEN it is canceled 2405 mBinderService.cancelNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), sbn.getUserId()); 2406 mTestableLooper.moveTimeForward(1); 2407 // THEN it is posted again (before the cancel has a chance to finish) 2408 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", sbn.getId(), 2409 sbn.getNotification(), sbn.getUserId()); 2410 // THEN the later enqueue isn't swallowed by the cancel. I.e., ordering is respected 2411 waitForIdle(); 2412 2413 // The final enqueue made it to the listener instead of being canceled 2414 StatusBarNotification[] notifs = 2415 mBinderService.getActiveNotifications(mPkg); 2416 assertEquals(1, notifs.length); 2417 assertEquals(1, mService.getNotificationRecordCount()); 2418 } 2419 2420 @Test testCancelNotificationWhilePostedAndEnqueued()2421 public void testCancelNotificationWhilePostedAndEnqueued() throws Exception { 2422 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2423 "testCancelNotificationWhilePostedAndEnqueued", 0, 2424 generateNotificationRecord(null).getNotification(), mUserId); 2425 waitForIdle(); 2426 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2427 "testCancelNotificationWhilePostedAndEnqueued", 0, 2428 generateNotificationRecord(null).getNotification(), mUserId); 2429 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 2430 "testCancelNotificationWhilePostedAndEnqueued", 0, mUserId); 2431 waitForIdle(); 2432 StatusBarNotification[] notifs = 2433 mBinderService.getActiveNotifications(mPkg); 2434 assertEquals(0, notifs.length); 2435 assertEquals(0, mService.getNotificationRecordCount()); 2436 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 2437 verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture()); 2438 assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface()); 2439 } 2440 2441 @Test testCancelNotificationsFromListenerImmediatelyAfterEnqueue()2442 public void testCancelNotificationsFromListenerImmediatelyAfterEnqueue() throws Exception { 2443 NotificationRecord r = generateNotificationRecord(null); 2444 final StatusBarNotification sbn = r.getSbn(); 2445 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2446 "testCancelNotificationsFromListenerImmediatelyAfterEnqueue", 2447 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2448 mBinderService.cancelNotificationsFromListener(null, null); 2449 waitForIdle(); 2450 StatusBarNotification[] notifs = 2451 mBinderService.getActiveNotifications(sbn.getPackageName()); 2452 assertEquals(0, notifs.length); 2453 assertEquals(0, mService.getNotificationRecordCount()); 2454 } 2455 2456 @Test testCancelAllNotificationsImmediatelyAfterEnqueue()2457 public void testCancelAllNotificationsImmediatelyAfterEnqueue() throws Exception { 2458 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2459 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2460 "testCancelAllNotificationsImmediatelyAfterEnqueue", 2461 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2462 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2463 waitForIdle(); 2464 StatusBarNotification[] notifs = 2465 mBinderService.getActiveNotifications(sbn.getPackageName()); 2466 assertEquals(0, notifs.length); 2467 assertEquals(0, mService.getNotificationRecordCount()); 2468 } 2469 2470 @Test testUserInitiatedClearAll_noLeak()2471 public void testUserInitiatedClearAll_noLeak() throws Exception { 2472 final NotificationRecord n = generateNotificationRecord( 2473 mTestNotificationChannel, 1, "group", true); 2474 2475 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2476 "testUserInitiatedClearAll_noLeak", 2477 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId()); 2478 waitForIdle(); 2479 2480 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 2481 n.getUserId()); 2482 waitForIdle(); 2483 StatusBarNotification[] notifs = 2484 mBinderService.getActiveNotifications(n.getSbn().getPackageName()); 2485 assertEquals(0, notifs.length); 2486 assertEquals(0, mService.getNotificationRecordCount()); 2487 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 2488 verify(mListeners, times(1)).notifyRemovedLocked(any(), anyInt(), captor.capture()); 2489 assertEquals(NotificationStats.DISMISSAL_OTHER, captor.getValue().getDismissalSurface()); 2490 } 2491 2492 @Test testCancelAllNotificationsCancelsChildren()2493 public void testCancelAllNotificationsCancelsChildren() throws Exception { 2494 final NotificationRecord parent = generateNotificationRecord( 2495 mTestNotificationChannel, 1, "group1", true); 2496 final NotificationRecord child = generateNotificationRecord( 2497 mTestNotificationChannel, 2, "group1", false); 2498 2499 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2500 "testCancelAllNotificationsCancelsChildren", 2501 parent.getSbn().getId(), parent.getSbn().getNotification(), 2502 parent.getSbn().getUserId()); 2503 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2504 "testCancelAllNotificationsCancelsChildren", 2505 child.getSbn().getId(), child.getSbn().getNotification(), 2506 child.getSbn().getUserId()); 2507 waitForIdle(); 2508 2509 mBinderService.cancelAllNotifications(mPkg, parent.getSbn().getUserId()); 2510 waitForIdle(); 2511 assertEquals(0, mService.getNotificationRecordCount()); 2512 } 2513 2514 @Test testCancelAllNotificationsMultipleEnqueuedDoesNotCrash()2515 public void testCancelAllNotificationsMultipleEnqueuedDoesNotCrash() throws Exception { 2516 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 2517 for (int i = 0; i < 10; i++) { 2518 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2519 "testCancelAllNotificationsMultipleEnqueuedDoesNotCrash", 2520 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 2521 } 2522 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 2523 waitForIdle(); 2524 2525 assertEquals(0, mService.getNotificationRecordCount()); 2526 } 2527 2528 @Test testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash()2529 public void testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash() throws Exception { 2530 final NotificationRecord parent = generateNotificationRecord( 2531 mTestNotificationChannel, 1, "group1", true); 2532 final NotificationRecord parentAsChild = generateNotificationRecord( 2533 mTestNotificationChannel, 1, "group1", false); 2534 final NotificationRecord child = generateNotificationRecord( 2535 mTestNotificationChannel, 2, "group1", false); 2536 2537 // fully post parent notification 2538 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2539 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2540 parent.getSbn().getId(), parent.getSbn().getNotification(), 2541 parent.getSbn().getUserId()); 2542 waitForIdle(); 2543 2544 // enqueue the child several times 2545 for (int i = 0; i < 10; i++) { 2546 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2547 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2548 child.getSbn().getId(), child.getSbn().getNotification(), 2549 child.getSbn().getUserId()); 2550 } 2551 // make the parent a child, which will cancel the child notification 2552 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 2553 "testCancelGroupSummaryMultipleEnqueuedChildrenDoesNotCrash", 2554 parentAsChild.getSbn().getId(), parentAsChild.getSbn().getNotification(), 2555 parentAsChild.getSbn().getUserId()); 2556 waitForIdle(); 2557 2558 assertEquals(0, mService.getNotificationRecordCount()); 2559 } 2560 2561 @Test 2562 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationAdded()2563 public void testAutobundledSummary_notificationAdded() { 2564 NotificationRecord summary = 2565 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2566 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2567 mService.addNotification(summary); 2568 mService.mSummaryByGroupKey.put("pkg", summary); 2569 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2570 mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); 2571 2572 mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY, 2573 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, 2574 mock(Icon.class), 0, 2575 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2576 waitForIdle(); 2577 2578 assertTrue(summary.getSbn().isOngoing()); 2579 } 2580 2581 @Test 2582 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationAdded_forcedGrouping()2583 public void testAutobundledSummary_notificationAdded_forcedGrouping() { 2584 NotificationRecord summary = 2585 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2586 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2587 mService.addNotification(summary); 2588 mService.mSummaryByGroupKey.put("pkg", summary); 2589 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2590 mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey()); 2591 2592 mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(), 2593 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, 2594 mock(Icon.class), 0, 2595 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2596 waitForIdle(); 2597 2598 assertTrue(summary.getSbn().isOngoing()); 2599 } 2600 2601 @Test 2602 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationRemoved()2603 public void testAutobundledSummary_notificationRemoved() { 2604 NotificationRecord summary = 2605 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2606 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2607 summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 2608 mService.addNotification(summary); 2609 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2610 mService.mAutobundledSummaries.get(0).put("pkg", summary.getKey()); 2611 mService.mSummaryByGroupKey.put(summary.getGroupKey(), summary); 2612 2613 mService.updateAutobundledSummaryLocked(0, "pkg", AUTOGROUP_KEY, 2614 new NotificationAttributes(GroupHelper.BASE_FLAGS, 2615 mock(Icon.class), 0, 2616 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2617 waitForIdle(); 2618 2619 assertFalse(summary.getSbn().isOngoing()); 2620 } 2621 2622 @Test 2623 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAutobundledSummary_notificationRemoved_forceGrouping()2624 public void testAutobundledSummary_notificationRemoved_forceGrouping() { 2625 NotificationRecord summary = 2626 generateNotificationRecord(mTestNotificationChannel, 0, AUTOGROUP_KEY, true); 2627 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2628 summary.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 2629 mService.addNotification(summary); 2630 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2631 mService.mAutobundledSummaries.get(0).put(summary.getGroupKey(), summary.getKey()); 2632 2633 mService.updateAutobundledSummaryLocked(0, "pkg", summary.getGroupKey(), 2634 new NotificationAttributes(GroupHelper.BASE_FLAGS, 2635 mock(Icon.class), 0, 2636 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID), false); 2637 waitForIdle(); 2638 2639 assertFalse(summary.getSbn().isOngoing()); 2640 } 2641 2642 @Test 2643 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAggregatedSummary_updateSummaryAttributes()2644 public void testAggregatedSummary_updateSummaryAttributes() { 2645 final String aggregateGroupName = "Aggregate_Test"; 2646 final String newChannelId = "newChannelId"; 2647 final NotificationChannel newChannel = new NotificationChannel( 2648 newChannelId, newChannelId, IMPORTANCE_DEFAULT); 2649 mService.setPreferencesHelper(mPreferencesHelper); 2650 final NotificationRecord summary = 2651 generateNotificationRecord(mTestNotificationChannel, 0, aggregateGroupName, true); 2652 final String groupKey = summary.getGroupKey(); 2653 summary.getNotification().flags |= Notification.FLAG_AUTOGROUP_SUMMARY; 2654 mService.addNotification(summary); 2655 mService.mAutobundledSummaries.put(0, new ArrayMap<>()); 2656 mService.mAutobundledSummaries.get(0).put(groupKey, summary.getKey()); 2657 when(mPreferencesHelper.getNotificationChannel(eq("pkg"), anyInt(), 2658 eq(newChannelId), anyBoolean())).thenReturn(newChannel); 2659 2660 mService.updateAutobundledSummaryLocked(0, "pkg", groupKey, 2661 new NotificationAttributes(GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, 2662 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, newChannelId), 2663 false); 2664 waitForIdle(); 2665 2666 assertTrue(summary.getSbn().isOngoing()); 2667 assertThat(summary.getNotification().getGroupAlertBehavior()).isEqualTo( 2668 GROUP_ALERT_CHILDREN); 2669 2670 assertThat(summary.getChannel().getId()).isEqualTo(newChannelId); 2671 } 2672 2673 @Test 2674 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAddAggregateNotification_notifyPostedLocked()2675 public void testAddAggregateNotification_notifyPostedLocked() throws Exception { 2676 final String originalGroupName = "originalGroup"; 2677 final NotificationRecord r = 2678 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 2679 mService.addNotification(r); 2680 mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true); 2681 2682 assertThat(r.getSbn().getOverrideGroupKey()).isEqualTo("grpKey"); 2683 verify(mRankingHandler, times(1)).requestSort(); 2684 verify(mListeners, times(1)).notifyPostedLocked(eq(r), eq(r)); 2685 } 2686 2687 @Test 2688 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testAddAggregateSummaryNotification_convertSummary()2689 public void testAddAggregateSummaryNotification_convertSummary() throws Exception { 2690 final String originalGroupName = "originalGroup"; 2691 final NotificationRecord r = 2692 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 2693 final String groupKey = r.getGroupKey(); 2694 mService.addNotification(r); 2695 assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isTrue(); 2696 boolean isConverted = mService.convertSummaryToNotificationLocked(r.getKey()); 2697 2698 assertThat(isConverted).isTrue(); 2699 assertThat(r.getSbn().isGroup()).isTrue(); 2700 assertThat(r.getNotification().isGroupSummary()).isFalse(); 2701 assertThat(mService.mSummaryByGroupKey.containsKey(groupKey)).isFalse(); 2702 } 2703 2704 @Test 2705 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2706 Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS}) testAggregateGroups_RemoveAppSummary()2707 public void testAggregateGroups_RemoveAppSummary() throws Exception { 2708 final String originalGroupName = "originalGroup"; 2709 final NotificationRecord r = 2710 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 2711 mService.addNotification(r); 2712 mService.removeAppSummaryLocked(r.getKey()); 2713 2714 assertThat(r.isCanceled).isTrue(); 2715 waitForIdle(); 2716 verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(0)); 2717 } 2718 2719 @Test 2720 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION}) testAggregateGroups_RemoveAppSummary_onClassification()2721 public void testAggregateGroups_RemoveAppSummary_onClassification() throws Exception { 2722 final String originalGroupName = "originalGroup"; 2723 final int summaryId = 0; 2724 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 2725 summaryId + 1, originalGroupName, false); 2726 mService.addNotification(r1); 2727 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 2728 summaryId + 2, originalGroupName, false); 2729 mService.addNotification(r2); 2730 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 2731 summaryId, originalGroupName, true); 2732 mService.addNotification(summary); 2733 final String originalGroupKey = summary.getGroupKey(); 2734 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 2735 2736 // Regroup first child notification 2737 r1.setOverrideGroupKey("newGroup"); 2738 // Check that removeAppProvidedSummaryOnClassificationLocked is null 2739 // => there is still one child left in the original group 2740 assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r1.getKey(), 2741 originalGroupKey)).isNull(); 2742 2743 // Regroup last child notification 2744 r2.setOverrideGroupKey("newGroup"); 2745 // Check that removeAppProvidedSummaryOnClassificationLocked returns the original summary 2746 // and that the original app-provided summary is canceled 2747 assertThat(mService.removeAppProvidedSummaryOnClassificationLocked(r2.getKey(), 2748 originalGroupKey)).isEqualTo(summary); 2749 waitForIdle(); 2750 verify(mWorkerHandler, times(1)).scheduleCancelNotification(any(), eq(summaryId)); 2751 assertThat(mService.mSummaryByGroupKey).doesNotContainKey(originalGroupKey); 2752 } 2753 2754 @Test 2755 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testUngroupingAggregateSummary()2756 public void testUngroupingAggregateSummary() throws Exception { 2757 final String originalGroupName = "originalGroup"; 2758 final String aggregateGroupName = "Aggregate_Test"; 2759 final int summaryId = Integer.MAX_VALUE; 2760 // Add 2 group notifications without a summary 2761 NotificationRecord nr0 = 2762 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 2763 NotificationRecord nr1 = 2764 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 2765 mService.addNotification(nr0); 2766 mService.addNotification(nr1); 2767 mService.mSummaryByGroupKey.remove(nr0.getGroupKey()); 2768 2769 // GroupHelper is a mock, so make the calls it would make 2770 // Add aggregate group summary 2771 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 2772 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 2773 nr0.getChannel().getId()); 2774 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 2775 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 2776 mService.addNotification(aggregateSummary); 2777 nr0.setOverrideGroupKey(aggregateGroupName); 2778 nr1.setOverrideGroupKey(aggregateGroupName); 2779 final String fullAggregateGroupKey = nr0.getGroupKey(); 2780 2781 // Check that the aggregate group summary was created 2782 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 2783 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 2784 nr0.getChannel().getId()); 2785 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 2786 2787 // Cancel both children 2788 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(), 2789 nr0.getSbn().getId(), nr0.getSbn().getUserId()); 2790 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(), 2791 nr1.getSbn().getId(), nr1.getSbn().getUserId()); 2792 waitForIdle(); 2793 2794 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any(), eq(false)); 2795 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any(), eq(false)); 2796 2797 // GroupHelper would send 'remove summary' event 2798 mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(), 2799 fullAggregateGroupKey); 2800 waitForIdle(); 2801 2802 // Make sure the summary was removed and not re-posted 2803 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 2804 } 2805 2806 @Test 2807 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2808 Flags.FLAG_NOTIFICATION_FORCE_GROUP_SINGLETONS}) testCancelGroupChildrenForCanceledSummary_singletonGroup()2809 public void testCancelGroupChildrenForCanceledSummary_singletonGroup() throws Exception { 2810 final String originalGroupName = "originalGroup"; 2811 final String aggregateGroupName = "Aggregate_Test"; 2812 final int summaryId = Integer.MAX_VALUE; 2813 // Add a "singleton group" 2814 NotificationRecord nr0 = 2815 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 2816 NotificationRecord nr1 = 2817 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 2818 final NotificationRecord summary = 2819 generateNotificationRecord(mTestNotificationChannel, 2, originalGroupName, true); 2820 final String originalGroupKey = summary.getGroupKey(); 2821 mService.addNotification(nr0); 2822 mService.addNotification(nr1); 2823 mService.addNotification(summary); 2824 2825 // GroupHelper is a mock, so make the calls it would make 2826 // Remove the app's summary notification 2827 mService.removeAppSummaryLocked(summary.getKey()); 2828 waitForIdle(); 2829 2830 // Add aggregate group summary 2831 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 2832 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 2833 nr0.getChannel().getId()); 2834 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 2835 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 2836 mService.addNotification(aggregateSummary); 2837 2838 nr0.setOverrideGroupKey(aggregateGroupName); 2839 nr1.setOverrideGroupKey(aggregateGroupName); 2840 final String fullAggregateGroupKey = nr0.getGroupKey(); 2841 2842 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 2843 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 2844 nr0.getChannel().getId()); 2845 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 2846 assertThat(mService.mSummaryByGroupKey.containsKey(originalGroupKey)).isFalse(); 2847 2848 // Cancel the original app summary (is already removed) 2849 mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(), 2850 summary.getSbn().getPackageName(), summary.getSbn().getTag(), 2851 summary.getSbn().getId(), summary.getSbn().getUserId()); 2852 waitForIdle(); 2853 2854 // Check if NMS.CancelNotificationRunnable calls maybeCancelGroupChildrenForCanceledSummary 2855 verify(mGroupHelper, times(1)).maybeCancelGroupChildrenForCanceledSummary( 2856 eq(summary.getSbn().getPackageName()), eq(summary.getSbn().getTag()), 2857 eq(summary.getSbn().getId()), eq(summary.getSbn().getUserId()), 2858 eq(REASON_APP_CANCEL)); 2859 } 2860 2861 @Test 2862 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testUpdateChannel_notifyGroupHelper()2863 public void testUpdateChannel_notifyGroupHelper() throws Exception { 2864 mService.setPreferencesHelper(mPreferencesHelper); 2865 mTestNotificationChannel.setLightColor(Color.CYAN); 2866 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 2867 eq(mTestNotificationChannel.getId()), anyBoolean())) 2868 .thenReturn(mTestNotificationChannel); 2869 2870 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel); 2871 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2872 waitForIdle(); 2873 2874 verify(mGroupHelper, times(1)).onChannelUpdated(eq(Process.myUserHandle().getIdentifier()), 2875 eq(mPkg), eq(mTestNotificationChannel), any(), any()); 2876 } 2877 2878 @Test 2879 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed()2880 public void testSnoozeRunnable_snoozeAggregateGroupChild_summaryNotSnoozed() throws Exception { 2881 final String aggregateGroupName = "Aggregate_Test"; 2882 2883 // build autogroup summary notification 2884 Notification.Builder nb = new Notification.Builder(mContext, 2885 mTestNotificationChannel.getId()) 2886 .setContentTitle("foo") 2887 .setSmallIcon(android.R.drawable.sym_def_app_icon) 2888 .setGroup(aggregateGroupName) 2889 .setGroupSummary(true) 2890 .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true); 2891 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 2892 "tag" + System.currentTimeMillis(), mUid, 0, nb.build(), 2893 UserHandle.getUserHandleForUid(mUid), null, 0); 2894 final NotificationRecord summary = new NotificationRecord(mContext, sbn, 2895 mTestNotificationChannel); 2896 2897 final NotificationRecord child = generateNotificationRecord( 2898 mTestNotificationChannel, 2, aggregateGroupName, false); 2899 mService.addNotification(summary); 2900 mService.addNotification(child); 2901 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 2902 2903 // snooze child only 2904 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 2905 mService.new SnoozeNotificationRunnable( 2906 child.getKey(), 100, null); 2907 snoozeNotificationRunnable.run(); 2908 2909 // only child should be snoozed 2910 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 2911 2912 // both group summary and child should be cancelled 2913 assertNull(mService.getNotificationRecord(summary.getKey())); 2914 assertNull(mService.getNotificationRecord(child.getKey())); 2915 2916 assertEquals(4, mNotificationRecordLogger.numCalls()); 2917 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 2918 mNotificationRecordLogger.event(0)); 2919 assertEquals( 2920 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 2921 mNotificationRecordLogger.event(1)); 2922 } 2923 2924 @Test 2925 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2926 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testOnlyForceGroupIfNeeded_newNotification_notAutogrouped()2927 public void testOnlyForceGroupIfNeeded_newNotification_notAutogrouped() { 2928 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 2929 when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false); 2930 mService.addEnqueuedNotification(r); 2931 NotificationManagerService.PostNotificationRunnable runnable = 2932 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 2933 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 2934 runnable.run(); 2935 waitForIdle(); 2936 2937 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2938 waitForIdle(); 2939 2940 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 2941 verify(mGroupHelper, times(1)).onNotificationPostedWithDelay(eq(r), any(), any()); 2942 } 2943 2944 @Test 2945 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2946 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped()2947 public void testOnlyForceGroupIfNeeded_newNotification_wasAutogrouped() { 2948 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 2949 when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(true); 2950 mService.addEnqueuedNotification(r); 2951 NotificationManagerService.PostNotificationRunnable runnable = 2952 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 2953 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 2954 runnable.run(); 2955 waitForIdle(); 2956 2957 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2958 waitForIdle(); 2959 2960 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 2961 verify(mGroupHelper, never()).onNotificationPostedWithDelay(eq(r), any(), any()); 2962 } 2963 2964 @Test 2965 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 2966 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testRemoveScheduledForceGroup_onNotificationCanceled()2967 public void testRemoveScheduledForceGroup_onNotificationCanceled() throws Exception { 2968 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "tag", null, 2969 false); 2970 when(mGroupHelper.onNotificationPosted(any(), anyBoolean())).thenReturn(false); 2971 mService.addEnqueuedNotification(r); 2972 NotificationManagerService.PostNotificationRunnable runnable = 2973 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 2974 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 2975 runnable.run(); 2976 waitForIdle(); 2977 2978 // Post an update to the notification 2979 NotificationRecord r_update = 2980 generateNotificationRecord(mTestNotificationChannel, 0, "tag", null, false); 2981 mService.addEnqueuedNotification(r_update); 2982 runnable = mService.new PostNotificationRunnable(r_update.getKey(), 2983 r_update.getSbn().getPackageName(), r_update.getUid(), 2984 mPostNotificationTrackerFactory.newTracker(null)); 2985 runnable.run(); 2986 waitForIdle(); 2987 2988 // Cancel the notification 2989 mBinderService.cancelNotificationWithTag(r.getSbn().getPackageName(), 2990 r.getSbn().getPackageName(), r.getSbn().getTag(), 2991 r.getSbn().getId(), r.getSbn().getUserId()); 2992 waitForIdle(); 2993 2994 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 2995 waitForIdle(); 2996 2997 // Check that onNotificationPostedWithDelay was canceled 2998 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 2999 verify(mGroupHelper, never()).onNotificationPostedWithDelay(any(), any(), any()); 3000 } 3001 3002 @Test 3003 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testEnqueueNotification_forceGrouped_clearsSummaryFlag()3004 public void testEnqueueNotification_forceGrouped_clearsSummaryFlag() throws Exception { 3005 final String originalGroupName = "originalGroup"; 3006 final String aggregateGroupName = "Aggregate_Test"; 3007 3008 // Old record was a summary and it was auto-grouped 3009 final NotificationRecord r = 3010 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 3011 mService.addNotification(r); 3012 mService.convertSummaryToNotificationLocked(r.getKey()); 3013 mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true); 3014 3015 assertThat(mService.mNotificationList).hasSize(1); 3016 3017 // Update record is a summary 3018 final Notification updatedNotification = generateNotificationRecord( 3019 mTestNotificationChannel, 0, originalGroupName, true).getNotification(); 3020 assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY); 3021 3022 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 3023 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId()); 3024 waitForIdle(); 3025 3026 // Check that FLAG_GROUP_SUMMARY was removed 3027 assertThat(mService.mNotificationList).hasSize(1); 3028 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0); 3029 } 3030 3031 @Test 3032 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag()3033 public void testEnqueueNotification_forceGroupedRegular_updatedAsSummary_clearsSummaryFlag() 3034 throws Exception { 3035 final String originalGroupName = "originalGroup"; 3036 final String aggregateGroupName = "Aggregate_Test"; 3037 3038 // Old record was not summary and it was auto-grouped 3039 final NotificationRecord r = 3040 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 3041 mService.addNotification(r); 3042 mService.addAutogroupKeyLocked(r.getKey(), aggregateGroupName, true); 3043 assertThat(mService.mNotificationList).hasSize(1); 3044 3045 // Update record is a summary 3046 final Notification updatedNotification = generateNotificationRecord( 3047 mTestNotificationChannel, 0, originalGroupName, true).getNotification(); 3048 assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY); 3049 3050 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 3051 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId()); 3052 waitForIdle(); 3053 3054 // Check that FLAG_GROUP_SUMMARY was removed 3055 assertThat(mService.mNotificationList).hasSize(1); 3056 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0); 3057 } 3058 3059 @Test 3060 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testEnqueueNotification_notForceGrouped_dontClearSummaryFlag()3061 public void testEnqueueNotification_notForceGrouped_dontClearSummaryFlag() 3062 throws Exception { 3063 final String originalGroupName = "originalGroup"; 3064 3065 // Old record was a summary and it was not auto-grouped 3066 final NotificationRecord r = 3067 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, true); 3068 mService.addNotification(r); 3069 assertThat(mService.mNotificationList).hasSize(1); 3070 3071 // Update record is a summary 3072 final Notification updatedNotification = generateNotificationRecord( 3073 mTestNotificationChannel, 0, originalGroupName, true).getNotification(); 3074 assertThat(updatedNotification.flags & FLAG_GROUP_SUMMARY).isEqualTo(FLAG_GROUP_SUMMARY); 3075 3076 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 3077 r.getSbn().getId(), updatedNotification, r.getSbn().getUserId()); 3078 waitForIdle(); 3079 3080 // Check that FLAG_GROUP_SUMMARY was not removed 3081 assertThat(mService.mNotificationList).hasSize(1); 3082 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo( 3083 FLAG_GROUP_SUMMARY); 3084 } 3085 3086 @Test 3087 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag()3088 public void testRemoveFGSFlagFromNotification_enqueued_forceGrouped_clearsSummaryFlag() { 3089 final String originalGroupName = "originalGroup"; 3090 final String aggregateGroupName = "Aggregate_Test"; 3091 3092 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, 3093 originalGroupName, true); 3094 r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY; 3095 r.setOverrideGroupKey(aggregateGroupName); 3096 mService.addEnqueuedNotification(r); 3097 3098 mInternalService.removeForegroundServiceFlagFromNotification( 3099 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 3100 waitForIdle(); 3101 3102 assertThat(mService.mEnqueuedNotifications).hasSize(1); 3103 assertThat(mService.mEnqueuedNotifications.get(0).getFlags() & FLAG_GROUP_SUMMARY) 3104 .isEqualTo(0); 3105 } 3106 3107 @Test 3108 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag()3109 public void testRemoveFGSFlagFromNotification_posted_forceGrouped_clearsSummaryFlag() { 3110 final String originalGroupName = "originalGroup"; 3111 final String aggregateGroupName = "Aggregate_Test"; 3112 3113 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, 3114 originalGroupName, true); 3115 r.getSbn().getNotification().flags &= ~FLAG_GROUP_SUMMARY; 3116 r.setOverrideGroupKey(aggregateGroupName); 3117 mService.addNotification(r); 3118 3119 mInternalService.removeForegroundServiceFlagFromNotification( 3120 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 3121 waitForIdle(); 3122 3123 assertThat(mService.mNotificationList).hasSize(1); 3124 assertThat(mService.mNotificationList.get(0).getFlags() & FLAG_GROUP_SUMMARY).isEqualTo(0); 3125 } 3126 3127 @Test 3128 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 3129 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testScheduleGroupHelperWithDelay_onChildNotificationCanceled()3130 public void testScheduleGroupHelperWithDelay_onChildNotificationCanceled() throws Exception { 3131 // Post summary + 2 child notification 3132 final String originalGroupName = "originalGroup"; 3133 final int summaryId = 0; 3134 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 3135 summaryId + 1, originalGroupName, false); 3136 mService.addNotification(r1); 3137 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 3138 summaryId + 2, originalGroupName, false); 3139 mService.addNotification(r2); 3140 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 3141 summaryId, originalGroupName, true); 3142 mService.addNotification(summary); 3143 final String originalGroupKey = summary.getGroupKey(); 3144 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 3145 3146 // Cancel the child notifications 3147 mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(), 3148 r1.getSbn().getPackageName(), r1.getSbn().getTag(), 3149 r1.getSbn().getId(), r1.getSbn().getUserId()); 3150 waitForIdle(); 3151 3152 mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(), 3153 r2.getSbn().getPackageName(), r2.getSbn().getTag(), 3154 r2.getSbn().getId(), r2.getSbn().getUserId()); 3155 waitForIdle(); 3156 3157 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 3158 waitForIdle(); 3159 3160 // Check that onGroupedNotificationRemovedWithDelay was called only once 3161 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any(), eq(false)); 3162 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any(), eq(false)); 3163 verify(mGroupHelper, times(1)).onGroupedNotificationRemovedWithDelay(eq(summary), any(), 3164 any()); 3165 } 3166 3167 @Test 3168 @EnableFlags({FLAG_NOTIFICATION_FORCE_GROUPING, 3169 android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST}) testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled()3170 public void testCleanupScheduleGroupHelperWithDelay_onAllNotificationCanceled() 3171 throws Exception { 3172 // Post summary + 2 child notification 3173 final String originalGroupName = "originalGroup"; 3174 final int summaryId = 0; 3175 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 3176 summaryId + 1, originalGroupName, false); 3177 mService.addNotification(r1); 3178 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 3179 summaryId + 2, originalGroupName, false); 3180 mService.addNotification(r2); 3181 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 3182 summaryId, originalGroupName, true); 3183 mService.addNotification(summary); 3184 final String originalGroupKey = summary.getGroupKey(); 3185 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 3186 3187 // Cancel all notifications: children + summary 3188 mBinderService.cancelNotificationWithTag(r1.getSbn().getPackageName(), 3189 r1.getSbn().getPackageName(), r1.getSbn().getTag(), 3190 r1.getSbn().getId(), r1.getSbn().getUserId()); 3191 waitForIdle(); 3192 3193 mBinderService.cancelNotificationWithTag(r2.getSbn().getPackageName(), 3194 r2.getSbn().getPackageName(), r2.getSbn().getTag(), 3195 r2.getSbn().getId(), r2.getSbn().getUserId()); 3196 waitForIdle(); 3197 3198 mBinderService.cancelNotificationWithTag(summary.getSbn().getPackageName(), 3199 summary.getSbn().getPackageName(), summary.getSbn().getTag(), 3200 summary.getSbn().getId(), summary.getSbn().getUserId()); 3201 waitForIdle(); 3202 3203 mTestableLooper.moveTimeForward(DELAY_FORCE_REGROUP_TIME); 3204 waitForIdle(); 3205 3206 // Check that onGroupedNotificationRemovedWithDelay was never called: summary was canceled 3207 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r1), any(), eq(false)); 3208 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(r2), any(), eq(false)); 3209 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(summary), any(), eq(false)); 3210 verify(mGroupHelper, never()).onGroupedNotificationRemovedWithDelay(any(), any(), any()); 3211 } 3212 3213 @Test testCancelAllNotifications_IgnoreForegroundService()3214 public void testCancelAllNotifications_IgnoreForegroundService() throws Exception { 3215 when(mAmi.applyForegroundServiceNotification( 3216 any(), anyString(), anyInt(), anyString(), anyInt())).thenReturn(SHOW_IMMEDIATELY); 3217 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3218 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3219 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3220 "testCancelAllNotifications_IgnoreForegroundService", 3221 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3222 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 3223 waitForIdle(); 3224 StatusBarNotification[] notifs = 3225 mBinderService.getActiveNotifications(sbn.getPackageName()); 3226 assertEquals(1, notifs.length); 3227 assertEquals(1, mService.getNotificationRecordCount()); 3228 } 3229 3230 @Test testCancelAllNotifications_FgsFlag_NoFgs_Allowed()3231 public void testCancelAllNotifications_FgsFlag_NoFgs_Allowed() throws Exception { 3232 when(mAmi.applyForegroundServiceNotification( 3233 any(), anyString(), anyInt(), anyString(), anyInt())) 3234 .thenReturn(NOT_FOREGROUND_SERVICE); 3235 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3236 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3237 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3238 "testCancelAllNotifications_IgnoreForegroundService", 3239 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3240 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 3241 waitForIdle(); 3242 StatusBarNotification[] notifs = 3243 mBinderService.getActiveNotifications(sbn.getPackageName()); 3244 assertEquals(0, notifs.length); 3245 } 3246 3247 @Test testCancelAllNotifications_IgnoreOtherPackages()3248 public void testCancelAllNotifications_IgnoreOtherPackages() throws Exception { 3249 when(mAmi.applyForegroundServiceNotification( 3250 any(), anyString(), anyInt(), anyString(), anyInt())) 3251 .thenReturn(SHOW_IMMEDIATELY); 3252 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3253 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3254 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3255 "testCancelAllNotifications_IgnoreOtherPackages", 3256 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3257 mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); 3258 waitForIdle(); 3259 StatusBarNotification[] notifs = 3260 mBinderService.getActiveNotifications(sbn.getPackageName()); 3261 assertEquals(1, notifs.length); 3262 assertEquals(1, mService.getNotificationRecordCount()); 3263 } 3264 3265 @Test testCancelAllNotifications_NullPkgRemovesAll()3266 public void testCancelAllNotifications_NullPkgRemovesAll() throws Exception { 3267 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3268 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3269 "testCancelAllNotifications_NullPkgRemovesAll", 3270 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3271 mBinderService.cancelAllNotifications(null, sbn.getUserId()); 3272 waitForIdle(); 3273 StatusBarNotification[] notifs = 3274 mBinderService.getActiveNotifications(sbn.getPackageName()); 3275 assertEquals(0, notifs.length); 3276 assertEquals(0, mService.getNotificationRecordCount()); 3277 } 3278 3279 @Test testCancelAllNotifications_NullPkgIgnoresUserAllNotifications()3280 public void testCancelAllNotifications_NullPkgIgnoresUserAllNotifications() throws Exception { 3281 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3282 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3283 "testCancelAllNotifications_NullPkgIgnoresUserAllNotifications", 3284 sbn.getId(), sbn.getNotification(), UserHandle.USER_ALL); 3285 // Null pkg is how we signal a user switch. 3286 mBinderService.cancelAllNotifications(null, sbn.getUserId()); 3287 waitForIdle(); 3288 StatusBarNotification[] notifs = 3289 mBinderService.getActiveNotifications(sbn.getPackageName()); 3290 assertEquals(1, notifs.length); 3291 assertEquals(1, mService.getNotificationRecordCount()); 3292 } 3293 3294 @Test testAppInitiatedCancelAllNotifications_CancelsNoClearFlag()3295 public void testAppInitiatedCancelAllNotifications_CancelsNoClearFlag() throws Exception { 3296 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3297 sbn.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3298 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 3299 "testAppInitiatedCancelAllNotifications_CancelsNoClearFlag", 3300 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3301 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 3302 waitForIdle(); 3303 StatusBarNotification[] notifs = 3304 mBinderService.getActiveNotifications(sbn.getPackageName()); 3305 assertEquals(0, notifs.length); 3306 } 3307 3308 @Test testCancelAllNotifications_CancelsNoClearFlag()3309 public void testCancelAllNotifications_CancelsNoClearFlag() throws Exception { 3310 final NotificationRecord notif = generateNotificationRecord( 3311 mTestNotificationChannel, 1, "group", true); 3312 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3313 mService.addNotification(notif); 3314 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 3315 notif.getUserId(), REASON_CANCEL); 3316 waitForIdle(); 3317 StatusBarNotification[] notifs = 3318 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3319 assertEquals(0, notifs.length); 3320 } 3321 3322 @Test testUserInitiatedCancelAllOnClearAll_NoClearFlag()3323 public void testUserInitiatedCancelAllOnClearAll_NoClearFlag() throws Exception { 3324 final NotificationRecord notif = generateNotificationRecord( 3325 mTestNotificationChannel, 1, "group", true); 3326 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 3327 mService.addNotification(notif); 3328 3329 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 3330 notif.getUserId()); 3331 waitForIdle(); 3332 StatusBarNotification[] notifs = 3333 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3334 assertEquals(1, notifs.length); 3335 } 3336 3337 @Test testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue()3338 public void testRemoveForegroundServiceFlag_ImmediatelyAfterEnqueue() throws Exception { 3339 when(mAmi.applyForegroundServiceNotification( 3340 any(), anyString(), anyInt(), anyString(), anyInt())) 3341 .thenReturn(SHOW_IMMEDIATELY); 3342 Notification n = 3343 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 3344 .setSmallIcon(android.R.drawable.sym_def_app_icon) 3345 .build(); 3346 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, 3347 n, UserHandle.getUserHandleForUid(mUid), null, 0); 3348 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3349 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null, 3350 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3351 mInternalService.removeForegroundServiceFlagFromNotification(mPkg, sbn.getId(), 3352 sbn.getUserId()); 3353 waitForIdle(); 3354 StatusBarNotification[] notifs = 3355 mBinderService.getActiveNotifications(sbn.getPackageName()); 3356 assertEquals(0, notifs[0].getNotification().flags & FLAG_FOREGROUND_SERVICE); 3357 } 3358 3359 @Test testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag()3360 public void testCancelAfterSecondEnqueueDoesNotSpecifyForegroundFlag() throws Exception { 3361 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 3362 sbn.getNotification().flags = 3363 Notification.FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE; 3364 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 3365 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3366 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; 3367 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 3368 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 3369 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3370 sbn.getUserId()); 3371 waitForIdle(); 3372 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 3373 assertEquals(0, mService.getNotificationRecordCount()); 3374 } 3375 3376 @Test 3377 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelWithTagDoesNotCancelLifetimeExtended()3378 public void testCancelWithTagDoesNotCancelLifetimeExtended() throws Exception { 3379 final NotificationRecord notif = generateNotificationRecord(null); 3380 notif.getSbn().getNotification().flags = 3381 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3382 mService.addNotification(notif); 3383 final StatusBarNotification sbn = notif.getSbn(); 3384 3385 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3386 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3387 3388 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3389 sbn.getUserId()); 3390 waitForIdle(); 3391 3392 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3393 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3394 3395 // Checks that a post update is sent. 3396 verify(mWorkerHandler, times(1)) 3397 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3398 ArgumentCaptor<NotificationRecord> captor = 3399 ArgumentCaptor.forClass(NotificationRecord.class); 3400 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3401 anyBoolean()); 3402 assertThat(captor.getValue().getNotification().flags 3403 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3404 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3405 } 3406 3407 @Test 3408 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testMultipleCancelOfLifetimeExtendedSendsOneUpdate()3409 public void testMultipleCancelOfLifetimeExtendedSendsOneUpdate() throws Exception { 3410 final NotificationRecord notif = generateNotificationRecord(null); 3411 notif.getSbn().getNotification().flags = 3412 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3413 mService.addNotification(notif); 3414 final StatusBarNotification sbn = notif.getSbn(); 3415 3416 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3417 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3418 3419 // Send two cancelations. 3420 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3421 sbn.getUserId()); 3422 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 3423 sbn.getUserId()); 3424 waitForIdle(); 3425 3426 assertThat(mBinderService.getActiveNotifications(sbn.getPackageName()).length).isEqualTo(1); 3427 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 3428 3429 // Checks that only one post update is sent. 3430 verify(mWorkerHandler, times(1)) 3431 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3432 ArgumentCaptor<NotificationRecord> captor = 3433 ArgumentCaptor.forClass(NotificationRecord.class); 3434 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3435 anyBoolean()); 3436 assertThat(captor.getValue().getNotification().flags 3437 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3438 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3439 } 3440 3441 @Test 3442 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelAllClearsLifetimeExtended()3443 public void testCancelAllClearsLifetimeExtended() throws Exception { 3444 final NotificationRecord notif = generateNotificationRecord( 3445 mTestNotificationChannel, 1, "group", true); 3446 notif.getNotification().flags |= Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3447 mService.addNotification(notif); 3448 StatusBarNotification[] notifs = 3449 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3450 assertThat(notifs.length).isEqualTo(1); 3451 3452 // Simulate a "cancel all" received. 3453 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 3454 notif.getUserId()); 3455 waitForIdle(); 3456 notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3457 assertThat(notifs.length).isEqualTo(0); 3458 3459 // Test that no update post is sent to System UI. 3460 verify(mWorkerHandler, never()) 3461 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 3462 } 3463 3464 @Test 3465 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testAppCancelAllDoesNotCancelLifetimeExtended()3466 public void testAppCancelAllDoesNotCancelLifetimeExtended() throws Exception { 3467 // Adds a lifetime extended notification. 3468 final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1, 3469 null, false); 3470 notif.getSbn().getNotification().flags = 3471 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3472 mService.addNotification(notif); 3473 // Adds a second, non-lifetime extended notification. 3474 final NotificationRecord notifCancelable = generateNotificationRecord( 3475 mTestNotificationChannel, 2, null, false); 3476 mService.addNotification(notifCancelable); 3477 // Verify that both notifications have been posted and are active. 3478 assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(2); 3479 3480 mBinderService.cancelAllNotifications(mPkg, notif.getSbn().getUserId()); 3481 waitForIdle(); 3482 3483 // The non-lifetime extended notification, with id = 2, has been cancelled. 3484 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 3485 assertThat(notifs.length).isEqualTo(1); 3486 assertThat(notifs[0].getId()).isEqualTo(1); 3487 3488 // Checks that a post update is sent. 3489 verify(mWorkerHandler, times(1)) 3490 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3491 ArgumentCaptor<NotificationRecord> captor = 3492 ArgumentCaptor.forClass(NotificationRecord.class); 3493 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3494 anyBoolean()); 3495 assertThat(captor.getValue().getNotification().flags 3496 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3497 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3498 } 3499 3500 @Test 3501 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testLifetimeExtendedCancelledOnClick()3502 public void testLifetimeExtendedCancelledOnClick() throws Exception { 3503 // Adds a lifetime extended notification. 3504 final NotificationRecord notif = generateNotificationRecord(mTestNotificationChannel, 1, 3505 null, false); 3506 notif.getSbn().getNotification().flags = 3507 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3508 mService.addNotification(notif); 3509 // Verify that the notification is posted and active. 3510 assertThat(mBinderService.getActiveNotifications(mPkg).length).isEqualTo(1); 3511 3512 // Click the notification. 3513 final NotificationVisibility nv = NotificationVisibility.obtain(notif.getKey(), 1, 2, true); 3514 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 3515 notif.getKey(), nv); 3516 waitForIdle(); 3517 3518 // The notification has been cancelled. 3519 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 3520 assertThat(notifs.length).isEqualTo(0); 3521 } 3522 3523 @Test testCancelNotificationWithTag_fromApp_cannotCancelFgsChild()3524 public void testCancelNotificationWithTag_fromApp_cannotCancelFgsChild() 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 final NotificationRecord child = generateNotificationRecord( 3534 mTestNotificationChannel, 2, "group", false); 3535 final NotificationRecord child2 = generateNotificationRecord( 3536 mTestNotificationChannel, 3, "group", false); 3537 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 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(1, notifs.length); 3548 } 3549 3550 @Test testCancelNotificationWithTag_fromApp_cannotCancelFgsParent()3551 public void testCancelNotificationWithTag_fromApp_cannotCancelFgsParent() 3552 throws Exception { 3553 when(mAmi.applyForegroundServiceNotification( 3554 any(), anyString(), anyInt(), anyString(), anyInt())) 3555 .thenReturn(SHOW_IMMEDIATELY); 3556 mService.isSystemUid = false; 3557 mService.isSystemAppId = false; 3558 final NotificationRecord parent = generateNotificationRecord( 3559 mTestNotificationChannel, 1, "group", true); 3560 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3561 final NotificationRecord child = generateNotificationRecord( 3562 mTestNotificationChannel, 2, "group", false); 3563 final NotificationRecord child2 = generateNotificationRecord( 3564 mTestNotificationChannel, 3, "group", false); 3565 mService.addNotification(parent); 3566 mService.addNotification(child); 3567 mService.addNotification(child2); 3568 mService.getBinderService().cancelNotificationWithTag( 3569 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 3570 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 3571 waitForIdle(); 3572 StatusBarNotification[] notifs = 3573 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3574 assertEquals(3, notifs.length); 3575 } 3576 3577 @Test testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild()3578 public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearChild() 3579 throws Exception { 3580 mService.isSystemUid = false; 3581 mService.isSystemAppId = false; 3582 final NotificationRecord parent = generateNotificationRecord( 3583 mTestNotificationChannel, 1, "group", true); 3584 final NotificationRecord child = generateNotificationRecord( 3585 mTestNotificationChannel, 2, "group", false); 3586 final NotificationRecord child2 = generateNotificationRecord( 3587 mTestNotificationChannel, 3, "group", false); 3588 child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3589 mService.addNotification(parent); 3590 mService.addNotification(child); 3591 mService.addNotification(child2); 3592 mService.getBinderService().cancelNotificationWithTag( 3593 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 3594 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 3595 waitForIdle(); 3596 StatusBarNotification[] notifs = 3597 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3598 assertEquals(0, notifs.length); 3599 } 3600 3601 @Test testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent()3602 public void testCancelNotificationWithTag_fromApp_canCancelOngoingNoClearParent() 3603 throws Exception { 3604 mService.isSystemUid = false; 3605 mService.isSystemAppId = false; 3606 final NotificationRecord parent = generateNotificationRecord( 3607 mTestNotificationChannel, 1, "group", true); 3608 parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3609 final NotificationRecord child = generateNotificationRecord( 3610 mTestNotificationChannel, 2, "group", false); 3611 final NotificationRecord child2 = generateNotificationRecord( 3612 mTestNotificationChannel, 3, "group", false); 3613 mService.addNotification(parent); 3614 mService.addNotification(child); 3615 mService.addNotification(child2); 3616 mService.getBinderService().cancelNotificationWithTag( 3617 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 3618 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 3619 waitForIdle(); 3620 StatusBarNotification[] notifs = 3621 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3622 assertEquals(0, notifs.length); 3623 } 3624 3625 @Test testCancelAllNotificationsFromApp_cannotCancelFgsChild()3626 public void testCancelAllNotificationsFromApp_cannotCancelFgsChild() 3627 throws Exception { 3628 when(mAmi.applyForegroundServiceNotification( 3629 any(), anyString(), anyInt(), anyString(), anyInt())) 3630 .thenReturn(SHOW_IMMEDIATELY); 3631 mService.isSystemUid = false; 3632 mService.isSystemAppId = false; 3633 final NotificationRecord parent = generateNotificationRecord( 3634 mTestNotificationChannel, 1, "group", true); 3635 final NotificationRecord child = generateNotificationRecord( 3636 mTestNotificationChannel, 2, "group", false); 3637 final NotificationRecord child2 = generateNotificationRecord( 3638 mTestNotificationChannel, 3, "group", false); 3639 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3640 final NotificationRecord newGroup = generateNotificationRecord( 3641 mTestNotificationChannel, 4, "group2", false); 3642 mService.addNotification(parent); 3643 mService.addNotification(child); 3644 mService.addNotification(child2); 3645 mService.addNotification(newGroup); 3646 mService.getBinderService().cancelAllNotifications( 3647 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3648 waitForIdle(); 3649 StatusBarNotification[] notifs = 3650 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3651 assertEquals(1, notifs.length); 3652 } 3653 3654 @Test testCancelAllNotifications_fromApp_cannotCancelFgsParent()3655 public void testCancelAllNotifications_fromApp_cannotCancelFgsParent() 3656 throws Exception { 3657 when(mAmi.applyForegroundServiceNotification( 3658 any(), anyString(), anyInt(), anyString(), anyInt())) 3659 .thenReturn(SHOW_IMMEDIATELY); 3660 mService.isSystemUid = false; 3661 mService.isSystemAppId = false; 3662 final NotificationRecord parent = generateNotificationRecord( 3663 mTestNotificationChannel, 1, "group", true); 3664 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3665 final NotificationRecord child = generateNotificationRecord( 3666 mTestNotificationChannel, 2, "group", false); 3667 final NotificationRecord child2 = generateNotificationRecord( 3668 mTestNotificationChannel, 3, "group", false); 3669 final NotificationRecord newGroup = generateNotificationRecord( 3670 mTestNotificationChannel, 4, "group2", false); 3671 mService.addNotification(parent); 3672 mService.addNotification(child); 3673 mService.addNotification(child2); 3674 mService.addNotification(newGroup); 3675 mService.getBinderService().cancelAllNotifications( 3676 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3677 waitForIdle(); 3678 StatusBarNotification[] notifs = 3679 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3680 assertEquals(1, notifs.length); 3681 } 3682 3683 @Test testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild()3684 public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearChild() 3685 throws Exception { 3686 mService.isSystemUid = false; 3687 mService.isSystemAppId = false; 3688 final NotificationRecord parent = generateNotificationRecord( 3689 mTestNotificationChannel, 1, "group", true); 3690 final NotificationRecord child = generateNotificationRecord( 3691 mTestNotificationChannel, 2, "group", false); 3692 final NotificationRecord child2 = generateNotificationRecord( 3693 mTestNotificationChannel, 3, "group", false); 3694 child2.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3695 final NotificationRecord newGroup = generateNotificationRecord( 3696 mTestNotificationChannel, 4, "group2", false); 3697 mService.addNotification(parent); 3698 mService.addNotification(child); 3699 mService.addNotification(child2); 3700 mService.addNotification(newGroup); 3701 mService.getBinderService().cancelAllNotifications( 3702 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3703 waitForIdle(); 3704 StatusBarNotification[] notifs = 3705 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3706 assertEquals(0, notifs.length); 3707 } 3708 3709 @Test testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent()3710 public void testCancelAllNotifications_fromApp_canCancelOngoingNoClearParent() 3711 throws Exception { 3712 mService.isSystemUid = false; 3713 mService.isSystemAppId = false; 3714 final NotificationRecord parent = generateNotificationRecord( 3715 mTestNotificationChannel, 1, "group", true); 3716 parent.getNotification().flags |= FLAG_ONGOING_EVENT | FLAG_NO_CLEAR; 3717 final NotificationRecord child = generateNotificationRecord( 3718 mTestNotificationChannel, 2, "group", false); 3719 final NotificationRecord child2 = generateNotificationRecord( 3720 mTestNotificationChannel, 3, "group", false); 3721 final NotificationRecord newGroup = generateNotificationRecord( 3722 mTestNotificationChannel, 4, "group2", false); 3723 mService.addNotification(parent); 3724 mService.addNotification(child); 3725 mService.addNotification(child2); 3726 mService.addNotification(newGroup); 3727 mService.getBinderService().cancelAllNotifications( 3728 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 3729 waitForIdle(); 3730 StatusBarNotification[] notifs = 3731 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3732 assertEquals(0, notifs.length); 3733 } 3734 3735 @Test testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent()3736 public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingParent() 3737 throws Exception { 3738 final NotificationRecord parent = generateNotificationRecord( 3739 mTestNotificationChannel, 1, "group", true); 3740 parent.getNotification().flags |= FLAG_ONGOING_EVENT; 3741 final NotificationRecord child = generateNotificationRecord( 3742 mTestNotificationChannel, 2, "group", false); 3743 final NotificationRecord child2 = generateNotificationRecord( 3744 mTestNotificationChannel, 3, "group", false); 3745 final NotificationRecord newGroup = generateNotificationRecord( 3746 mTestNotificationChannel, 4, "group2", false); 3747 mService.addNotification(parent); 3748 mService.addNotification(child); 3749 mService.addNotification(child2); 3750 mService.addNotification(newGroup); 3751 mService.getBinderService().cancelNotificationsFromListener(null, null); 3752 waitForIdle(); 3753 StatusBarNotification[] notifs = 3754 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3755 assertEquals(1, notifs.length); 3756 } 3757 3758 @Test testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild()3759 public void testCancelNotificationsFromListener_clearAll_GroupWithOngoingChild() 3760 throws Exception { 3761 final NotificationRecord parent = generateNotificationRecord( 3762 mTestNotificationChannel, 1, "group", true); 3763 final NotificationRecord child = generateNotificationRecord( 3764 mTestNotificationChannel, 2, "group", false); 3765 final NotificationRecord child2 = generateNotificationRecord( 3766 mTestNotificationChannel, 3, "group", false); 3767 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3768 final NotificationRecord newGroup = generateNotificationRecord( 3769 mTestNotificationChannel, 4, "group2", false); 3770 mService.addNotification(parent); 3771 mService.addNotification(child); 3772 mService.addNotification(child2); 3773 mService.addNotification(newGroup); 3774 mService.getBinderService().cancelNotificationsFromListener(null, null); 3775 waitForIdle(); 3776 StatusBarNotification[] notifs = 3777 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3778 assertEquals(1, notifs.length); 3779 } 3780 3781 @Test testCancelNotificationsFromListener_clearAll_GroupWithFgsParent()3782 public void testCancelNotificationsFromListener_clearAll_GroupWithFgsParent() 3783 throws Exception { 3784 when(mAmi.applyForegroundServiceNotification( 3785 any(), anyString(), anyInt(), anyString(), anyInt())) 3786 .thenReturn(SHOW_IMMEDIATELY); 3787 final NotificationRecord parent = generateNotificationRecord( 3788 mTestNotificationChannel, 1, "group", true); 3789 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3790 final NotificationRecord child = generateNotificationRecord( 3791 mTestNotificationChannel, 2, "group", false); 3792 final NotificationRecord child2 = generateNotificationRecord( 3793 mTestNotificationChannel, 3, "group", false); 3794 final NotificationRecord newGroup = generateNotificationRecord( 3795 mTestNotificationChannel, 4, "group2", false); 3796 mService.addNotification(parent); 3797 mService.addNotification(child); 3798 mService.addNotification(child2); 3799 mService.addNotification(newGroup); 3800 mService.getBinderService().cancelNotificationsFromListener(null, null); 3801 waitForIdle(); 3802 StatusBarNotification[] notifs = 3803 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3804 assertEquals(0, notifs.length); 3805 } 3806 3807 @Test testCancelNotificationsFromListener_clearAll_GroupWithFgsChild()3808 public void testCancelNotificationsFromListener_clearAll_GroupWithFgsChild() 3809 throws Exception { 3810 when(mAmi.applyForegroundServiceNotification( 3811 any(), anyString(), anyInt(), anyString(), anyInt())) 3812 .thenReturn(SHOW_IMMEDIATELY); 3813 final NotificationRecord parent = generateNotificationRecord( 3814 mTestNotificationChannel, 1, "group", true); 3815 final NotificationRecord child = generateNotificationRecord( 3816 mTestNotificationChannel, 2, "group", false); 3817 final NotificationRecord child2 = generateNotificationRecord( 3818 mTestNotificationChannel, 3, "group", false); 3819 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3820 final NotificationRecord newGroup = generateNotificationRecord( 3821 mTestNotificationChannel, 4, "group2", false); 3822 mService.addNotification(parent); 3823 mService.addNotification(child); 3824 mService.addNotification(child2); 3825 mService.addNotification(newGroup); 3826 mService.getBinderService().cancelNotificationsFromListener(null, null); 3827 waitForIdle(); 3828 StatusBarNotification[] notifs = 3829 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3830 assertEquals(0, notifs.length); 3831 } 3832 3833 @Test testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent()3834 public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearParent() 3835 throws Exception { 3836 final NotificationRecord parent = generateNotificationRecord( 3837 mTestNotificationChannel, 1, "group", true); 3838 parent.getNotification().flags |= FLAG_NO_CLEAR; 3839 final NotificationRecord child = generateNotificationRecord( 3840 mTestNotificationChannel, 2, "group", false); 3841 final NotificationRecord child2 = generateNotificationRecord( 3842 mTestNotificationChannel, 3, "group", false); 3843 final NotificationRecord newGroup = generateNotificationRecord( 3844 mTestNotificationChannel, 4, "group2", false); 3845 mService.addNotification(parent); 3846 mService.addNotification(child); 3847 mService.addNotification(child2); 3848 mService.addNotification(newGroup); 3849 mService.getBinderService().cancelNotificationsFromListener(null, null); 3850 waitForIdle(); 3851 StatusBarNotification[] notifs = 3852 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3853 assertEquals(1, notifs.length); 3854 } 3855 3856 @Test testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild()3857 public void testCancelNotificationsFromListener_clearAll_GroupWithNoClearChild() 3858 throws Exception { 3859 final NotificationRecord parent = generateNotificationRecord( 3860 mTestNotificationChannel, 1, "group", true); 3861 final NotificationRecord child = generateNotificationRecord( 3862 mTestNotificationChannel, 2, "group", false); 3863 final NotificationRecord child2 = generateNotificationRecord( 3864 mTestNotificationChannel, 3, "group", false); 3865 child2.getNotification().flags |= FLAG_NO_CLEAR; 3866 final NotificationRecord newGroup = generateNotificationRecord( 3867 mTestNotificationChannel, 4, "group2", false); 3868 mService.addNotification(parent); 3869 mService.addNotification(child); 3870 mService.addNotification(child2); 3871 mService.addNotification(newGroup); 3872 mService.getBinderService().cancelNotificationsFromListener(null, null); 3873 waitForIdle(); 3874 StatusBarNotification[] notifs = 3875 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3876 assertEquals(1, notifs.length); 3877 } 3878 3879 @Test testCancelNotificationsFromListener_clearAll_Ongoing()3880 public void testCancelNotificationsFromListener_clearAll_Ongoing() 3881 throws Exception { 3882 final NotificationRecord child2 = generateNotificationRecord( 3883 mTestNotificationChannel, 3, null, false); 3884 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3885 mService.addNotification(child2); 3886 String[] keys = {child2.getSbn().getKey()}; 3887 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3888 waitForIdle(); 3889 StatusBarNotification[] notifs = 3890 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3891 assertEquals(1, notifs.length); 3892 } 3893 3894 @Test testCancelNotificationsFromListener_clearAll_NoClear()3895 public void testCancelNotificationsFromListener_clearAll_NoClear() 3896 throws Exception { 3897 final NotificationRecord child2 = generateNotificationRecord( 3898 mTestNotificationChannel, 3, null, false); 3899 child2.getNotification().flags |= FLAG_NO_CLEAR; 3900 mService.addNotification(child2); 3901 mService.getBinderService().cancelNotificationsFromListener(null, null); 3902 waitForIdle(); 3903 StatusBarNotification[] notifs = 3904 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3905 assertEquals(1, notifs.length); 3906 } 3907 3908 @Test testCancelNotificationsFromListener_clearAll_Fgs()3909 public void testCancelNotificationsFromListener_clearAll_Fgs() 3910 throws Exception { 3911 when(mAmi.applyForegroundServiceNotification( 3912 any(), anyString(), anyInt(), anyString(), anyInt())) 3913 .thenReturn(SHOW_IMMEDIATELY); 3914 final NotificationRecord child2 = generateNotificationRecord( 3915 mTestNotificationChannel, 3, null, false); 3916 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 3917 mService.addNotification(child2); 3918 mService.getBinderService().cancelNotificationsFromListener(null, null); 3919 waitForIdle(); 3920 StatusBarNotification[] notifs = 3921 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 3922 assertEquals(0, notifs.length); 3923 } 3924 3925 @Test 3926 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt()3927 public void testCancelNotificationsFromListener_clearAll_NoClearLifetimeExt() 3928 throws Exception { 3929 final NotificationRecord notif = generateNotificationRecord( 3930 mTestNotificationChannel, 1, null, false); 3931 notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 3932 mService.addNotification(notif); 3933 verify(mWorkerHandler, times(0)) 3934 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3935 mService.getBinderService().cancelNotificationsFromListener(null, null); 3936 waitForIdle(); 3937 // Notification not cancelled. 3938 StatusBarNotification[] notifs = 3939 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 3940 assertThat(notifs.length).isEqualTo(1); 3941 3942 // Checks that a post update is sent. 3943 verify(mWorkerHandler, times(1)) 3944 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 3945 ArgumentCaptor<NotificationRecord> captor = 3946 ArgumentCaptor.forClass(NotificationRecord.class); 3947 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 3948 anyBoolean()); 3949 assertThat(captor.getValue().getNotification().flags 3950 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 3951 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 3952 } 3953 3954 @Test testCancelNotificationsFromListener_byKey_GroupWithOngoingParent()3955 public void testCancelNotificationsFromListener_byKey_GroupWithOngoingParent() 3956 throws Exception { 3957 final NotificationRecord parent = generateNotificationRecord( 3958 mTestNotificationChannel, 1, "group", true); 3959 parent.getNotification().flags |= FLAG_ONGOING_EVENT; 3960 final NotificationRecord child = generateNotificationRecord( 3961 mTestNotificationChannel, 2, "group", false); 3962 final NotificationRecord child2 = generateNotificationRecord( 3963 mTestNotificationChannel, 3, "group", false); 3964 final NotificationRecord newGroup = generateNotificationRecord( 3965 mTestNotificationChannel, 4, "group2", false); 3966 mService.addNotification(parent); 3967 mService.addNotification(child); 3968 mService.addNotification(child2); 3969 mService.addNotification(newGroup); 3970 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3971 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3972 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3973 waitForIdle(); 3974 StatusBarNotification[] notifs = 3975 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 3976 assertEquals(1, notifs.length); 3977 } 3978 3979 @Test testCancelNotificationsFromListener_byKey_GroupWithOngoingChild()3980 public void testCancelNotificationsFromListener_byKey_GroupWithOngoingChild() 3981 throws Exception { 3982 final NotificationRecord parent = generateNotificationRecord( 3983 mTestNotificationChannel, 1, "group", true); 3984 final NotificationRecord child = generateNotificationRecord( 3985 mTestNotificationChannel, 2, "group", false); 3986 final NotificationRecord child2 = generateNotificationRecord( 3987 mTestNotificationChannel, 3, "group", false); 3988 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 3989 final NotificationRecord newGroup = generateNotificationRecord( 3990 mTestNotificationChannel, 4, "group2", false); 3991 mService.addNotification(parent); 3992 mService.addNotification(child); 3993 mService.addNotification(child2); 3994 mService.addNotification(newGroup); 3995 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 3996 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 3997 mService.getBinderService().cancelNotificationsFromListener(null, keys); 3998 waitForIdle(); 3999 StatusBarNotification[] notifs = 4000 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4001 assertEquals(1, notifs.length); 4002 } 4003 4004 @Test testCancelNotificationsFromListener_byKey_GroupWithFgsParent()4005 public void testCancelNotificationsFromListener_byKey_GroupWithFgsParent() 4006 throws Exception { 4007 when(mAmi.applyForegroundServiceNotification( 4008 any(), anyString(), anyInt(), anyString(), anyInt())) 4009 .thenReturn(SHOW_IMMEDIATELY); 4010 final NotificationRecord parent = generateNotificationRecord( 4011 mTestNotificationChannel, 1, "group", true); 4012 parent.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 4013 final NotificationRecord child = generateNotificationRecord( 4014 mTestNotificationChannel, 2, "group", false); 4015 final NotificationRecord child2 = generateNotificationRecord( 4016 mTestNotificationChannel, 3, "group", false); 4017 final NotificationRecord newGroup = generateNotificationRecord( 4018 mTestNotificationChannel, 4, "group2", false); 4019 mService.addNotification(parent); 4020 mService.addNotification(child); 4021 mService.addNotification(child2); 4022 mService.addNotification(newGroup); 4023 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 4024 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 4025 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4026 waitForIdle(); 4027 StatusBarNotification[] notifs = 4028 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4029 assertEquals(0, notifs.length); 4030 } 4031 4032 @Test testCancelNotificationsFromListener_byKey_GroupWithFgsChild()4033 public void testCancelNotificationsFromListener_byKey_GroupWithFgsChild() 4034 throws Exception { 4035 when(mAmi.applyForegroundServiceNotification( 4036 any(), anyString(), anyInt(), anyString(), anyInt())) 4037 .thenReturn(SHOW_IMMEDIATELY); 4038 final NotificationRecord parent = generateNotificationRecord( 4039 mTestNotificationChannel, 1, "group", true); 4040 final NotificationRecord child = generateNotificationRecord( 4041 mTestNotificationChannel, 2, "group", false); 4042 final NotificationRecord child2 = generateNotificationRecord( 4043 mTestNotificationChannel, 3, "group", false); 4044 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 4045 final NotificationRecord newGroup = generateNotificationRecord( 4046 mTestNotificationChannel, 4, "group2", false); 4047 mService.addNotification(parent); 4048 mService.addNotification(child); 4049 mService.addNotification(child2); 4050 mService.addNotification(newGroup); 4051 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 4052 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 4053 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4054 waitForIdle(); 4055 StatusBarNotification[] notifs = 4056 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4057 assertEquals(0, notifs.length); 4058 } 4059 4060 @Test testCancelNotificationsFromListener_byKey_GroupWithNoClearParent()4061 public void testCancelNotificationsFromListener_byKey_GroupWithNoClearParent() 4062 throws Exception { 4063 final NotificationRecord parent = generateNotificationRecord( 4064 mTestNotificationChannel, 1, "group", true); 4065 parent.getNotification().flags |= FLAG_NO_CLEAR; 4066 final NotificationRecord child = generateNotificationRecord( 4067 mTestNotificationChannel, 2, "group", false); 4068 final NotificationRecord child2 = generateNotificationRecord( 4069 mTestNotificationChannel, 3, "group", false); 4070 final NotificationRecord newGroup = generateNotificationRecord( 4071 mTestNotificationChannel, 4, "group2", false); 4072 mService.addNotification(parent); 4073 mService.addNotification(child); 4074 mService.addNotification(child2); 4075 mService.addNotification(newGroup); 4076 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 4077 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 4078 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4079 waitForIdle(); 4080 StatusBarNotification[] notifs = 4081 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4082 assertEquals(0, notifs.length); 4083 } 4084 4085 @Test testCancelNotificationsFromListener_byKey_GroupWithNoClearChild()4086 public void testCancelNotificationsFromListener_byKey_GroupWithNoClearChild() 4087 throws Exception { 4088 final NotificationRecord parent = generateNotificationRecord( 4089 mTestNotificationChannel, 1, "group", true); 4090 final NotificationRecord child = generateNotificationRecord( 4091 mTestNotificationChannel, 2, "group", false); 4092 final NotificationRecord child2 = generateNotificationRecord( 4093 mTestNotificationChannel, 3, "group", false); 4094 child2.getNotification().flags |= FLAG_NO_CLEAR; 4095 final NotificationRecord newGroup = generateNotificationRecord( 4096 mTestNotificationChannel, 4, "group2", false); 4097 mService.addNotification(parent); 4098 mService.addNotification(child); 4099 mService.addNotification(child2); 4100 mService.addNotification(newGroup); 4101 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 4102 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 4103 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4104 waitForIdle(); 4105 StatusBarNotification[] notifs = 4106 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4107 assertEquals(0, notifs.length); 4108 } 4109 4110 @Test testCancelNotificationsFromListener_byKey_Ongoing()4111 public void testCancelNotificationsFromListener_byKey_Ongoing() 4112 throws Exception { 4113 final NotificationRecord child2 = generateNotificationRecord( 4114 mTestNotificationChannel, 3, null, false); 4115 child2.getNotification().flags |= FLAG_ONGOING_EVENT; 4116 mService.addNotification(child2); 4117 String[] keys = {child2.getSbn().getKey()}; 4118 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4119 waitForIdle(); 4120 StatusBarNotification[] notifs = 4121 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 4122 assertEquals(1, notifs.length); 4123 } 4124 4125 @Test testCancelNotificationsFromListener_byKey_NoClear()4126 public void testCancelNotificationsFromListener_byKey_NoClear() 4127 throws Exception { 4128 final NotificationRecord child2 = generateNotificationRecord( 4129 mTestNotificationChannel, 3, null, false); 4130 child2.getNotification().flags |= FLAG_NO_CLEAR; 4131 mService.addNotification(child2); 4132 String[] keys = {child2.getSbn().getKey()}; 4133 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4134 waitForIdle(); 4135 StatusBarNotification[] notifs = 4136 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 4137 assertEquals(0, notifs.length); 4138 } 4139 4140 @Test testCancelNotificationsFromListener_byKey_Fgs()4141 public void testCancelNotificationsFromListener_byKey_Fgs() 4142 throws Exception { 4143 when(mAmi.applyForegroundServiceNotification( 4144 any(), anyString(), anyInt(), anyString(), anyInt())) 4145 .thenReturn(SHOW_IMMEDIATELY); 4146 final NotificationRecord child2 = generateNotificationRecord( 4147 mTestNotificationChannel, 3, null, false); 4148 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 4149 mService.addNotification(child2); 4150 String[] keys = {child2.getSbn().getKey()}; 4151 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4152 waitForIdle(); 4153 StatusBarNotification[] notifs = 4154 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 4155 assertEquals(0, notifs.length); 4156 } 4157 4158 @Test 4159 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testCancelNotificationsFromListener_byKey_NoClearLifetimeExt()4160 public void testCancelNotificationsFromListener_byKey_NoClearLifetimeExt() 4161 throws Exception { 4162 final NotificationRecord notif = generateNotificationRecord( 4163 mTestNotificationChannel, 3, null, false); 4164 notif.getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 4165 mService.addNotification(notif); 4166 String[] keys = {notif.getSbn().getKey()}; 4167 mService.getBinderService().cancelNotificationsFromListener(null, keys); 4168 waitForIdle(); 4169 StatusBarNotification[] notifs = 4170 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 4171 assertEquals(1, notifs.length); 4172 4173 // Checks that a post update is sent. 4174 verify(mWorkerHandler, times(1)) 4175 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 4176 ArgumentCaptor<NotificationRecord> captor = 4177 ArgumentCaptor.forClass(NotificationRecord.class); 4178 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 4179 anyBoolean()); 4180 assertThat(captor.getValue().getNotification().flags 4181 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 4182 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 4183 } 4184 4185 @Test testGroupInstanceIds()4186 public void testGroupInstanceIds() throws Exception { 4187 final NotificationRecord group1 = generateNotificationRecord( 4188 mTestNotificationChannel, 1, "group1", true); 4189 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds", 4190 group1.getSbn().getId(), group1.getSbn().getNotification(), 4191 group1.getSbn().getUserId()); 4192 waitForIdle(); 4193 4194 // same group, child, should be returned 4195 final NotificationRecord group1Child = generateNotificationRecord( 4196 mTestNotificationChannel, 2, "group1", false); 4197 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testGroupInstanceIds", 4198 group1Child.getSbn().getId(), 4199 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); 4200 waitForIdle(); 4201 4202 assertEquals(2, mNotificationRecordLogger.numCalls()); 4203 assertEquals(mNotificationRecordLogger.get(0).getInstanceId(), 4204 mNotificationRecordLogger.get(1).groupInstanceId.getId()); 4205 } 4206 4207 @Test testFindGroupNotificationsLocked()4208 public void testFindGroupNotificationsLocked() throws Exception { 4209 // make sure the same notification can be found in both lists and returned 4210 final NotificationRecord group1 = generateNotificationRecord( 4211 mTestNotificationChannel, 1, "group1", true); 4212 mService.addEnqueuedNotification(group1); 4213 mService.addNotification(group1); 4214 4215 // should not be returned 4216 final NotificationRecord group2 = generateNotificationRecord( 4217 mTestNotificationChannel, 2, "group2", true); 4218 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 4219 group2.getSbn().getId(), group2.getSbn().getNotification(), 4220 group2.getSbn().getUserId()); 4221 waitForIdle(); 4222 4223 // should not be returned 4224 final NotificationRecord nonGroup = generateNotificationRecord( 4225 mTestNotificationChannel, 3, null, false); 4226 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 4227 nonGroup.getSbn().getId(), nonGroup.getSbn().getNotification(), 4228 nonGroup.getSbn().getUserId()); 4229 waitForIdle(); 4230 4231 // same group, child, should be returned 4232 final NotificationRecord group1Child = generateNotificationRecord( 4233 mTestNotificationChannel, 4, "group1", false); 4234 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testFindGroupNotificationsLocked", 4235 group1Child.getSbn().getId(), 4236 group1Child.getSbn().getNotification(), group1Child.getSbn().getUserId()); 4237 waitForIdle(); 4238 4239 List<NotificationRecord> inGroup1 = 4240 mService.findGroupNotificationsLocked(mPkg, group1.getGroupKey(), 4241 group1.getSbn().getUserId()); 4242 assertEquals(3, inGroup1.size()); 4243 for (NotificationRecord record : inGroup1) { 4244 assertTrue(record.getGroupKey().equals(group1.getGroupKey())); 4245 assertTrue(record.getSbn().getId() == 1 || record.getSbn().getId() == 4); 4246 } 4247 } 4248 4249 @Test testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing()4250 public void testCancelAllNotificationsInt_CancelsNoClearFlagOnGoing() throws Exception { 4251 final NotificationRecord notif = generateNotificationRecord( 4252 mTestNotificationChannel, 1, "group", true); 4253 notif.getNotification().flags |= Notification.FLAG_NO_CLEAR; 4254 mService.addNotification(notif); 4255 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 4256 Notification.FLAG_ONGOING_EVENT, notif.getUserId(), REASON_CANCEL); 4257 waitForIdle(); 4258 StatusBarNotification[] notifs = 4259 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 4260 assertEquals(0, notifs.length); 4261 } 4262 4263 @Test testAppInitiatedCancelAllNotifications_CancelsOngoingFlag()4264 public void testAppInitiatedCancelAllNotifications_CancelsOngoingFlag() throws Exception { 4265 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 4266 sbn.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 4267 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 4268 "testAppInitiatedCancelAllNotifications_CancelsOnGoingFlag", 4269 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 4270 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 4271 waitForIdle(); 4272 StatusBarNotification[] notifs = 4273 mBinderService.getActiveNotifications(sbn.getPackageName()); 4274 assertEquals(0, notifs.length); 4275 } 4276 4277 @Test testCancelAllNotificationsInt_CancelsOngoingFlag()4278 public void testCancelAllNotificationsInt_CancelsOngoingFlag() throws Exception { 4279 final NotificationRecord notif = generateNotificationRecord( 4280 mTestNotificationChannel, 1, "group", true); 4281 notif.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 4282 mService.addNotification(notif); 4283 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 4284 notif.getUserId(), REASON_CANCEL); 4285 waitForIdle(); 4286 StatusBarNotification[] notifs = 4287 mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 4288 assertEquals(0, notifs.length); 4289 } 4290 4291 @Test testUserInitiatedCancelAllWithGroup_OngoingFlag()4292 public void testUserInitiatedCancelAllWithGroup_OngoingFlag() throws Exception { 4293 final NotificationRecord parent = generateNotificationRecord( 4294 mTestNotificationChannel, 1, "group", true); 4295 final NotificationRecord child = generateNotificationRecord( 4296 mTestNotificationChannel, 2, "group", false); 4297 final NotificationRecord child2 = generateNotificationRecord( 4298 mTestNotificationChannel, 3, "group", false); 4299 child2.getNotification().flags |= Notification.FLAG_ONGOING_EVENT; 4300 final NotificationRecord newGroup = generateNotificationRecord( 4301 mTestNotificationChannel, 4, "group2", false); 4302 mService.addNotification(parent); 4303 mService.addNotification(child); 4304 mService.addNotification(child2); 4305 mService.addNotification(newGroup); 4306 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 4307 parent.getUserId()); 4308 waitForIdle(); 4309 StatusBarNotification[] notifs = 4310 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4311 assertEquals(1, notifs.length); 4312 } 4313 4314 @Test testUserInitiatedCancelAllWithGroup_NoClearFlag()4315 public void testUserInitiatedCancelAllWithGroup_NoClearFlag() throws Exception { 4316 final NotificationRecord parent = generateNotificationRecord( 4317 mTestNotificationChannel, 1, "group", true); 4318 final NotificationRecord child = generateNotificationRecord( 4319 mTestNotificationChannel, 2, "group", false); 4320 final NotificationRecord child2 = generateNotificationRecord( 4321 mTestNotificationChannel, 3, "group", false); 4322 child2.getNotification().flags |= Notification.FLAG_NO_CLEAR; 4323 final NotificationRecord newGroup = generateNotificationRecord( 4324 mTestNotificationChannel, 4, "group2", false); 4325 mService.addNotification(parent); 4326 mService.addNotification(child); 4327 mService.addNotification(child2); 4328 mService.addNotification(newGroup); 4329 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 4330 parent.getUserId()); 4331 waitForIdle(); 4332 StatusBarNotification[] notifs = 4333 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4334 assertEquals(1, notifs.length); 4335 } 4336 4337 @Test testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag()4338 public void testUserInitiatedCancelAllWithGroup_ForegroundServiceFlag() throws Exception { 4339 when(mAmi.applyForegroundServiceNotification( 4340 any(), anyString(), anyInt(), anyString(), anyInt())) 4341 .thenReturn(SHOW_IMMEDIATELY); 4342 final NotificationRecord parent = generateNotificationRecord( 4343 mTestNotificationChannel, 1, "group", true); 4344 final NotificationRecord child = generateNotificationRecord( 4345 mTestNotificationChannel, 2, "group", false); 4346 final NotificationRecord child2 = generateNotificationRecord( 4347 mTestNotificationChannel, 3, "group", false); 4348 child2.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 4349 final NotificationRecord newGroup = generateNotificationRecord( 4350 mTestNotificationChannel, 4, "group2", false); 4351 mService.addNotification(parent); 4352 mService.addNotification(child); 4353 mService.addNotification(child2); 4354 mService.addNotification(newGroup); 4355 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 4356 parent.getUserId()); 4357 waitForIdle(); 4358 StatusBarNotification[] notifs = 4359 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 4360 assertEquals(0, notifs.length); 4361 } 4362 4363 @Test testDefaultChannelUpdatesApp_postMigrationToPermissions()4364 public void testDefaultChannelUpdatesApp_postMigrationToPermissions() throws Exception { 4365 final NotificationChannel defaultChannel = mBinderService.getNotificationChannel( 4366 PKG_N_MR1, ActivityManager.getCurrentUser(), PKG_N_MR1, 4367 NotificationChannel.DEFAULT_CHANNEL_ID); 4368 defaultChannel.setImportance(IMPORTANCE_NONE); 4369 4370 mBinderService.updateNotificationChannelForPackage(PKG_N_MR1, mUid, defaultChannel); 4371 4372 verify(mPermissionHelper).setNotificationPermission( 4373 PKG_N_MR1, ActivityManager.getCurrentUser(), false, true); 4374 } 4375 4376 @Test testPostNotification_appPermissionFixed()4377 public void testPostNotification_appPermissionFixed() throws Exception { 4378 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 4379 when(mPermissionHelper.isPermissionFixed(mPkg, mUserId)).thenReturn(true); 4380 4381 NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel); 4382 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 4383 "testPostNotification_appPermissionFixed", 0, 4384 temp.getNotification(), mUserId); 4385 waitForIdle(); 4386 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 4387 StatusBarNotification[] notifs = 4388 mBinderService.getActiveNotifications(mPkg); 4389 assertThat(mService.getNotificationRecord(notifs[0].getKey()).isImportanceFixed()).isTrue(); 4390 } 4391 4392 @Test testSummaryNotification_appPermissionFixed()4393 public void testSummaryNotification_appPermissionFixed() { 4394 NotificationRecord temp = generateNotificationRecord(mTestNotificationChannel); 4395 mService.addNotification(temp); 4396 4397 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 4398 when(mPermissionHelper.isPermissionFixed(mPkg, temp.getUserId())).thenReturn(true); 4399 4400 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 4401 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 4402 4403 NotificationRecord r = mService.createAutoGroupSummary(temp.getUserId(), 4404 temp.getSbn().getPackageName(), temp.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr); 4405 4406 assertThat(r.isImportanceFixed()).isTrue(); 4407 } 4408 4409 @Test testTvExtenderChannelOverride_onTv()4410 public void testTvExtenderChannelOverride_onTv() throws Exception { 4411 mService.setIsTelevision(true); 4412 mService.setPreferencesHelper(mPreferencesHelper); 4413 when(mPreferencesHelper.getNotificationChannel( 4414 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn( 4415 new NotificationChannel("foo", "foo", IMPORTANCE_HIGH)); 4416 4417 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); 4418 mBinderService.enqueueNotificationWithTag( 4419 mPkg, 4420 mPkg, 4421 "testTvExtenderChannelOverride_onTv", 4422 0, 4423 generateNotificationRecord(null, tv).getNotification(), 4424 mUserId); 4425 verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( 4426 anyString(), anyInt(), eq("foo"), eq(null), anyBoolean(), anyBoolean()); 4427 } 4428 4429 @Test testTvExtenderChannelOverride_notOnTv()4430 public void testTvExtenderChannelOverride_notOnTv() throws Exception { 4431 mService.setIsTelevision(false); 4432 mService.setPreferencesHelper(mPreferencesHelper); 4433 when(mPreferencesHelper.getNotificationChannel( 4434 anyString(), anyInt(), anyString(), anyBoolean())).thenReturn( 4435 mTestNotificationChannel); 4436 4437 Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo"); 4438 mBinderService.enqueueNotificationWithTag( 4439 mPkg, 4440 mPkg, 4441 "testTvExtenderChannelOverride_notOnTv", 4442 0, 4443 generateNotificationRecord(null, tv).getNotification(), 4444 mUserId); 4445 verify(mPreferencesHelper, times(1)).getConversationNotificationChannel( 4446 anyString(), anyInt(), eq(mTestNotificationChannel.getId()), eq(null), 4447 anyBoolean(), anyBoolean()); 4448 } 4449 4450 @Test onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage()4451 public void onOpChanged_permissionRevoked_cancelsAllNotificationsFromPackage() 4452 throws RemoteException { 4453 // Have preexisting posted notifications from revoked package and other packages. 4454 mService.addNotification(new NotificationRecord(mContext, 4455 generateSbn("revoked", 1001, 1, 0), mTestNotificationChannel)); 4456 mService.addNotification(new NotificationRecord(mContext, 4457 generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); 4458 // Have preexisting enqueued notifications from revoked package and other packages. 4459 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4460 generateSbn("revoked", 1001, 3, 0), mTestNotificationChannel)); 4461 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4462 generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); 4463 assertThat(mService.mNotificationList).hasSize(2); 4464 assertThat(mService.mEnqueuedNotifications).hasSize(2); 4465 4466 when(mPackageManagerInternal.getPackageUid("revoked", 0, 0)).thenReturn(1001); 4467 when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(false); 4468 4469 mOnPermissionChangeListener.onOpChanged( 4470 AppOpsManager.OPSTR_POST_NOTIFICATION, "revoked", 0); 4471 waitForIdle(); 4472 4473 assertThat(mService.mNotificationList).hasSize(1); 4474 assertThat(mService.mNotificationList.get(0).getSbn().getPackageName()).isEqualTo("other"); 4475 assertThat(mService.mEnqueuedNotifications).hasSize(1); 4476 assertThat(mService.mEnqueuedNotifications.get(0).getSbn().getPackageName()).isEqualTo( 4477 "other"); 4478 } 4479 4480 @Test onOpChanged_permissionStillGranted_notificationsAreNotAffected()4481 public void onOpChanged_permissionStillGranted_notificationsAreNotAffected() 4482 throws RemoteException { 4483 // NOTE: This combination (receiving the onOpChanged broadcast for a package, the permission 4484 // being now granted, AND having previously posted notifications from said package) should 4485 // never happen (if we trust the broadcasts are correct). So this test is for a what-if 4486 // scenario, to verify we still handle it reasonably. 4487 4488 // Have preexisting posted notifications from specific package and other packages. 4489 mService.addNotification(new NotificationRecord(mContext, 4490 generateSbn("granted", 1001, 1, 0), mTestNotificationChannel)); 4491 mService.addNotification(new NotificationRecord(mContext, 4492 generateSbn("other", 1002, 2, 0), mTestNotificationChannel)); 4493 // Have preexisting enqueued notifications from specific package and other packages. 4494 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4495 generateSbn("granted", 1001, 3, 0), mTestNotificationChannel)); 4496 mService.addEnqueuedNotification(new NotificationRecord(mContext, 4497 generateSbn("other", 1002, 4, 0), mTestNotificationChannel)); 4498 assertThat(mService.mNotificationList).hasSize(2); 4499 assertThat(mService.mEnqueuedNotifications).hasSize(2); 4500 4501 when(mPackageManagerInternal.getPackageUid("granted", 0, 0)).thenReturn(1001); 4502 when(mPermissionHelper.hasPermission(eq(1001))).thenReturn(true); 4503 4504 mOnPermissionChangeListener.onOpChanged( 4505 AppOpsManager.OPSTR_POST_NOTIFICATION, "granted", 0); 4506 waitForIdle(); 4507 4508 assertThat(mService.mNotificationList).hasSize(2); 4509 assertThat(mService.mEnqueuedNotifications).hasSize(2); 4510 } 4511 4512 @Test onOpChanged_notInitializedUser_ignored()4513 public void onOpChanged_notInitializedUser_ignored() throws RemoteException { 4514 when(mUmInternal.isUserInitialized(eq(0))).thenReturn(false); 4515 4516 mOnPermissionChangeListener.onOpChanged( 4517 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0); 4518 waitForIdle(); 4519 4520 // We early-exited and didn't even query PM for package details. 4521 verify(mPackageManagerInternal, never()).getPackageUid(any(), anyLong(), anyInt()); 4522 } 4523 4524 @Test setNotificationsEnabledForPackage_disabling_clearsNotifications()4525 public void setNotificationsEnabledForPackage_disabling_clearsNotifications() throws Exception { 4526 mService.addNotification(new NotificationRecord(mContext, 4527 generateSbn("package", 1001, 1, 0), mTestNotificationChannel)); 4528 assertThat(mService.mNotificationList).hasSize(1); 4529 when(mPackageManagerInternal.getPackageUid("package", 0, 0)).thenReturn(1001); 4530 when(mPermissionHelper.hasRequestedPermission(any(), eq("package"), anyInt())).thenReturn( 4531 true); 4532 4533 // Start with granted permission and simulate effect of revoking it. 4534 when(mPermissionHelper.hasPermission(1001)).thenReturn(true); 4535 doAnswer(invocation -> { 4536 when(mPermissionHelper.hasPermission(1001)).thenReturn(false); 4537 mOnPermissionChangeListener.onOpChanged( 4538 AppOpsManager.OPSTR_POST_NOTIFICATION, "package", 0); 4539 return null; 4540 }).when(mPermissionHelper).setNotificationPermission("package", 0, false, true); 4541 4542 mBinderService.setNotificationsEnabledForPackage("package", 1001, false); 4543 waitForIdle(); 4544 4545 assertThat(mService.mNotificationList).hasSize(0); 4546 4547 mTestableLooper.moveTimeForward(500); 4548 waitForIdle(); 4549 verify(mContext).sendBroadcastAsUser(any(), eq(UserHandle.of(0)), eq(null)); 4550 } 4551 4552 @Test testUpdateAppNotifyCreatorBlock()4553 public void testUpdateAppNotifyCreatorBlock() throws Exception { 4554 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 4555 4556 mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, false); 4557 Thread.sleep(500); 4558 waitForIdle(); 4559 4560 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4561 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4562 4563 assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, 4564 captor.getValue().getAction()); 4565 assertEquals(mPkg, captor.getValue().getPackage()); 4566 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); 4567 } 4568 4569 @Test testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting()4570 public void testUpdateAppNotifyCreatorBlock_notIfMatchesExistingSetting() throws Exception { 4571 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 4572 4573 mBinderService.setNotificationsEnabledForPackage(mPkg, 0, false); 4574 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 4575 } 4576 4577 @Test testUpdateAppNotifyCreatorUnblock()4578 public void testUpdateAppNotifyCreatorUnblock() throws Exception { 4579 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 4580 4581 mBinderService.setNotificationsEnabledForPackage(mPkg, mUid, true); 4582 Thread.sleep(500); 4583 waitForIdle(); 4584 4585 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4586 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4587 4588 assertEquals(NotificationManager.ACTION_APP_BLOCK_STATE_CHANGED, 4589 captor.getValue().getAction()); 4590 assertEquals(mPkg, captor.getValue().getPackage()); 4591 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, true)); 4592 } 4593 4594 @Test testUpdateChannelNotifyCreatorBlock()4595 public void testUpdateChannelNotifyCreatorBlock() throws Exception { 4596 mService.setPreferencesHelper(mPreferencesHelper); 4597 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4598 eq(mTestNotificationChannel.getId()), anyBoolean())) 4599 .thenReturn(mTestNotificationChannel); 4600 4601 NotificationChannel updatedChannel = 4602 new NotificationChannel(mTestNotificationChannel.getId(), 4603 mTestNotificationChannel.getName(), IMPORTANCE_NONE); 4604 4605 mBinderService.updateNotificationChannelForPackage(mPkg, 0, updatedChannel); 4606 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4607 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4608 4609 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED, 4610 captor.getValue().getAction()); 4611 assertEquals(mPkg, captor.getValue().getPackage()); 4612 assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra( 4613 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID)); 4614 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4615 } 4616 4617 @Test testUpdateChannelNotifyCreatorUnblock()4618 public void testUpdateChannelNotifyCreatorUnblock() throws Exception { 4619 NotificationChannel existingChannel = 4620 new NotificationChannel(mTestNotificationChannel.getId(), 4621 mTestNotificationChannel.getName(), IMPORTANCE_NONE); 4622 mService.setPreferencesHelper(mPreferencesHelper); 4623 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4624 eq(mTestNotificationChannel.getId()), anyBoolean())) 4625 .thenReturn(existingChannel); 4626 4627 mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel); 4628 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4629 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4630 4631 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED, 4632 captor.getValue().getAction()); 4633 assertEquals(mPkg, captor.getValue().getPackage()); 4634 assertEquals(mTestNotificationChannel.getId(), captor.getValue().getStringExtra( 4635 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_ID)); 4636 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4637 } 4638 4639 @Test testUpdateChannelNoNotifyCreatorOtherChanges()4640 public void testUpdateChannelNoNotifyCreatorOtherChanges() throws Exception { 4641 NotificationChannel existingChannel = 4642 new NotificationChannel(mTestNotificationChannel.getId(), 4643 mTestNotificationChannel.getName(), IMPORTANCE_MAX); 4644 mService.setPreferencesHelper(mPreferencesHelper); 4645 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4646 eq(mTestNotificationChannel.getId()), anyBoolean())) 4647 .thenReturn(existingChannel); 4648 4649 mBinderService.updateNotificationChannelForPackage(mPkg, 0, mTestNotificationChannel); 4650 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 4651 } 4652 4653 @Test testUpdateGroupNotifyCreatorBlock()4654 public void testUpdateGroupNotifyCreatorBlock() throws Exception { 4655 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 4656 mService.setPreferencesHelper(mPreferencesHelper); 4657 when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()), 4658 eq(mPkg), anyInt())) 4659 .thenReturn(existing); 4660 4661 NotificationChannelGroup updated = new NotificationChannelGroup("id", "name"); 4662 updated.setBlocked(true); 4663 4664 mBinderService.updateNotificationChannelGroupForPackage(mPkg, 0, updated); 4665 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4666 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4667 4668 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED, 4669 captor.getValue().getAction()); 4670 assertEquals(mPkg, captor.getValue().getPackage()); 4671 assertEquals(existing.getId(), captor.getValue().getStringExtra( 4672 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID)); 4673 assertTrue(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4674 } 4675 4676 @Test testUpdateGroupNotifyCreatorUnblock()4677 public void testUpdateGroupNotifyCreatorUnblock() throws Exception { 4678 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 4679 existing.setBlocked(true); 4680 mService.setPreferencesHelper(mPreferencesHelper); 4681 when(mPreferencesHelper.getNotificationChannelGroup(eq(existing.getId()), 4682 eq(mPkg), anyInt())) 4683 .thenReturn(existing); 4684 4685 mBinderService.updateNotificationChannelGroupForPackage( 4686 mPkg, 0, new NotificationChannelGroup("id", "name")); 4687 ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class); 4688 verify(mContext, times(1)).sendBroadcastAsUser(captor.capture(), any(), eq(null)); 4689 4690 assertEquals(NotificationManager.ACTION_NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED, 4691 captor.getValue().getAction()); 4692 assertEquals(mPkg, captor.getValue().getPackage()); 4693 assertEquals(existing.getId(), captor.getValue().getStringExtra( 4694 NotificationManager.EXTRA_NOTIFICATION_CHANNEL_GROUP_ID)); 4695 assertFalse(captor.getValue().getBooleanExtra(EXTRA_BLOCKED_STATE, false)); 4696 } 4697 4698 @Test testUpdateGroupNoNotifyCreatorOtherChanges()4699 public void testUpdateGroupNoNotifyCreatorOtherChanges() throws Exception { 4700 NotificationChannelGroup existing = new NotificationChannelGroup("id", "name"); 4701 mService.setPreferencesHelper(mPreferencesHelper); 4702 when(mPreferencesHelper.getNotificationChannelGroup( 4703 eq(existing.getId()), eq(mPkg), anyInt())) 4704 .thenReturn(existing); 4705 4706 mBinderService.updateNotificationChannelGroupForPackage( 4707 mPkg, 0, new NotificationChannelGroup("id", "new name")); 4708 verify(mContext, never()).sendBroadcastAsUser(any(), any(), eq(null)); 4709 } 4710 4711 @Test testCreateChannelNotifyListener()4712 public void testCreateChannelNotifyListener() throws Exception { 4713 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4714 .thenReturn(singletonList(mock(AssociationInfo.class))); 4715 mService.setPreferencesHelper(mPreferencesHelper); 4716 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4717 eq(mTestNotificationChannel.getId()), anyBoolean())) 4718 .thenReturn(mTestNotificationChannel); 4719 NotificationChannel channel2 = new NotificationChannel("a", "b", IMPORTANCE_LOW); 4720 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4721 eq(channel2.getId()), anyBoolean())) 4722 .thenReturn(channel2); 4723 when(mPreferencesHelper.createNotificationChannel(eq(mPkg), anyInt(), 4724 eq(channel2), anyBoolean(), anyBoolean(), anyInt(), anyBoolean())) 4725 .thenReturn(true); 4726 4727 reset(mListeners); 4728 mBinderService.createNotificationChannels(mPkg, 4729 new ParceledListSlice(Arrays.asList(mTestNotificationChannel, channel2))); 4730 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4731 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4732 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4733 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4734 eq(Process.myUserHandle()), eq(channel2), 4735 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4736 } 4737 4738 @Test testCreateChannelGroupNotifyListener()4739 public void testCreateChannelGroupNotifyListener() throws Exception { 4740 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4741 .thenReturn(singletonList(mock(AssociationInfo.class))); 4742 mService.setPreferencesHelper(mPreferencesHelper); 4743 NotificationChannelGroup group1 = new NotificationChannelGroup("a", "b"); 4744 NotificationChannelGroup group2 = new NotificationChannelGroup("n", "m"); 4745 4746 reset(mListeners); 4747 mBinderService.createNotificationChannelGroups(mPkg, 4748 new ParceledListSlice(Arrays.asList(group1, group2))); 4749 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 4750 eq(Process.myUserHandle()), eq(group1), 4751 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4752 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 4753 eq(Process.myUserHandle()), eq(group2), 4754 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_ADDED)); 4755 } 4756 4757 @Test testUpdateChannelNotifyListener()4758 public void testUpdateChannelNotifyListener() throws Exception { 4759 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4760 .thenReturn(singletonList(mock(AssociationInfo.class))); 4761 mService.setPreferencesHelper(mPreferencesHelper); 4762 mTestNotificationChannel.setLightColor(Color.CYAN); 4763 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4764 eq(mTestNotificationChannel.getId()), anyBoolean())) 4765 .thenReturn(mTestNotificationChannel); 4766 4767 reset(mListeners); 4768 mBinderService.updateNotificationChannelForPackage(mPkg, mUid, mTestNotificationChannel); 4769 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4770 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4771 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 4772 } 4773 4774 @Test testDeleteChannelNotifyListener()4775 public void testDeleteChannelNotifyListener() throws Exception { 4776 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4777 .thenReturn(singletonList(mock(AssociationInfo.class))); 4778 mService.setPreferencesHelper(mPreferencesHelper); 4779 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4780 eq(mTestNotificationChannel.getId()), anyBoolean())) 4781 .thenReturn(mTestNotificationChannel); 4782 when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(), 4783 eq(mTestNotificationChannel.getId()), anyInt(), anyBoolean())).thenReturn(true); 4784 reset(mListeners); 4785 mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId()); 4786 verify(mListeners, times(1)).notifyNotificationChannelChanged(eq(mPkg), 4787 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 4788 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4789 } 4790 4791 @Test 4792 @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) testAppsCannotDeleteBundleChannel()4793 public void testAppsCannotDeleteBundleChannel() throws Exception { 4794 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4795 .thenReturn(singletonList(mock(AssociationInfo.class))); 4796 mService.setPreferencesHelper(mPreferencesHelper); 4797 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4798 eq(NEWS_ID), anyBoolean())) 4799 .thenReturn(mTestNotificationChannel); 4800 when(mPreferencesHelper.deleteNotificationChannel(eq(mPkg), anyInt(), 4801 eq(NEWS_ID), anyInt(), anyBoolean())).thenReturn(true); 4802 reset(mListeners); 4803 mBinderService.deleteNotificationChannel(mPkg, NEWS_ID); 4804 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 4805 eq(Process.myUserHandle()), any(), 4806 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4807 } 4808 4809 @Test testDeleteChannelOnlyDoExtraWorkIfExisted()4810 public void testDeleteChannelOnlyDoExtraWorkIfExisted() throws Exception { 4811 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4812 .thenReturn(singletonList(mock(AssociationInfo.class))); 4813 mService.setPreferencesHelper(mPreferencesHelper); 4814 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 4815 eq(mTestNotificationChannel.getId()), anyBoolean())) 4816 .thenReturn(null); 4817 reset(mListeners); 4818 mBinderService.deleteNotificationChannel(mPkg, mTestNotificationChannel.getId()); 4819 verifyNoMoreInteractions(mListeners); 4820 verifyNoMoreInteractions(mHistoryManager); 4821 } 4822 4823 @Test testDeleteChannelGroupNotifyListener()4824 public void testDeleteChannelGroupNotifyListener() throws Exception { 4825 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4826 .thenReturn(singletonList(mock(AssociationInfo.class))); 4827 NotificationChannelGroup ncg = new NotificationChannelGroup("a", "b/c"); 4828 mService.setPreferencesHelper(mPreferencesHelper); 4829 when(mPreferencesHelper.getNotificationChannelGroupWithChannels( 4830 eq(mPkg), anyInt(), eq(ncg.getId()), anyBoolean())) 4831 .thenReturn(ncg); 4832 reset(mListeners); 4833 mBinderService.deleteNotificationChannelGroup(mPkg, ncg.getId()); 4834 verify(mListeners, times(1)).notifyNotificationChannelGroupChanged(eq(mPkg), 4835 eq(Process.myUserHandle()), eq(ncg), 4836 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED)); 4837 } 4838 4839 @Test testDeleteChannelGroupChecksForFgses()4840 public void testDeleteChannelGroupChecksForFgses() throws Exception { 4841 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4842 .thenReturn(singletonList(mock(AssociationInfo.class))); 4843 CountDownLatch latch = new CountDownLatch(2); 4844 mService.createNotificationChannelGroup( 4845 mPkg, mUid, new NotificationChannelGroup("group", "group"), true, false); 4846 new Thread(() -> { 4847 NotificationChannel notificationChannel = new NotificationChannel("id", "id", 4848 NotificationManager.IMPORTANCE_HIGH); 4849 notificationChannel.setGroup("group"); 4850 ParceledListSlice<NotificationChannel> pls = 4851 new ParceledListSlice(ImmutableList.of(notificationChannel)); 4852 try { 4853 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 4854 } catch (RemoteException e) { 4855 throw new RuntimeException(e); 4856 } 4857 latch.countDown(); 4858 }).start(); 4859 new Thread(() -> { 4860 try { 4861 synchronized (this) { 4862 wait(5000); 4863 } 4864 mService.createNotificationChannelGroup(mPkg, mUid, 4865 new NotificationChannelGroup("new", "new group"), true, false); 4866 NotificationChannel notificationChannel = 4867 new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH); 4868 notificationChannel.setGroup("new"); 4869 ParceledListSlice<NotificationChannel> pls = 4870 new ParceledListSlice(ImmutableList.of(notificationChannel)); 4871 try { 4872 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 4873 mBinderService.deleteNotificationChannelGroup(mPkg, "group"); 4874 } catch (RemoteException e) { 4875 throw new RuntimeException(e); 4876 } 4877 } catch (Exception e) { 4878 e.printStackTrace(); 4879 } 4880 latch.countDown(); 4881 }).start(); 4882 4883 latch.await(); 4884 verify(mAmi).hasForegroundServiceNotification(anyString(), anyInt(), anyString()); 4885 } 4886 setUpChannelsForConversationChannelTest()4887 private void setUpChannelsForConversationChannelTest() throws RemoteException { 4888 when(mPreferencesHelper.getNotificationChannel( 4889 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(false))) 4890 .thenReturn(mParentChannel); 4891 when(mPreferencesHelper.getConversationNotificationChannel( 4892 eq(mPkg), eq(mUid), eq(PARENT_CHANNEL_ID), eq(CONVERSATION_ID), eq(false), eq(false))) 4893 .thenReturn(mConversationChannel); 4894 when(mPackageManager.getPackageUid(mPkg, 0, mUserId)).thenReturn(mUid); 4895 } 4896 4897 @Test 4898 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_cdm_success()4899 public void createConversationChannelForPkgFromPrivilegedListener_cdm_success() throws Exception { 4900 // Set up cdm 4901 mService.setPreferencesHelper(mPreferencesHelper); 4902 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4903 .thenReturn(singletonList(mock(AssociationInfo.class))); 4904 4905 // Set up parent channel 4906 setUpChannelsForConversationChannelTest(); 4907 final NotificationChannel parentChannelCopy = mParentChannel.copy(); 4908 4909 NotificationChannel createdChannel = 4910 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 4911 null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID); 4912 4913 // Verify that a channel is created and a copied channel is returned. 4914 verify(mPreferencesHelper, times(1)).createNotificationChannel( 4915 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(), 4916 eq(mUid), anyBoolean()); 4917 assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel); 4918 assertThat(createdChannel).isEqualTo(mConversationChannel); 4919 4920 // Verify that the channel creation is not directly use the parent channel. 4921 verify(mPreferencesHelper, never()).createNotificationChannel( 4922 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(), 4923 anyInt(), anyBoolean()); 4924 4925 // Verify that the content of parent channel is not changed. 4926 assertThat(parentChannelCopy).isEqualTo(mParentChannel); 4927 } 4928 4929 @Test 4930 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess()4931 public void createConversationChannelForPkgFromPrivilegedListener_cdm_noAccess() throws Exception { 4932 // Set up cdm without access 4933 mService.setPreferencesHelper(mPreferencesHelper); 4934 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4935 .thenReturn(emptyList()); 4936 4937 // Set up parent channel 4938 setUpChannelsForConversationChannelTest(); 4939 4940 try { 4941 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 4942 null, mPkg, mUser, "parentId", "conversationId"); 4943 fail("listeners that don't have a companion device shouldn't be able to call this"); 4944 } catch (SecurityException e) { 4945 // pass 4946 } 4947 4948 verify(mPreferencesHelper, never()).createNotificationChannel( 4949 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(), 4950 anyInt(), anyBoolean()); 4951 } 4952 4953 @Test 4954 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_assistant_success()4955 public void createConversationChannelForPkgFromPrivilegedListener_assistant_success() throws Exception { 4956 // Set up assistant 4957 mService.setPreferencesHelper(mPreferencesHelper); 4958 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4959 .thenReturn(emptyList()); 4960 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 4961 4962 // Set up parent channel 4963 setUpChannelsForConversationChannelTest(); 4964 final NotificationChannel parentChannelCopy = mParentChannel.copy(); 4965 4966 NotificationChannel createdChannel = 4967 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 4968 null, mPkg, mUser, PARENT_CHANNEL_ID, CONVERSATION_ID); 4969 4970 // Verify that a channel is created and a copied channel is returned. 4971 verify(mPreferencesHelper, times(1)).createNotificationChannel( 4972 eq(mPkg), eq(mUid), any(), anyBoolean(), anyBoolean(), 4973 eq(mUid), anyBoolean()); 4974 assertThat(createdChannel).isNotSameInstanceAs(mConversationChannel); 4975 assertThat(createdChannel).isEqualTo(mConversationChannel); 4976 4977 // Verify that the channel creation is not directly use the parent channel. 4978 verify(mPreferencesHelper, never()).createNotificationChannel( 4979 anyString(), anyInt(), eq(mParentChannel), anyBoolean(), anyBoolean(), 4980 anyInt(), anyBoolean()); 4981 4982 // Verify that the content of parent channel is not changed. 4983 assertThat(parentChannelCopy).isEqualTo(mParentChannel); 4984 } 4985 4986 @Test 4987 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess()4988 public void createConversationChannelForPkgFromPrivilegedListener_assistant_noAccess() throws Exception { 4989 // Set up assistant without access 4990 mService.setPreferencesHelper(mPreferencesHelper); 4991 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 4992 .thenReturn(emptyList()); 4993 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); 4994 4995 // Set up parent channel 4996 setUpChannelsForConversationChannelTest(); 4997 4998 try { 4999 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 5000 null, mPkg, mUser, "parentId", "conversationId"); 5001 fail("listeners that don't have a companion device shouldn't be able to call this"); 5002 } catch (SecurityException e) { 5003 // pass 5004 } 5005 5006 verify(mPreferencesHelper, never()).createNotificationChannel( 5007 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(), 5008 anyInt(), anyBoolean()); 5009 } 5010 5011 @Test 5012 @RequiresFlagsEnabled(FLAG_NOTIFICATION_CONVERSATION_CHANNEL_MANAGEMENT) createConversationChannelForPkgFromPrivilegedListener_badUser()5013 public void createConversationChannelForPkgFromPrivilegedListener_badUser() throws Exception { 5014 // Set up bad user 5015 mService.setPreferencesHelper(mPreferencesHelper); 5016 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5017 .thenReturn(singletonList(mock(AssociationInfo.class))); 5018 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5019 mListener.component = new ComponentName(mPkg, mPkg); 5020 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5021 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5022 5023 // Set up parent channel 5024 setUpChannelsForConversationChannelTest(); 5025 5026 try { 5027 mBinderService.createConversationNotificationChannelForPackageFromPrivilegedListener( 5028 null, mPkg, mUser, "parentId", "conversationId"); 5029 fail("listener getting channels from a user they cannot see"); 5030 } catch (SecurityException e) { 5031 // pass 5032 } 5033 5034 verify(mPreferencesHelper, never()).createNotificationChannel( 5035 anyString(), anyInt(), any(), anyBoolean(), anyBoolean(), 5036 anyInt(), anyBoolean()); 5037 } 5038 5039 @Test updateNotificationChannelFromPrivilegedListener_cdm_success()5040 public void updateNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { 5041 5042 mService.setPreferencesHelper(mPreferencesHelper); 5043 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5044 .thenReturn(singletonList(mock(AssociationInfo.class))); 5045 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5046 eq(mTestNotificationChannel.getId()), anyBoolean())) 5047 .thenReturn(mTestNotificationChannel); 5048 5049 mBinderService.updateNotificationChannelFromPrivilegedListener( 5050 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5051 5052 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 5053 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5054 5055 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5056 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5057 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5058 } 5059 5060 @Test updateNotificationChannelFromPrivilegedListener_cdm_noAccess()5061 public void updateNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { 5062 mService.setPreferencesHelper(mPreferencesHelper); 5063 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5064 .thenReturn(emptyList()); 5065 5066 try { 5067 mBinderService.updateNotificationChannelFromPrivilegedListener( 5068 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5069 fail("listeners that don't have a companion device shouldn't be able to call this"); 5070 } catch (SecurityException e) { 5071 // pass 5072 } 5073 5074 verify(mPreferencesHelper, never()).updateNotificationChannel( 5075 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5076 5077 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5078 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5079 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5080 } 5081 5082 @Test updateNotificationChannelFromPrivilegedListener_assistant_success()5083 public void updateNotificationChannelFromPrivilegedListener_assistant_success() throws Exception { 5084 mService.setPreferencesHelper(mPreferencesHelper); 5085 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5086 .thenReturn(emptyList()); 5087 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 5088 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5089 eq(mTestNotificationChannel.getId()), anyBoolean())) 5090 .thenReturn(mTestNotificationChannel); 5091 5092 mBinderService.updateNotificationChannelFromPrivilegedListener( 5093 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5094 5095 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 5096 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5097 5098 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5099 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5100 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5101 } 5102 5103 @Test updateNotificationChannelFromPrivilegedListener_assistant_noAccess()5104 public void updateNotificationChannelFromPrivilegedListener_assistant_noAccess() throws Exception { 5105 mService.setPreferencesHelper(mPreferencesHelper); 5106 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5107 .thenReturn(emptyList()); 5108 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); 5109 5110 try { 5111 mBinderService.updateNotificationChannelFromPrivilegedListener( 5112 null, mPkg, Process.myUserHandle(), mTestNotificationChannel); 5113 fail("listeners that don't have a companion device shouldn't be able to call this"); 5114 } catch (SecurityException e) { 5115 // pass 5116 } 5117 5118 verify(mPreferencesHelper, never()).updateNotificationChannel( 5119 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5120 5121 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5122 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5123 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5124 } 5125 5126 @Test updateNotificationChannelFromPrivilegedListener_badUser()5127 public void updateNotificationChannelFromPrivilegedListener_badUser() throws Exception { 5128 mService.setPreferencesHelper(mPreferencesHelper); 5129 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5130 .thenReturn(singletonList(mock(AssociationInfo.class))); 5131 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5132 mListener.component = new ComponentName(mPkg, mPkg); 5133 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5134 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5135 5136 try { 5137 mBinderService.updateNotificationChannelFromPrivilegedListener( 5138 null, mPkg, UserHandle.ALL, mTestNotificationChannel); 5139 fail("incorrectly allowed a change to a user listener cannot see"); 5140 } catch (SecurityException e) { 5141 // pass 5142 } 5143 5144 verify(mPreferencesHelper, never()).updateNotificationChannel( 5145 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5146 5147 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5148 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5149 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5150 } 5151 5152 @Test updateNotificationChannelFromPrivilegedListener_noSoundUriPermission()5153 public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission() 5154 throws Exception { 5155 mService.setPreferencesHelper(mPreferencesHelper); 5156 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5157 .thenReturn(singletonList(mock(AssociationInfo.class))); 5158 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5159 eq(mTestNotificationChannel.getId()), anyBoolean())) 5160 .thenReturn(mTestNotificationChannel); 5161 5162 final Uri soundUri = Uri.parse("content://media/test/sound/uri"); 5163 final NotificationChannel updatedNotificationChannel = new NotificationChannel( 5164 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 5165 updatedNotificationChannel.setSound(soundUri, 5166 updatedNotificationChannel.getAudioAttributes()); 5167 5168 doThrow(new SecurityException("no access")).when(mUgmInternal) 5169 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), 5170 anyInt(), eq(Process.myUserHandle().getIdentifier())); 5171 5172 assertThrows(SecurityException.class, 5173 () -> mBinderService.updateNotificationChannelFromPrivilegedListener(null, mPkg, 5174 Process.myUserHandle(), updatedNotificationChannel)); 5175 5176 verify(mPreferencesHelper, never()).updateNotificationChannel( 5177 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5178 5179 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5180 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5181 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5182 } 5183 5184 @Test updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound()5185 public void updateNotificationChannelFromPrivilegedListener_noSoundUriPermission_sameSound() 5186 throws Exception { 5187 mService.setPreferencesHelper(mPreferencesHelper); 5188 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5189 .thenReturn(singletonList(mock(AssociationInfo.class))); 5190 when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(), 5191 eq(mTestNotificationChannel.getId()), anyBoolean())) 5192 .thenReturn(mTestNotificationChannel); 5193 5194 final Uri soundUri = Settings.System.DEFAULT_NOTIFICATION_URI; 5195 final NotificationChannel updatedNotificationChannel = new NotificationChannel( 5196 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 5197 updatedNotificationChannel.setSound(soundUri, 5198 updatedNotificationChannel.getAudioAttributes()); 5199 5200 doThrow(new SecurityException("no access")).when(mUgmInternal) 5201 .checkGrantUriPermission(eq(Process.myUid()), any(), eq(soundUri), 5202 anyInt(), eq(Process.myUserHandle().getIdentifier())); 5203 5204 mBinderService.updateNotificationChannelFromPrivilegedListener( 5205 null, mPkg, Process.myUserHandle(), updatedNotificationChannel); 5206 5207 verify(mPreferencesHelper, times(1)).updateNotificationChannel( 5208 anyString(), anyInt(), any(), anyBoolean(), anyInt(), anyBoolean()); 5209 5210 verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg), 5211 eq(Process.myUserHandle()), eq(mTestNotificationChannel), 5212 eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED)); 5213 } 5214 5215 @Test testGetNotificationChannelFromPrivilegedListener_cdm_success()5216 public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception { 5217 mService.setPreferencesHelper(mPreferencesHelper); 5218 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5219 .thenReturn(singletonList(mock(AssociationInfo.class))); 5220 5221 mBinderService.getNotificationChannelsFromPrivilegedListener( 5222 null, mPkg, Process.myUserHandle()); 5223 5224 verify(mPreferencesHelper, times(1)).getNotificationChannels( 5225 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5226 } 5227 5228 @Test testGetNotificationChannelFromPrivilegedListener_cdm_noAccess()5229 public void testGetNotificationChannelFromPrivilegedListener_cdm_noAccess() throws Exception { 5230 mService.setPreferencesHelper(mPreferencesHelper); 5231 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5232 .thenReturn(emptyList()); 5233 5234 try { 5235 mBinderService.getNotificationChannelsFromPrivilegedListener( 5236 null, mPkg, Process.myUserHandle()); 5237 fail("listeners that don't have a companion device shouldn't be able to call this"); 5238 } catch (SecurityException e) { 5239 // pass 5240 } 5241 5242 verify(mPreferencesHelper, never()).getNotificationChannels( 5243 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5244 } 5245 5246 @Test testGetNotificationChannelFromPrivilegedListener_assistant_success()5247 public void testGetNotificationChannelFromPrivilegedListener_assistant_success() 5248 throws Exception { 5249 mService.setPreferencesHelper(mPreferencesHelper); 5250 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5251 .thenReturn(emptyList()); 5252 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 5253 5254 mBinderService.getNotificationChannelsFromPrivilegedListener( 5255 null, mPkg, Process.myUserHandle()); 5256 5257 verify(mPreferencesHelper, times(1)).getNotificationChannels( 5258 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5259 } 5260 5261 @Test testGetNotificationChannelFromPrivilegedListener_assistant_noAccess()5262 public void testGetNotificationChannelFromPrivilegedListener_assistant_noAccess() 5263 throws Exception { 5264 mService.setPreferencesHelper(mPreferencesHelper); 5265 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5266 .thenReturn(emptyList()); 5267 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(false); 5268 5269 try { 5270 mBinderService.getNotificationChannelsFromPrivilegedListener( 5271 null, mPkg, Process.myUserHandle()); 5272 fail("listeners that don't have a companion device shouldn't be able to call this"); 5273 } catch (SecurityException e) { 5274 // pass 5275 } 5276 5277 verify(mPreferencesHelper, never()).getNotificationChannels( 5278 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5279 } 5280 5281 @Test testGetNotificationChannelFromPrivilegedListener_badUser()5282 public void testGetNotificationChannelFromPrivilegedListener_badUser() throws Exception { 5283 mService.setPreferencesHelper(mPreferencesHelper); 5284 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5285 .thenReturn(singletonList(mock(AssociationInfo.class))); 5286 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5287 mListener.component = new ComponentName(mPkg, mPkg); 5288 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5289 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5290 5291 try { 5292 mBinderService.getNotificationChannelsFromPrivilegedListener( 5293 null, mPkg, Process.myUserHandle()); 5294 fail("listener getting channels from a user they cannot see"); 5295 } catch (SecurityException e) { 5296 // pass 5297 } 5298 5299 verify(mPreferencesHelper, never()).getNotificationChannels( 5300 anyString(), anyInt(), anyBoolean(), anyBoolean()); 5301 } 5302 5303 @Test testGetNotificationChannelGroupsFromPrivilegedListener_success()5304 public void testGetNotificationChannelGroupsFromPrivilegedListener_success() throws Exception { 5305 mService.setPreferencesHelper(mPreferencesHelper); 5306 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5307 .thenReturn(singletonList(mock(AssociationInfo.class))); 5308 5309 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 5310 null, mPkg, Process.myUserHandle()); 5311 5312 verify(mPreferencesHelper, times(1)).getNotificationChannelGroupsWithoutChannels( 5313 anyString(), anyInt()); 5314 } 5315 5316 @Test testGetNotificationChannelGroupsFromPrivilegedListener_noAccess()5317 public void testGetNotificationChannelGroupsFromPrivilegedListener_noAccess() throws Exception { 5318 mService.setPreferencesHelper(mPreferencesHelper); 5319 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5320 .thenReturn(emptyList()); 5321 5322 try { 5323 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 5324 null, mPkg, Process.myUserHandle()); 5325 fail("listeners that don't have a companion device shouldn't be able to call this"); 5326 } catch (SecurityException e) { 5327 // pass 5328 } 5329 5330 verify(mPreferencesHelper, never()).getNotificationChannelGroupsWithoutChannels(anyString(), 5331 anyInt()); 5332 } 5333 5334 @Test testGetNotificationChannelGroupsFromPrivilegedListener_badUser()5335 public void testGetNotificationChannelGroupsFromPrivilegedListener_badUser() throws Exception { 5336 mService.setPreferencesHelper(mPreferencesHelper); 5337 when(mCompanionMgr.getAssociations(mPkg, mUserId)) 5338 .thenReturn(emptyList()); 5339 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5340 mListener.component = new ComponentName(mPkg, mPkg); 5341 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5342 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5343 try { 5344 mBinderService.getNotificationChannelGroupsFromPrivilegedListener( 5345 null, mPkg, Process.myUserHandle()); 5346 fail("listeners that don't have a companion device shouldn't be able to call this"); 5347 } catch (SecurityException e) { 5348 // pass 5349 } 5350 5351 verify(mPreferencesHelper, never()).getNotificationChannelGroupsWithoutChannels(anyString(), 5352 anyInt()); 5353 } 5354 5355 @Test testGetPackagesWithChannels_blocked()5356 public void testGetPackagesWithChannels_blocked() throws Exception { 5357 // While we mostly rely on the PreferencesHelper implementation of channels, we filter in 5358 // NMS so that we do not return blocked packages. 5359 // Three packages; all under user 1. 5360 // pkg2 is blocked, but pkg1 and pkg3 are not. 5361 String pkg1 = "com.package.one", pkg2 = "com.package.two", pkg3 = "com.package.three"; 5362 int uid1 = UserHandle.getUid(1, 111); 5363 int uid2 = UserHandle.getUid(1, 222); 5364 int uid3 = UserHandle.getUid(1, 333); 5365 5366 when(mPackageManager.getPackageUid(eq(pkg1), anyLong(), anyInt())).thenReturn(uid1); 5367 when(mPackageManager.getPackageUid(eq(pkg2), anyLong(), anyInt())).thenReturn(uid2); 5368 when(mPackageManager.getPackageUid(eq(pkg3), anyLong(), anyInt())).thenReturn(uid3); 5369 when(mPermissionHelper.hasPermission(uid1)).thenReturn(true); 5370 when(mPermissionHelper.hasPermission(uid2)).thenReturn(false); 5371 when(mPermissionHelper.hasPermission(uid3)).thenReturn(true); 5372 5373 NotificationChannel channel1 = new NotificationChannel("id1", "name1", 5374 NotificationManager.IMPORTANCE_DEFAULT); 5375 NotificationChannel channel2 = new NotificationChannel("id3", "name3", 5376 NotificationManager.IMPORTANCE_DEFAULT); 5377 NotificationChannel channel3 = new NotificationChannel("id4", "name3", 5378 NotificationManager.IMPORTANCE_DEFAULT); 5379 mService.mPreferencesHelper.createNotificationChannel(pkg1, uid1, channel1, true, false, 5380 uid1, false); 5381 mService.mPreferencesHelper.createNotificationChannel(pkg2, uid2, channel2, true, false, 5382 uid2, false); 5383 mService.mPreferencesHelper.createNotificationChannel(pkg3, uid3, channel3, true, false, 5384 uid3, false); 5385 5386 // Output should contain only the package with notification permissions (1, 3). 5387 enableInteractAcrossUsers(); 5388 assertThat(mBinderService.getPackagesWithAnyChannels(1)).containsExactly(pkg1, pkg3); 5389 } 5390 5391 @Test testHasCompanionDevice_failure()5392 public void testHasCompanionDevice_failure() throws Exception { 5393 when(mCompanionMgr.getAssociations(anyString(), anyInt())).thenThrow( 5394 new IllegalArgumentException()); 5395 mService.hasCompanionDevice(mListener); 5396 } 5397 5398 @Test testHasCompanionDevice_noService()5399 public void testHasCompanionDevice_noService() { 5400 NotificationManagerService noManService = 5401 new TestableNotificationManagerService(mContext, mNotificationRecordLogger, 5402 mNotificationInstanceIdSequence); 5403 5404 assertFalse(noManService.hasCompanionDevice(mListener)); 5405 } 5406 5407 @Test testCrossUserSnooze()5408 public void testCrossUserSnooze() { 5409 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); 5410 mService.addNotification(r); 5411 NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); 5412 mService.addNotification(r2); 5413 5414 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5415 mListener.component = new ComponentName(mPkg, mPkg); 5416 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false); 5417 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5418 5419 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5420 r.getKey(), 1000, null); 5421 5422 verify(mWorkerHandler, never()).post( 5423 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5424 } 5425 5426 @Test testSameUserSnooze()5427 public void testSameUserSnooze() { 5428 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10); 5429 mService.addNotification(r); 5430 NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0); 5431 mService.addNotification(r2); 5432 5433 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5434 mListener.component = new ComponentName(mPkg, mPkg); 5435 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5436 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5437 5438 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5439 r2.getKey(), 1000, null); 5440 5441 verify(mWorkerHandler).post( 5442 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5443 } 5444 5445 @Test snoozeNotificationInt_rapidSnooze_new()5446 public void snoozeNotificationInt_rapidSnooze_new() { 5447 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 5448 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5449 5450 // Create recent notification. 5451 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5452 System.currentTimeMillis()); 5453 mService.addNotification(nr1); 5454 5455 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5456 mListener.component = new ComponentName(mPkg, mPkg); 5457 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5458 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5459 5460 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5461 nr1.getKey(), 1000, null); 5462 5463 verify(mWorkerHandler).post( 5464 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5465 // Ensure cancel event is logged. 5466 verify(mAppOpsManager).noteOpNoThrow( 5467 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, 5468 null); 5469 } 5470 5471 @Test snoozeNotificationInt_rapidSnooze_old()5472 public void snoozeNotificationInt_rapidSnooze_old() { 5473 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 5474 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5475 5476 // Create old notification. 5477 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5478 System.currentTimeMillis() - 60000); 5479 mService.addNotification(nr1); 5480 5481 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5482 mListener.component = new ComponentName(mPkg, mPkg); 5483 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5484 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5485 5486 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5487 nr1.getKey(), 1000, null); 5488 5489 verify(mWorkerHandler).post( 5490 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5491 // Ensure cancel event is not logged. 5492 verify(mAppOpsManager, never()).noteOpNoThrow( 5493 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 5494 any(), any()); 5495 } 5496 5497 @Test snoozeNotificationInt_rapidSnooze_new_flagDisabled()5498 public void snoozeNotificationInt_rapidSnooze_new_flagDisabled() { 5499 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 5500 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5501 5502 // Create recent notification. 5503 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5504 System.currentTimeMillis()); 5505 mService.addNotification(nr1); 5506 5507 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5508 mListener.component = new ComponentName(mPkg, mPkg); 5509 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5510 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5511 5512 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5513 nr1.getKey(), 1000, null); 5514 5515 verify(mWorkerHandler).post( 5516 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5517 // Ensure cancel event is not logged. 5518 verify(mAppOpsManager, never()).noteOpNoThrow( 5519 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 5520 any(), any()); 5521 } 5522 5523 @Test snoozeNotificationInt_rapidSnooze_old_flagDisabled()5524 public void snoozeNotificationInt_rapidSnooze_old_flagDisabled() { 5525 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 5526 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 5527 5528 // Create old notification. 5529 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 5530 System.currentTimeMillis() - 60000); 5531 mService.addNotification(nr1); 5532 5533 mListener = mock(ManagedServices.ManagedServiceInfo.class); 5534 mListener.component = new ComponentName(mPkg, mPkg); 5535 when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true); 5536 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 5537 5538 mService.snoozeNotificationInt(Binder.getCallingUid(), mock(INotificationListener.class), 5539 nr1.getKey(), 1000, null); 5540 5541 verify(mWorkerHandler).post( 5542 any(NotificationManagerService.SnoozeNotificationRunnable.class)); 5543 // Ensure cancel event is not logged. 5544 verify(mAppOpsManager, never()).noteOpNoThrow( 5545 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 5546 any(), any()); 5547 } 5548 5549 @Test testSnoozeRunnable_tooManySnoozed_singleNotification()5550 public void testSnoozeRunnable_tooManySnoozed_singleNotification() { 5551 final NotificationRecord notification = generateNotificationRecord( 5552 mTestNotificationChannel, 1, null, true); 5553 mService.addNotification(notification); 5554 5555 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5556 when(mSnoozeHelper.canSnooze(1)).thenReturn(false); 5557 5558 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5559 mService.new SnoozeNotificationRunnable( 5560 notification.getKey(), 100, null); 5561 snoozeNotificationRunnable.run(); 5562 5563 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 5564 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 5565 } 5566 5567 @Test testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification()5568 public void testSnoozeRunnable_tooManySnoozed_singleGroupChildNotification() { 5569 final NotificationRecord notification = generateNotificationRecord( 5570 mTestNotificationChannel, 1, "group", true); 5571 final NotificationRecord notificationChild = generateNotificationRecord( 5572 mTestNotificationChannel, 1, "group", false); 5573 mService.addNotification(notification); 5574 mService.addNotification(notificationChild); 5575 5576 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5577 when(mSnoozeHelper.canSnooze(2)).thenReturn(false); 5578 5579 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5580 mService.new SnoozeNotificationRunnable( 5581 notificationChild.getKey(), 100, null); 5582 snoozeNotificationRunnable.run(); 5583 5584 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 5585 assertThat(mService.getNotificationRecordCount()).isEqualTo(2); 5586 } 5587 5588 @Test testSnoozeRunnable_tooManySnoozed_summaryNotification()5589 public void testSnoozeRunnable_tooManySnoozed_summaryNotification() { 5590 final NotificationRecord notification = generateNotificationRecord( 5591 mTestNotificationChannel, 1, "group", true); 5592 final NotificationRecord notificationChild = generateNotificationRecord( 5593 mTestNotificationChannel, 12, "group", false); 5594 final NotificationRecord notificationChild2 = generateNotificationRecord( 5595 mTestNotificationChannel, 13, "group", false); 5596 mService.addNotification(notification); 5597 mService.addNotification(notificationChild); 5598 mService.addNotification(notificationChild2); 5599 5600 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5601 when(mSnoozeHelper.canSnooze(3)).thenReturn(false); 5602 5603 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5604 mService.new SnoozeNotificationRunnable( 5605 notification.getKey(), 100, null); 5606 snoozeNotificationRunnable.run(); 5607 5608 verify(mSnoozeHelper, never()).snooze(any(NotificationRecord.class), anyLong()); 5609 assertThat(mService.getNotificationRecordCount()).isEqualTo(3); 5610 } 5611 5612 @Test testSnoozeRunnable_reSnoozeASingleSnoozedNotification()5613 public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() { 5614 final NotificationRecord notification = generateNotificationRecord( 5615 mTestNotificationChannel, 1, null, true); 5616 mService.addNotification(notification); 5617 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 5618 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5619 5620 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5621 mService.new SnoozeNotificationRunnable( 5622 notification.getKey(), 100, null); 5623 snoozeNotificationRunnable.run(); 5624 snoozeNotificationRunnable.run(); 5625 5626 // snooze twice 5627 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 5628 } 5629 5630 @Test testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey()5631 public void testSnoozeRunnable_reSnoozeASnoozedNotificationWithGroupKey() { 5632 final NotificationRecord notification = generateNotificationRecord( 5633 mTestNotificationChannel, 1, "group", true); 5634 mService.addNotification(notification); 5635 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 5636 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5637 5638 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5639 mService.new SnoozeNotificationRunnable( 5640 notification.getKey(), 100, null); 5641 snoozeNotificationRunnable.run(); 5642 snoozeNotificationRunnable.run(); 5643 5644 // snooze twice 5645 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 5646 } 5647 5648 @Test testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey()5649 public void testSnoozeRunnable_reSnoozeMultipleNotificationsWithGroupKey() throws Exception { 5650 final NotificationRecord notification = generateNotificationRecord( 5651 mTestNotificationChannel, 1, "group", true); 5652 final NotificationRecord notification2 = generateNotificationRecord( 5653 mTestNotificationChannel, 2, "group", true); 5654 mService.addNotification(notification); 5655 mService.addNotification(notification2); 5656 when(mSnoozeHelper.getNotification(any())).thenReturn(notification); 5657 when(mSnoozeHelper.getNotifications( 5658 anyString(), anyString(), anyInt())).thenReturn(new ArrayList<>()); 5659 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5660 5661 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5662 mService.new SnoozeNotificationRunnable( 5663 notification.getKey(), 100, null); 5664 snoozeNotificationRunnable.run(); 5665 when(mSnoozeHelper.getNotifications(anyString(), anyString(), anyInt())) 5666 .thenReturn(new ArrayList<>(Arrays.asList(notification, notification2))); 5667 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable2 = 5668 mService.new SnoozeNotificationRunnable( 5669 notification2.getKey(), 100, null); 5670 snoozeNotificationRunnable2.run(); 5671 5672 // snooze twice 5673 verify(mSnoozeHelper, times(4)).snooze(any(NotificationRecord.class), anyLong()); 5674 } 5675 5676 @Test testSnoozeRunnable_snoozeNonGrouped()5677 public void testSnoozeRunnable_snoozeNonGrouped() throws Exception { 5678 final NotificationRecord nonGrouped = generateNotificationRecord( 5679 mTestNotificationChannel, 1, null, false); 5680 final NotificationRecord grouped = generateNotificationRecord( 5681 mTestNotificationChannel, 2, "group", false); 5682 mService.addNotification(grouped); 5683 mService.addNotification(nonGrouped); 5684 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5685 5686 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5687 mService.new SnoozeNotificationRunnable( 5688 nonGrouped.getKey(), 100, null); 5689 snoozeNotificationRunnable.run(); 5690 5691 // only snooze the one notification 5692 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5693 assertTrue(nonGrouped.getStats().hasSnoozed()); 5694 5695 assertEquals(2, mNotificationRecordLogger.numCalls()); 5696 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5697 mNotificationRecordLogger.event(0)); 5698 assertEquals( 5699 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5700 mNotificationRecordLogger.event(1)); 5701 } 5702 5703 @Test testSnoozeRunnable_snoozeSummary_withChildren()5704 public void testSnoozeRunnable_snoozeSummary_withChildren() throws Exception { 5705 final NotificationRecord parent = generateNotificationRecord( 5706 mTestNotificationChannel, 1, "group", true); 5707 final NotificationRecord child = generateNotificationRecord( 5708 mTestNotificationChannel, 2, "group", false); 5709 final NotificationRecord child2 = generateNotificationRecord( 5710 mTestNotificationChannel, 3, "group", false); 5711 mService.addNotification(parent); 5712 mService.addNotification(child); 5713 mService.addNotification(child2); 5714 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5715 5716 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5717 mService.new SnoozeNotificationRunnable( 5718 parent.getKey(), 100, null); 5719 snoozeNotificationRunnable.run(); 5720 5721 // snooze parent and children 5722 verify(mSnoozeHelper, times(3)).snooze(any(NotificationRecord.class), anyLong()); 5723 } 5724 5725 @Test testSnoozeRunnable_snoozeGroupChild_fellowChildren()5726 public void testSnoozeRunnable_snoozeGroupChild_fellowChildren() throws Exception { 5727 final NotificationRecord parent = generateNotificationRecord( 5728 mTestNotificationChannel, 1, "group", true); 5729 final NotificationRecord child = generateNotificationRecord( 5730 mTestNotificationChannel, 2, "group", false); 5731 final NotificationRecord child2 = generateNotificationRecord( 5732 mTestNotificationChannel, 3, "group", false); 5733 mService.addNotification(parent); 5734 mService.addNotification(child); 5735 mService.addNotification(child2); 5736 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5737 5738 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5739 mService.new SnoozeNotificationRunnable( 5740 child2.getKey(), 100, null); 5741 snoozeNotificationRunnable.run(); 5742 5743 // only snooze the one child 5744 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5745 5746 assertEquals(2, mNotificationRecordLogger.numCalls()); 5747 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5748 mNotificationRecordLogger.event(0)); 5749 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 5750 .NOTIFICATION_CANCEL_SNOOZED, mNotificationRecordLogger.event(1)); 5751 } 5752 5753 @Test testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary()5754 public void testSnoozeRunnable_snoozeGroupChild_onlyChildOfSummary() throws Exception { 5755 final NotificationRecord parent = generateNotificationRecord( 5756 mTestNotificationChannel, 1, "group", true); 5757 assertTrue(parent.getSbn().getNotification().isGroupSummary()); 5758 final NotificationRecord child = generateNotificationRecord( 5759 mTestNotificationChannel, 2, "group", false); 5760 mService.addNotification(parent); 5761 mService.addNotification(child); 5762 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5763 5764 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5765 mService.new SnoozeNotificationRunnable( 5766 child.getKey(), 100, null); 5767 snoozeNotificationRunnable.run(); 5768 5769 // snooze child and summary 5770 verify(mSnoozeHelper, times(2)).snooze(any(NotificationRecord.class), anyLong()); 5771 5772 assertEquals(4, mNotificationRecordLogger.numCalls()); 5773 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5774 mNotificationRecordLogger.event(0)); 5775 assertEquals( 5776 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5777 mNotificationRecordLogger.event(1)); 5778 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5779 mNotificationRecordLogger.event(2)); 5780 assertEquals( 5781 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5782 mNotificationRecordLogger.event(3)); 5783 } 5784 5785 @Test testSnoozeRunnable_snoozeGroupChild_noOthersInGroup()5786 public void testSnoozeRunnable_snoozeGroupChild_noOthersInGroup() throws Exception { 5787 final NotificationRecord child = generateNotificationRecord( 5788 mTestNotificationChannel, 2, "group", false); 5789 mService.addNotification(child); 5790 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5791 5792 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5793 mService.new SnoozeNotificationRunnable( 5794 child.getKey(), 100, null); 5795 snoozeNotificationRunnable.run(); 5796 5797 // snooze child only 5798 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5799 5800 assertEquals(2, mNotificationRecordLogger.numCalls()); 5801 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5802 mNotificationRecordLogger.event(0)); 5803 assertEquals( 5804 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5805 mNotificationRecordLogger.event(1)); 5806 } 5807 5808 @Test 5809 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed()5810 public void testSnoozeRunnable_snoozeAutoGroupChild_summaryNotSnoozed() throws Exception { 5811 final NotificationRecord parent = generateNotificationRecord( 5812 mTestNotificationChannel, 1, GroupHelper.AUTOGROUP_KEY, true); 5813 final NotificationRecord child = generateNotificationRecord( 5814 mTestNotificationChannel, 2, GroupHelper.AUTOGROUP_KEY, false); 5815 mService.addNotification(parent); 5816 mService.addNotification(child); 5817 when(mSnoozeHelper.canSnooze(anyInt())).thenReturn(true); 5818 5819 // snooze child only 5820 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5821 mService.new SnoozeNotificationRunnable( 5822 child.getKey(), 100, null); 5823 snoozeNotificationRunnable.run(); 5824 5825 // only child should be snoozed 5826 verify(mSnoozeHelper, times(1)).snooze(any(NotificationRecord.class), anyLong()); 5827 5828 // both group summary and child should be cancelled 5829 assertNull(mService.getNotificationRecord(parent.getKey())); 5830 assertNull(mService.getNotificationRecord(child.getKey())); 5831 5832 assertEquals(4, mNotificationRecordLogger.numCalls()); 5833 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SNOOZED, 5834 mNotificationRecordLogger.event(0)); 5835 assertEquals( 5836 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_SNOOZED, 5837 mNotificationRecordLogger.event(1)); 5838 } 5839 5840 @Test testPostGroupChild_unsnoozeParent()5841 public void testPostGroupChild_unsnoozeParent() throws Exception { 5842 final NotificationRecord child = generateNotificationRecord( 5843 mTestNotificationChannel, 2, "group", false); 5844 5845 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing", 5846 child.getSbn().getId(), child.getSbn().getNotification(), 5847 child.getSbn().getUserId()); 5848 waitForIdle(); 5849 5850 verify(mSnoozeHelper, times(1)).repostGroupSummary( 5851 anyString(), anyInt(), eq(child.getGroupKey())); 5852 } 5853 5854 @Test testPostNonGroup_noUnsnoozing()5855 public void testPostNonGroup_noUnsnoozing() throws Exception { 5856 final NotificationRecord record = generateNotificationRecord( 5857 mTestNotificationChannel, 2, null, false); 5858 5859 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostNonGroup_noUnsnoozing", 5860 record.getSbn().getId(), record.getSbn().getNotification(), 5861 record.getSbn().getUserId()); 5862 waitForIdle(); 5863 5864 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString()); 5865 } 5866 5867 @Test testPostGroupSummary_noUnsnoozing()5868 public void testPostGroupSummary_noUnsnoozing() throws Exception { 5869 final NotificationRecord parent = generateNotificationRecord( 5870 mTestNotificationChannel, 2, "group", true); 5871 5872 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testPostGroupSummary_noUnsnoozing", 5873 parent.getSbn().getId(), parent.getSbn().getNotification(), 5874 parent.getSbn().getUserId()); 5875 waitForIdle(); 5876 5877 verify(mSnoozeHelper, never()).repostGroupSummary(anyString(), anyInt(), anyString()); 5878 } 5879 5880 @Test testSystemNotificationListenerCanUnsnooze()5881 public void testSystemNotificationListenerCanUnsnooze() throws Exception { 5882 final NotificationRecord nr = generateNotificationRecord( 5883 mTestNotificationChannel, 2, "group", false); 5884 5885 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 5886 "testSystemNotificationListenerCanUnsnooze", 5887 nr.getSbn().getId(), nr.getSbn().getNotification(), 5888 nr.getSbn().getUserId()); 5889 waitForIdle(); 5890 NotificationManagerService.SnoozeNotificationRunnable snoozeNotificationRunnable = 5891 mService.new SnoozeNotificationRunnable( 5892 nr.getKey(), 100, null); 5893 snoozeNotificationRunnable.run(); 5894 5895 ManagedServices.ManagedServiceInfo listener = mListeners.new ManagedServiceInfo( 5896 null, new ComponentName(mPkg, "test_class"), mUid, true, null, 0, 234); 5897 listener.isSystem = true; 5898 when(mListeners.checkServiceTokenLocked(any())).thenReturn(listener); 5899 5900 mBinderService.unsnoozeNotificationFromSystemListener(null, nr.getKey()); 5901 waitForIdle(); 5902 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 5903 assertEquals(1, notifs.length); 5904 assertNotNull(notifs[0].getKey());//mService.getNotificationRecord(nr.getSbn().getKey())); 5905 } 5906 5907 @Test testSetListenerAccessForUser()5908 public void testSetListenerAccessForUser() throws Exception { 5909 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5910 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5911 mBinderService.setNotificationListenerAccessGrantedForUser( 5912 c, user.getIdentifier(), true, true); 5913 5914 5915 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 5916 verify(mListeners, times(1)).setPackageOrComponentEnabled( 5917 c.flattenToString(), user.getIdentifier(), true, true, true); 5918 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5919 c.flattenToString(), user.getIdentifier(), false, true, true); 5920 verify(mAssistants, never()).setPackageOrComponentEnabled( 5921 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 5922 } 5923 5924 @Test testSetListenerAccessForUser_grantWithNameTooLong_throws()5925 public void testSetListenerAccessForUser_grantWithNameTooLong_throws() { 5926 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5927 ComponentName c = new ComponentName("com.example.package", 5928 com.google.common.base.Strings.repeat("Blah", 150)); 5929 5930 assertThrows(IllegalArgumentException.class, 5931 () -> mBinderService.setNotificationListenerAccessGrantedForUser( 5932 c, user.getIdentifier(), /* enabled= */ true, true)); 5933 } 5934 5935 @Test testSetListenerAccessForUser_revokeWithNameTooLong_okay()5936 public void testSetListenerAccessForUser_revokeWithNameTooLong_okay() throws Exception { 5937 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5938 ComponentName c = new ComponentName("com.example.package", 5939 com.google.common.base.Strings.repeat("Blah", 150)); 5940 5941 mBinderService.setNotificationListenerAccessGrantedForUser( 5942 c, user.getIdentifier(), /* enabled= */ false, true); 5943 5944 verify(mListeners).setPackageOrComponentEnabled( 5945 c.flattenToString(), user.getIdentifier(), true, /* enabled= */ false, true); 5946 } 5947 5948 @Test testSetAssistantAccessForUser()5949 public void testSetAssistantAccessForUser() throws Exception { 5950 UserInfo ui = new UserInfo(); 5951 ui.id = mContext.getUserId() + 10; 5952 UserHandle user = UserHandle.of(ui.id); 5953 List<UserInfo> uis = new ArrayList<>(); 5954 uis.add(ui); 5955 ComponentName c = ComponentName.unflattenFromString("package/Component"); 5956 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 5957 5958 mBinderService.setNotificationAssistantAccessGrantedForUser(c, user.getIdentifier(), true); 5959 5960 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 5961 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 5962 c.flattenToString(), user.getIdentifier(), true, true, true); 5963 verify(mAssistants).setUserSet(ui.id, true); 5964 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 5965 c.flattenToString(), user.getIdentifier(), false, true); 5966 verify(mListeners, never()).setPackageOrComponentEnabled( 5967 any(), anyInt(), anyBoolean(), anyBoolean()); 5968 } 5969 5970 @Test testGetAssistantAllowedForUser()5971 public void testGetAssistantAllowedForUser() throws Exception { 5972 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 5973 try { 5974 mBinderService.getAllowedNotificationAssistantForUser(user.getIdentifier()); 5975 } catch (IllegalStateException e) { 5976 if (!e.getMessage().contains("At most one NotificationAssistant")) { 5977 throw e; 5978 } 5979 } 5980 verify(mAssistants, times(1)).getAllowedComponents(user.getIdentifier()); 5981 } 5982 5983 @Test testGetAssistantAllowed()5984 public void testGetAssistantAllowed() throws Exception { 5985 try { 5986 mBinderService.getAllowedNotificationAssistant(); 5987 } catch (IllegalStateException e) { 5988 if (!e.getMessage().contains("At most one NotificationAssistant")) { 5989 throw e; 5990 } 5991 } 5992 verify(mAssistants, times(1)).getAllowedComponents(mContext.getUserId()); 5993 } 5994 5995 @Test testSetNASMigrationDoneAndResetDefault_enableNAS()5996 public void testSetNASMigrationDoneAndResetDefault_enableNAS() throws Exception { 5997 int userId = 10; 5998 setNASMigrationDone(false, userId); 5999 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 6000 6001 mBinderService.setNASMigrationDoneAndResetDefault(userId, true); 6002 6003 assertTrue(mService.isNASMigrationDone(userId)); 6004 verify(mAssistants, times(1)).resetDefaultFromConfig(); 6005 } 6006 6007 @Test testSetNASMigrationDoneAndResetDefault_disableNAS()6008 public void testSetNASMigrationDoneAndResetDefault_disableNAS() throws Exception { 6009 int userId = 10; 6010 setNASMigrationDone(false, userId); 6011 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 6012 6013 mBinderService.setNASMigrationDoneAndResetDefault(userId, false); 6014 6015 assertTrue(mService.isNASMigrationDone(userId)); 6016 verify(mAssistants, times(1)).clearDefaults(); 6017 } 6018 6019 @Test testSetNASMigrationDoneAndResetDefault_multiProfile()6020 public void testSetNASMigrationDoneAndResetDefault_multiProfile() throws Exception { 6021 int userId1 = 11; 6022 int userId2 = 12; //work profile 6023 setNASMigrationDone(false, userId1); 6024 setNASMigrationDone(false, userId2); 6025 setUsers(new int[]{userId1, userId2}); 6026 when(mUm.isManagedProfile(userId2)).thenReturn(true); 6027 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2}); 6028 6029 mBinderService.setNASMigrationDoneAndResetDefault(userId1, true); 6030 assertTrue(mService.isNASMigrationDone(userId1)); 6031 assertTrue(mService.isNASMigrationDone(userId2)); 6032 } 6033 6034 @Test testSetNASMigrationDoneAndResetDefault_multiUser()6035 public void testSetNASMigrationDoneAndResetDefault_multiUser() throws Exception { 6036 int userId1 = 11; 6037 int userId2 = 12; 6038 setNASMigrationDone(false, userId1); 6039 setNASMigrationDone(false, userId2); 6040 setUsers(new int[]{userId1, userId2}); 6041 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1}); 6042 when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2}); 6043 6044 mBinderService.setNASMigrationDoneAndResetDefault(userId1, true); 6045 assertTrue(mService.isNASMigrationDone(userId1)); 6046 assertFalse(mService.isNASMigrationDone(userId2)); 6047 } 6048 6049 @Test testSetDndAccessForUser()6050 public void testSetDndAccessForUser() throws Exception { 6051 UserHandle user = UserHandle.of(mContext.getUserId() + 10); 6052 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6053 mBinderService.setNotificationPolicyAccessGrantedForUser( 6054 c.getPackageName(), user.getIdentifier(), true); 6055 6056 verify(mContext, times(1)).sendBroadcastAsUser(any(), eq(user), any()); 6057 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6058 c.getPackageName(), user.getIdentifier(), true, true); 6059 verify(mAssistants, never()).setPackageOrComponentEnabled( 6060 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6061 verify(mListeners, never()).setPackageOrComponentEnabled( 6062 any(), anyInt(), anyBoolean(), anyBoolean()); 6063 } 6064 6065 @Test testSetListenerAccess()6066 public void testSetListenerAccess() throws Exception { 6067 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6068 mBinderService.setNotificationListenerAccessGranted(c, true, true); 6069 6070 verify(mListeners, times(1)).setPackageOrComponentEnabled( 6071 c.flattenToString(), mContext.getUserId(), true, true, true); 6072 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6073 c.flattenToString(), mContext.getUserId(), false, true, true); 6074 verify(mAssistants, never()).setPackageOrComponentEnabled( 6075 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6076 } 6077 6078 @Test testSetAssistantAccess()6079 public void testSetAssistantAccess() throws Exception { 6080 List<UserInfo> uis = new ArrayList<>(); 6081 UserInfo ui = new UserInfo(); 6082 ui.id = mContext.getUserId(); 6083 uis.add(ui); 6084 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6085 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6086 6087 mBinderService.setNotificationAssistantAccessGranted(c, true); 6088 6089 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6090 c.flattenToString(), ui.id, true, true, true); 6091 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6092 c.flattenToString(), ui.id, false, true); 6093 verify(mListeners, never()).setPackageOrComponentEnabled( 6094 any(), anyInt(), anyBoolean(), anyBoolean()); 6095 } 6096 6097 @Test testSetAssistantAccess_multiProfile()6098 public void testSetAssistantAccess_multiProfile() throws Exception { 6099 List<UserInfo> uis = new ArrayList<>(); 6100 UserInfo ui = new UserInfo(); 6101 ui.id = mContext.getUserId(); 6102 uis.add(ui); 6103 UserInfo ui10 = new UserInfo(); 6104 ui10.id = mContext.getUserId() + 10; 6105 uis.add(ui10); 6106 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6107 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6108 6109 mBinderService.setNotificationAssistantAccessGranted(c, true); 6110 6111 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6112 c.flattenToString(), ui.id, true, true, true); 6113 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6114 c.flattenToString(), ui10.id, true, true, true); 6115 6116 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6117 c.flattenToString(), ui.id, false, true); 6118 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6119 c.flattenToString(), ui10.id, false, true); 6120 verify(mListeners, never()).setPackageOrComponentEnabled( 6121 any(), anyInt(), anyBoolean(), anyBoolean()); 6122 } 6123 6124 @Test testSetAssistantAccess_nullWithAllowedAssistant()6125 public void testSetAssistantAccess_nullWithAllowedAssistant() throws Exception { 6126 ArrayList<ComponentName> componentList = new ArrayList<>(); 6127 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6128 componentList.add(c); 6129 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 6130 List<UserInfo> uis = new ArrayList<>(); 6131 UserInfo ui = new UserInfo(); 6132 ui.id = mContext.getUserId(); 6133 uis.add(ui); 6134 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6135 6136 mBinderService.setNotificationAssistantAccessGranted(null, true); 6137 6138 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6139 c.flattenToString(), ui.id, true, false, true); 6140 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6141 c.flattenToString(), ui.id, false, false); 6142 verify(mListeners, never()).setPackageOrComponentEnabled( 6143 any(), anyInt(), anyBoolean(), anyBoolean()); 6144 } 6145 6146 @Test testSetAssistantAccessForUser_nullWithAllowedAssistant()6147 public void testSetAssistantAccessForUser_nullWithAllowedAssistant() throws Exception { 6148 List<UserInfo> uis = new ArrayList<>(); 6149 UserInfo ui = new UserInfo(); 6150 ui.id = mContext.getUserId() + 10; 6151 uis.add(ui); 6152 UserHandle user = ui.getUserHandle(); 6153 ArrayList<ComponentName> componentList = new ArrayList<>(); 6154 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6155 componentList.add(c); 6156 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 6157 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6158 6159 mBinderService.setNotificationAssistantAccessGrantedForUser( 6160 null, user.getIdentifier(), true); 6161 6162 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6163 c.flattenToString(), user.getIdentifier(), true, false, true); 6164 verify(mAssistants).setUserSet(ui.id, true); 6165 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6166 c.flattenToString(), user.getIdentifier(), false, false); 6167 verify(mListeners, never()).setPackageOrComponentEnabled( 6168 any(), anyInt(), anyBoolean(), anyBoolean()); 6169 } 6170 6171 @Test testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant()6172 public void testSetAssistantAccessForUser_workProfile_nullWithAllowedAssistant() 6173 throws Exception { 6174 List<UserInfo> uis = new ArrayList<>(); 6175 UserInfo ui = new UserInfo(); 6176 ui.id = mContext.getUserId(); 6177 uis.add(ui); 6178 UserInfo ui10 = new UserInfo(); 6179 ui10.id = mContext.getUserId() + 10; 6180 uis.add(ui10); 6181 UserHandle user = ui.getUserHandle(); 6182 ArrayList<ComponentName> componentList = new ArrayList<>(); 6183 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6184 componentList.add(c); 6185 when(mAssistants.getAllowedComponents(anyInt())).thenReturn(componentList); 6186 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6187 6188 mBinderService.setNotificationAssistantAccessGrantedForUser( 6189 null, user.getIdentifier(), true); 6190 6191 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6192 c.flattenToString(), user.getIdentifier(), true, false, true); 6193 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6194 c.flattenToString(), ui10.id, true, false, true); 6195 verify(mAssistants).setUserSet(ui.id, true); 6196 verify(mAssistants).setUserSet(ui10.id, true); 6197 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6198 c.flattenToString(), user.getIdentifier(), false, false); 6199 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6200 c.flattenToString(), ui10.id, false, false); 6201 verify(mListeners, never()).setPackageOrComponentEnabled( 6202 any(), anyInt(), anyBoolean(), anyBoolean()); 6203 } 6204 6205 @Test testSetDndAccess()6206 public void testSetDndAccess() throws Exception { 6207 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6208 6209 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 6210 6211 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6212 c.getPackageName(), mContext.getUserId(), true, true); 6213 verify(mAssistants, never()).setPackageOrComponentEnabled( 6214 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6215 verify(mListeners, never()).setPackageOrComponentEnabled( 6216 any(), anyInt(), anyBoolean(), anyBoolean()); 6217 } 6218 6219 @Test testSetListenerAccess_onLowRam()6220 public void testSetListenerAccess_onLowRam() throws Exception { 6221 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6222 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6223 mBinderService.setNotificationListenerAccessGranted(c, true, true); 6224 6225 verify(mListeners).setPackageOrComponentEnabled( 6226 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6227 verify(mConditionProviders).setPackageOrComponentEnabled( 6228 anyString(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6229 verify(mAssistants).migrateToXml(); 6230 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 6231 } 6232 6233 @Test testSetAssistantAccess_onLowRam()6234 public void testSetAssistantAccess_onLowRam() throws Exception { 6235 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6236 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6237 List<UserInfo> uis = new ArrayList<>(); 6238 UserInfo ui = new UserInfo(); 6239 ui.id = mContext.getUserId(); 6240 uis.add(ui); 6241 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6242 6243 mBinderService.setNotificationAssistantAccessGranted(c, true); 6244 6245 verify(mListeners).migrateToXml(); 6246 verify(mConditionProviders).setPackageOrComponentEnabled( 6247 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6248 verify(mAssistants).migrateToXml(); 6249 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 6250 } 6251 6252 @Test testSetDndAccess_onLowRam()6253 public void testSetDndAccess_onLowRam() throws Exception { 6254 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6255 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6256 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 6257 6258 verify(mListeners).migrateToXml(); 6259 verify(mConditionProviders).setPackageOrComponentEnabled( 6260 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6261 verify(mAssistants).migrateToXml(); 6262 verify(mAssistants).resetDefaultAssistantsIfNecessary(); 6263 } 6264 6265 @Test testSetListenerAccess_doesNothingOnLowRam_exceptWatch()6266 public void testSetListenerAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 6267 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 6268 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6269 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6270 6271 mBinderService.setNotificationListenerAccessGranted(c, true, true); 6272 6273 verify(mListeners, times(1)).setPackageOrComponentEnabled( 6274 c.flattenToString(), mContext.getUserId(), true, true, true); 6275 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6276 c.flattenToString(), mContext.getUserId(), false, true, true); 6277 verify(mAssistants, never()).setPackageOrComponentEnabled( 6278 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6279 } 6280 6281 @Test testSetAssistantAccess_doesNothingOnLowRam_exceptWatch()6282 public void testSetAssistantAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 6283 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 6284 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6285 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6286 List<UserInfo> uis = new ArrayList<>(); 6287 UserInfo ui = new UserInfo(); 6288 ui.id = mContext.getUserId(); 6289 uis.add(ui); 6290 when(mUm.getEnabledProfiles(ui.id)).thenReturn(uis); 6291 6292 mBinderService.setNotificationAssistantAccessGranted(c, true); 6293 6294 verify(mListeners, never()).setPackageOrComponentEnabled( 6295 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6296 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6297 c.flattenToString(), ui.id, false, true); 6298 verify(mAssistants, times(1)).setPackageOrComponentEnabled( 6299 c.flattenToString(), ui.id, true, true, true); 6300 } 6301 6302 @Test testSetDndAccess_doesNothingOnLowRam_exceptWatch()6303 public void testSetDndAccess_doesNothingOnLowRam_exceptWatch() throws Exception { 6304 when(mPackageManagerClient.hasSystemFeature(FEATURE_WATCH)).thenReturn(true); 6305 when(mActivityManager.isLowRamDevice()).thenReturn(true); 6306 ComponentName c = ComponentName.unflattenFromString("package/Component"); 6307 6308 mBinderService.setNotificationPolicyAccessGranted(c.getPackageName(), true); 6309 6310 verify(mListeners, never()).setPackageOrComponentEnabled( 6311 anyString(), anyInt(), anyBoolean(), anyBoolean()); 6312 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 6313 c.getPackageName(), mContext.getUserId(), true, true); 6314 verify(mAssistants, never()).setPackageOrComponentEnabled( 6315 any(), anyInt(), anyBoolean(), anyBoolean(), anyBoolean()); 6316 } 6317 6318 @Test testOnlyAutogroupIfNeeded_newNotification_ghUpdate()6319 public void testOnlyAutogroupIfNeeded_newNotification_ghUpdate() { 6320 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 6321 mService.addEnqueuedNotification(r); 6322 NotificationManagerService.PostNotificationRunnable runnable = 6323 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 6324 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6325 runnable.run(); 6326 waitForIdle(); 6327 6328 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 6329 } 6330 6331 @Test testOnlyAutogroupIfNeeded_groupChanged_ghUpdate()6332 public void testOnlyAutogroupIfNeeded_groupChanged_ghUpdate() { 6333 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 6334 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", "group", false); 6335 mService.addNotification(r); 6336 6337 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 6338 "testOnlyAutogroupIfNeeded_groupChanged_ghUpdate", null, false); 6339 mService.addEnqueuedNotification(update); 6340 NotificationManagerService.PostNotificationRunnable runnable = 6341 mService.new PostNotificationRunnable(update.getKey(), 6342 update.getSbn().getPackageName(), update.getUid(), 6343 mPostNotificationTrackerFactory.newTracker(null)); 6344 runnable.run(); 6345 waitForIdle(); 6346 6347 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 6348 } 6349 6350 @Test testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate()6351 public void testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate() { 6352 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 6353 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", "group", false); 6354 mService.addNotification(r); 6355 6356 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 6357 "testOnlyAutogroupIfNeeded_flagsChanged_ghUpdate", null, false); 6358 update.getNotification().flags = FLAG_AUTO_CANCEL; 6359 mService.addEnqueuedNotification(update); 6360 NotificationManagerService.PostNotificationRunnable runnable = 6361 mService.new PostNotificationRunnable(update.getKey(), 6362 update.getSbn().getPackageName(), update.getUid(), 6363 mPostNotificationTrackerFactory.newTracker(null)); 6364 runnable.run(); 6365 waitForIdle(); 6366 6367 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 6368 } 6369 6370 @Test testOnlyAutogroupIfNeeded_channelChanged_ghUpdate()6371 public void testOnlyAutogroupIfNeeded_channelChanged_ghUpdate() { 6372 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 6373 "testOnlyAutogroupIfNeeded_channelChanged_ghUpdate", null, false); 6374 mService.addNotification(r); 6375 6376 NotificationRecord update = generateNotificationRecord(mSilentChannel, 0, 6377 "testOnlyAutogroupIfNeeded_channelChanged_ghUpdate", null, false); 6378 mService.addEnqueuedNotification(update); 6379 6380 NotificationManagerService.PostNotificationRunnable runnable = 6381 mService.new PostNotificationRunnable(update.getKey(), 6382 update.getSbn().getPackageName(), update.getUid(), 6383 mPostNotificationTrackerFactory.newTracker(null)); 6384 runnable.run(); 6385 waitForIdle(); 6386 6387 verify(mGroupHelper, times(1)).onNotificationPosted(any(), anyBoolean()); 6388 } 6389 6390 @Test testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate()6391 public void testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate() { 6392 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, 6393 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); 6394 mService.addNotification(r); 6395 NotificationRecord update = generateNotificationRecord(mTestNotificationChannel, 0, 6396 "testOnlyAutogroupIfGroupChanged_noValidChange_noGhUpdate", null, false); 6397 update.getNotification().color = Color.BLACK; 6398 mService.addEnqueuedNotification(update); 6399 6400 NotificationManagerService.PostNotificationRunnable runnable = 6401 mService.new PostNotificationRunnable(update.getKey(), 6402 update.getSbn().getPackageName(), 6403 update.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6404 runnable.run(); 6405 waitForIdle(); 6406 6407 verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean()); 6408 } 6409 6410 @Test testDontAutogroupIfCritical()6411 public void testDontAutogroupIfCritical() throws Exception { 6412 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, null, false); 6413 r.setCriticality(CriticalNotificationExtractor.CRITICAL_LOW); 6414 mService.addEnqueuedNotification(r); 6415 NotificationManagerService.PostNotificationRunnable runnable = 6416 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 6417 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6418 runnable.run(); 6419 6420 r = generateNotificationRecord(mTestNotificationChannel, 1, null, false); 6421 r.setCriticality(CriticalNotificationExtractor.CRITICAL); 6422 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 6423 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 6424 mService.addEnqueuedNotification(r); 6425 6426 runnable.run(); 6427 waitForIdle(); 6428 6429 verify(mGroupHelper, never()).onNotificationPosted(any(), anyBoolean()); 6430 } 6431 6432 @Test testNoNotificationDuringSetupPermission()6433 public void testNoNotificationDuringSetupPermission() throws Exception { 6434 mContext.getTestablePermissions().setPermission( 6435 android.Manifest.permission.NOTIFICATION_DURING_SETUP, PERMISSION_GRANTED); 6436 Bundle extras = new Bundle(); 6437 extras.putBoolean(EXTRA_ALLOW_DURING_SETUP, true); 6438 Notification.Builder nb = new Notification.Builder(mContext, 6439 mTestNotificationChannel.getId()) 6440 .setContentTitle("foo") 6441 .addExtras(extras) 6442 .setSmallIcon(android.R.drawable.sym_def_app_icon); 6443 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 6444 "testNoNotificationDuringSetupPermission", mUid, 0, 6445 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 6446 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6447 6448 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 6449 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 6450 waitForIdle(); 6451 6452 NotificationRecord posted = mService.findNotificationLocked( 6453 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 6454 6455 assertTrue(posted.getNotification().extras.containsKey(EXTRA_ALLOW_DURING_SETUP)); 6456 } 6457 6458 @Test testNoFakeColorizedPermission()6459 public void testNoFakeColorizedPermission() throws Exception { 6460 mContext.getTestablePermissions().setPermission( 6461 android.Manifest.permission.USE_COLORIZED_NOTIFICATIONS, PERMISSION_DENIED); 6462 Notification.Builder nb = new Notification.Builder(mContext, 6463 mTestNotificationChannel.getId()) 6464 .setContentTitle("foo") 6465 .setColorized(true).setColor(Color.WHITE) 6466 .setFlag(FLAG_CAN_COLORIZE, true) 6467 .setSmallIcon(android.R.drawable.sym_def_app_icon); 6468 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 6469 "testNoFakeColorizedPermission", mUid, 0, 6470 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 6471 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6472 6473 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 6474 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 6475 waitForIdle(); 6476 6477 NotificationRecord posted = mService.findNotificationLocked( 6478 mPkg, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getUserId()); 6479 6480 assertFalse(posted.getNotification().isColorized()); 6481 } 6482 6483 @Test 6484 @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION}) testMediaStyle_enforceNoClearFlagEnabled()6485 public void testMediaStyle_enforceNoClearFlagEnabled() throws RemoteException { 6486 Notification.MediaStyle style = new Notification.MediaStyle(); 6487 Notification.Builder nb = new Notification.Builder(mContext, 6488 mTestNotificationChannel.getId()) 6489 .setStyle(style); 6490 6491 NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag"); 6492 6493 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR); 6494 } 6495 6496 @Test 6497 @EnableCompatChanges({NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION}) testCustomMediaStyle_enforceNoClearFlagEnabled()6498 public void testCustomMediaStyle_enforceNoClearFlagEnabled() throws RemoteException { 6499 Notification.DecoratedMediaCustomViewStyle style = 6500 new Notification.DecoratedMediaCustomViewStyle(); 6501 Notification.Builder nb = new Notification.Builder(mContext, 6502 mTestNotificationChannel.getId()) 6503 .setStyle(style); 6504 6505 NotificationRecord posted = createAndPostNotification(nb, 6506 "testCustomMediaStyleSetNoClearFlag"); 6507 6508 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isEqualTo(FLAG_NO_CLEAR); 6509 } 6510 6511 @Test 6512 @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION) testMediaStyle_enforceNoClearFlagDisabled()6513 public void testMediaStyle_enforceNoClearFlagDisabled() throws RemoteException { 6514 Notification.MediaStyle style = new Notification.MediaStyle(); 6515 Notification.Builder nb = new Notification.Builder(mContext, 6516 mTestNotificationChannel.getId()) 6517 .setStyle(style); 6518 6519 NotificationRecord posted = createAndPostNotification(nb, "testMediaStyleSetNoClearFlag"); 6520 6521 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR); 6522 } 6523 6524 @Test 6525 @DisableCompatChanges(NotificationManagerService.ENFORCE_NO_CLEAR_FLAG_ON_MEDIA_NOTIFICATION) testCustomMediaStyle_enforceNoClearFlagDisabled()6526 public void testCustomMediaStyle_enforceNoClearFlagDisabled() throws RemoteException { 6527 Notification.DecoratedMediaCustomViewStyle style = 6528 new Notification.DecoratedMediaCustomViewStyle(); 6529 Notification.Builder nb = new Notification.Builder(mContext, 6530 mTestNotificationChannel.getId()) 6531 .setStyle(style); 6532 6533 NotificationRecord posted = createAndPostNotification(nb, 6534 "testCustomMediaStyleSetNoClearFlag"); 6535 6536 assertThat(posted.getFlags() & FLAG_NO_CLEAR).isNotEqualTo(FLAG_NO_CLEAR); 6537 } 6538 6539 @Test testMediaStyleRemote_hasPermission()6540 public void testMediaStyleRemote_hasPermission() throws RemoteException { 6541 String deviceName = "device"; 6542 mContext.getTestablePermissions().setPermission( 6543 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_GRANTED); 6544 Notification.MediaStyle style = new Notification.MediaStyle(); 6545 style.setRemotePlaybackInfo(deviceName, 0, null); 6546 Notification.Builder nb = new Notification.Builder(mContext, 6547 mTestNotificationChannel.getId()) 6548 .setStyle(style); 6549 6550 NotificationRecord posted = createAndPostNotification(nb, 6551 "testMediaStyleRemoteHasPermission"); 6552 Bundle extras = posted.getNotification().extras; 6553 6554 assertTrue(extras.containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6555 assertEquals(deviceName, extras.getString(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6556 } 6557 6558 @Test testMediaStyleRemote_noPermission()6559 public void testMediaStyleRemote_noPermission() throws RemoteException { 6560 String deviceName = "device"; 6561 mContext.getTestablePermissions().setPermission( 6562 android.Manifest.permission.MEDIA_CONTENT_CONTROL, PERMISSION_DENIED); 6563 Notification.MediaStyle style = new Notification.MediaStyle(); 6564 style.setRemotePlaybackInfo(deviceName, 0, null); 6565 Notification.Builder nb = new Notification.Builder(mContext, 6566 mTestNotificationChannel.getId()) 6567 .setStyle(style); 6568 6569 NotificationRecord posted = createAndPostNotification(nb, 6570 "testMediaStyleRemoteNoPermission"); 6571 6572 assertFalse(posted.getNotification().extras 6573 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6574 assertFalse(posted.getNotification().extras 6575 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); 6576 assertFalse(posted.getNotification().extras 6577 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); 6578 } 6579 6580 @Test testCustomMediaStyleRemote_noPermission()6581 public void testCustomMediaStyleRemote_noPermission() throws RemoteException { 6582 String deviceName = "device"; 6583 when(mPackageManager.checkPermission( 6584 eq(android.Manifest.permission.MEDIA_CONTENT_CONTROL), any(), anyInt())) 6585 .thenReturn(PERMISSION_DENIED); 6586 Notification.DecoratedMediaCustomViewStyle style = 6587 new Notification.DecoratedMediaCustomViewStyle(); 6588 style.setRemotePlaybackInfo(deviceName, 0, null); 6589 Notification.Builder nb = new Notification.Builder(mContext, 6590 mTestNotificationChannel.getId()) 6591 .setStyle(style); 6592 6593 NotificationRecord posted = createAndPostNotification(nb, 6594 "testCustomMediaStyleRemoteNoPermission"); 6595 6596 assertFalse(posted.getNotification().extras 6597 .containsKey(Notification.EXTRA_MEDIA_REMOTE_DEVICE)); 6598 assertFalse(posted.getNotification().extras 6599 .containsKey(Notification.EXTRA_MEDIA_REMOTE_ICON)); 6600 assertFalse(posted.getNotification().extras 6601 .containsKey(Notification.EXTRA_MEDIA_REMOTE_INTENT)); 6602 } 6603 6604 @Test testSubstituteAppName_hasPermission()6605 public void testSubstituteAppName_hasPermission() throws RemoteException { 6606 String subName = "Substitute Name"; 6607 mContext.getTestablePermissions().setPermission( 6608 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_GRANTED); 6609 Bundle extras = new Bundle(); 6610 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, subName); 6611 Notification.Builder nb = new Notification.Builder(mContext, 6612 mTestNotificationChannel.getId()) 6613 .addExtras(extras); 6614 6615 NotificationRecord posted = createAndPostNotification(nb, 6616 "testSubstituteAppNameHasPermission"); 6617 6618 assertTrue(posted.getNotification().extras 6619 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)); 6620 assertEquals(posted.getNotification().extras 6621 .getString(Notification.EXTRA_SUBSTITUTE_APP_NAME), subName); 6622 } 6623 6624 @Test testSubstituteAppName_noPermission()6625 public void testSubstituteAppName_noPermission() throws RemoteException { 6626 mContext.getTestablePermissions().setPermission( 6627 android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, PERMISSION_DENIED); 6628 Bundle extras = new Bundle(); 6629 extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, "Substitute Name"); 6630 Notification.Builder nb = new Notification.Builder(mContext, 6631 mTestNotificationChannel.getId()) 6632 .addExtras(extras); 6633 6634 NotificationRecord posted = createAndPostNotification(nb, 6635 "testSubstituteAppNameNoPermission"); 6636 6637 assertFalse(posted.getNotification().extras 6638 .containsKey(Notification.EXTRA_SUBSTITUTE_APP_NAME)); 6639 } 6640 6641 @Test testGetNotificationCountLocked()6642 public void testGetNotificationCountLocked() { 6643 String sampleTagToExclude = null; 6644 int sampleIdToExclude = 0; 6645 for (int i = 0; i < 20; i++) { 6646 NotificationRecord r = 6647 generateNotificationRecord(mTestNotificationChannel, i, null, false); 6648 mService.addEnqueuedNotification(r); 6649 6650 } 6651 for (int i = 0; i < 20; i++) { 6652 NotificationRecord r = 6653 generateNotificationRecord(mTestNotificationChannel, i, null, false); 6654 mService.addNotification(r); 6655 sampleTagToExclude = r.getSbn().getTag(); 6656 sampleIdToExclude = i; 6657 } 6658 6659 // another package 6660 Notification n = 6661 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 6662 .setSmallIcon(android.R.drawable.sym_def_app_icon) 6663 .build(); 6664 6665 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, "tag", mUid, 0, 6666 n, UserHandle.getUserHandleForUid(mUid), null, 0); 6667 NotificationRecord otherPackage = 6668 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 6669 mService.addEnqueuedNotification(otherPackage); 6670 mService.addNotification(otherPackage); 6671 6672 // Same notifications are enqueued as posted, everything counts b/c id and tag don't match 6673 // anything that's currently enqueued or posted 6674 int userId = mUserId; 6675 assertEquals(40, 6676 mService.getNotificationCount(mPkg, userId, 0, null)); 6677 assertEquals(40, 6678 mService.getNotificationCount(mPkg, userId, 0, "tag2")); 6679 6680 // return all for package "a" - "banana" tag isn't used 6681 assertEquals(2, 6682 mService.getNotificationCount("a", userId, 0, "banana")); 6683 6684 // exclude a known notification - it's excluded from only the posted list, not enqueued 6685 assertEquals(39, mService.getNotificationCount( 6686 mPkg, userId, sampleIdToExclude, sampleTagToExclude)); 6687 } 6688 6689 @Test testAddAutogroup_requestsSort()6690 public void testAddAutogroup_requestsSort() throws Exception { 6691 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6692 mService.addNotification(r); 6693 mService.addAutogroupKeyLocked(r.getKey(), "grpKey", true); 6694 6695 verify(mRankingHandler, times(1)).requestSort(); 6696 } 6697 6698 @Test testRemoveAutogroup_requestsSort()6699 public void testRemoveAutogroup_requestsSort() throws Exception { 6700 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6701 r.setOverrideGroupKey("TEST"); 6702 mService.addNotification(r); 6703 mService.removeAutogroupKeyLocked(r.getKey()); 6704 6705 verify(mRankingHandler, times(1)).requestSort(); 6706 } 6707 6708 @Test testReaddAutogroup_noSort()6709 public void testReaddAutogroup_noSort() throws Exception { 6710 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6711 r.setOverrideGroupKey("TEST"); 6712 mService.addNotification(r); 6713 mService.addAutogroupKeyLocked(r.getKey(), "grpName", true); 6714 6715 verify(mRankingHandler, never()).requestSort(); 6716 } 6717 6718 @Test 6719 @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST) testAutogroupSuppressSort_noSort()6720 public void testAutogroupSuppressSort_noSort() throws Exception { 6721 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6722 mService.addNotification(r); 6723 mService.addAutogroupKeyLocked(r.getKey(), "grpName", false); 6724 6725 verify(mRankingHandler, never()).requestSort(); 6726 } 6727 6728 @Test 6729 @EnableFlags(android.app.Flags.FLAG_CHECK_AUTOGROUP_BEFORE_POST) testAutogroupOnPost_skipManualSort()6730 public void testAutogroupOnPost_skipManualSort() throws Exception { 6731 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6732 mService.addNotification(r); 6733 verify(mRankingHandler, never()).requestSort(); 6734 } 6735 6736 @Test testHandleRankingSort_sendsUpdateOnSignalExtractorChange()6737 public void testHandleRankingSort_sendsUpdateOnSignalExtractorChange() throws Exception { 6738 mService.setPreferencesHelper(mPreferencesHelper); 6739 NotificationManagerService.WorkerHandler handler = mock( 6740 NotificationManagerService.WorkerHandler.class); 6741 mService.setHandler(handler); 6742 6743 Map<String, Answer> answers = getSignalExtractorSideEffects(); 6744 for (String message : answers.keySet()) { 6745 mService.clearNotifications(); 6746 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6747 mService.addNotification(r); 6748 6749 doAnswer(answers.get(message)).when(mRankingHelper).extractSignals(r); 6750 6751 mService.handleRankingSort(); 6752 } 6753 verify(handler, times(answers.size())).scheduleSendRankingUpdate(); 6754 } 6755 6756 @Test testHandleRankingSort_noUpdateWhenNoSignalChange()6757 public void testHandleRankingSort_noUpdateWhenNoSignalChange() throws Exception { 6758 mService.setRankingHelper(mRankingHelper); 6759 NotificationManagerService.WorkerHandler handler = mock( 6760 NotificationManagerService.WorkerHandler.class); 6761 mService.setHandler(handler); 6762 6763 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 6764 mService.addNotification(r); 6765 6766 mService.handleRankingSort(); 6767 verify(handler, never()).scheduleSendRankingUpdate(); 6768 } 6769 6770 @Test testReadPolicyXml_readApprovedServicesFromXml()6771 public void testReadPolicyXml_readApprovedServicesFromXml() throws Exception { 6772 final String upgradeXml = "<notification-policy version=\"1\">" 6773 + "<ranking></ranking>" 6774 + "<enabled_listeners>" 6775 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 6776 + "</enabled_listeners>" 6777 + "<enabled_assistants>" 6778 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 6779 + "</enabled_assistants>" 6780 + "<dnd_apps>" 6781 + "<service_listing approved=\"test\" user=\"0\" primary=\"true\" />" 6782 + "</dnd_apps>" 6783 + "</notification-policy>"; 6784 mService.readPolicyXml( 6785 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), 6786 false, 6787 UserHandle.USER_ALL, null); 6788 verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 6789 verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 6790 verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt()); 6791 6792 // numbers are inflated for setup 6793 verify(mListeners, times(1)).migrateToXml(); 6794 verify(mConditionProviders, times(1)).migrateToXml(); 6795 verify(mAssistants, times(1)).migrateToXml(); 6796 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 6797 } 6798 6799 @Test testReadPolicyXml_readSnoozedNotificationsFromXml()6800 public void testReadPolicyXml_readSnoozedNotificationsFromXml() throws Exception { 6801 final String upgradeXml = "<notification-policy version=\"1\">" 6802 + "<snoozed-notifications>></snoozed-notifications>" 6803 + "</notification-policy>"; 6804 mService.readPolicyXml( 6805 new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), 6806 false, 6807 UserHandle.USER_ALL, null); 6808 verify(mSnoozeHelper, times(1)).readXml(any(TypedXmlPullParser.class), anyLong()); 6809 } 6810 6811 @Test testReadPolicyXml_readApprovedServicesFromSettings()6812 public void testReadPolicyXml_readApprovedServicesFromSettings() throws Exception { 6813 final String preupgradeXml = "<notification-policy version=\"1\">" 6814 + "<ranking></ranking>" 6815 + "</notification-policy>"; 6816 mService.readPolicyXml( 6817 new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), 6818 false, 6819 UserHandle.USER_ALL, null); 6820 verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt()); 6821 verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt()); 6822 verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt()); 6823 6824 // numbers are inflated for setup 6825 verify(mListeners, times(2)).migrateToXml(); 6826 verify(mConditionProviders, times(2)).migrateToXml(); 6827 verify(mAssistants, times(2)).migrateToXml(); 6828 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 6829 } 6830 6831 @Test testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser()6832 public void testReadPolicyXml_doesNotRestoreManagedServicesForCloneUser() throws Exception { 6833 final String policyXml = "<notification-policy version=\"1\">" 6834 + "<ranking></ranking>" 6835 + "<enabled_listeners>" 6836 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6837 + "</enabled_listeners>" 6838 + "<enabled_assistants>" 6839 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6840 + "</enabled_assistants>" 6841 + "<dnd_apps>" 6842 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6843 + "</dnd_apps>" 6844 + "</notification-policy>"; 6845 UserInfo ui = new UserInfo(10, "Clone", UserInfo.FLAG_PROFILE); 6846 ui.userType = USER_TYPE_PROFILE_CLONE; 6847 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6848 mService.readPolicyXml( 6849 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6850 true, 6851 10, null); 6852 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 6853 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 6854 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 6855 } 6856 6857 @Test testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser()6858 public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception { 6859 final String policyXml = "<notification-policy version=\"1\">" 6860 + "<ranking></ranking>" 6861 + "<enabled_listeners>" 6862 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6863 + "</enabled_listeners>" 6864 + "<enabled_assistants>" 6865 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6866 + "</enabled_assistants>" 6867 + "<dnd_apps>" 6868 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6869 + "</dnd_apps>" 6870 + "</notification-policy>"; 6871 UserInfo ui = new UserInfo(10, "Work", UserInfo.FLAG_PROFILE); 6872 ui.userType = USER_TYPE_PROFILE_MANAGED; 6873 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6874 mService.readPolicyXml( 6875 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6876 true, 6877 10, null); 6878 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 6879 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 6880 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 6881 } 6882 6883 @Test testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser()6884 public void testReadPolicyXml_doesNotRestoreManagedServicesForPrivateUser() throws Exception { 6885 mSetFlagsRule.enableFlags(android.os.Flags.FLAG_ALLOW_PRIVATE_PROFILE, 6886 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 6887 final String policyXml = "<notification-policy version=\"1\">" 6888 + "<ranking></ranking>" 6889 + "<enabled_listeners>" 6890 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6891 + "</enabled_listeners>" 6892 + "<enabled_assistants>" 6893 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6894 + "</enabled_assistants>" 6895 + "<dnd_apps>" 6896 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6897 + "</dnd_apps>" 6898 + "</notification-policy>"; 6899 UserInfo ui = new UserInfo(10, "Private", UserInfo.FLAG_PROFILE); 6900 ui.userType = USER_TYPE_PROFILE_PRIVATE; 6901 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6902 mService.readPolicyXml( 6903 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6904 true, 6905 10, null); 6906 verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10)); 6907 verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10)); 6908 verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10)); 6909 } 6910 6911 @Test testReadPolicyXml_restoresManagedServicesForNonManagedUser()6912 public void testReadPolicyXml_restoresManagedServicesForNonManagedUser() throws Exception { 6913 final String policyXml = "<notification-policy version=\"1\">" 6914 + "<ranking></ranking>" 6915 + "<enabled_listeners>" 6916 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6917 + "</enabled_listeners>" 6918 + "<enabled_assistants>" 6919 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6920 + "</enabled_assistants>" 6921 + "<dnd_apps>" 6922 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />" 6923 + "</dnd_apps>" 6924 + "</notification-policy>"; 6925 UserInfo ui = new UserInfo(); 6926 ui.id = 10; 6927 ui.userType = USER_TYPE_FULL_SECONDARY; 6928 when(mUmInternal.getUserInfo(10)).thenReturn(ui); 6929 mService.readPolicyXml( 6930 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())), 6931 true, 6932 10, null); 6933 verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10)); 6934 verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10)); 6935 verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10)); 6936 } 6937 6938 @Test 6939 @EnableFlags(android.app.Flags.FLAG_BACKUP_RESTORE_LOGGING) testReadPolicyXml_backupRestoreLogging()6940 public void testReadPolicyXml_backupRestoreLogging() throws Exception { 6941 BackupRestoreEventLogger logger = mock(BackupRestoreEventLogger.class); 6942 6943 if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) { 6944 // By default, the ZenModeHelper only has a configuration for the system user. 6945 // If the current user is not the system user, the user must be updated. 6946 mService.mZenModeHelper.onUserSwitched(ActivityManager.getCurrentUser()); 6947 } 6948 UserInfo ui = new UserInfo(ActivityManager.getCurrentUser(), "Clone", UserInfo.FLAG_FULL); 6949 ui.userType = USER_TYPE_FULL_SYSTEM; 6950 when(mUmInternal.getUserInfo(ActivityManager.getCurrentUser())).thenReturn(ui); 6951 when(mPermissionHelper.getNotificationPermissionValues(ActivityManager.getCurrentUser())) 6952 .thenReturn(new ArrayMap<>()); 6953 TypedXmlSerializer serializer = Xml.newFastSerializer(); 6954 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 6955 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 6956 serializer.startDocument(null, true); 6957 mService.writePolicyXml(baos, true, ActivityManager.getCurrentUser(), logger); 6958 serializer.flush(); 6959 6960 mService.readPolicyXml( 6961 new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), 6962 true, ActivityManager.getCurrentUser(), logger); 6963 6964 verify(logger).logItemsBackedUp(DATA_TYPE_ZEN_CONFIG, 1); 6965 verify(logger, never()) 6966 .logItemsBackupFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString()); 6967 6968 verify(logger).logItemsRestored(DATA_TYPE_ZEN_CONFIG, 1); 6969 verify(logger, never()) 6970 .logItemsRestoreFailed(eq(DATA_TYPE_ZEN_CONFIG), anyInt(), anyString()); 6971 } 6972 6973 @Test testLocaleChangedCallsUpdateDefaultZenModeRules()6974 public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception { 6975 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 6976 mService.mZenModeHelper = mZenModeHelper; 6977 mService.mLocaleChangeReceiver.onReceive(mContext, 6978 new Intent(Intent.ACTION_LOCALE_CHANGED)); 6979 6980 verify(mZenModeHelper).updateZenRulesOnLocaleChange(); 6981 } 6982 simulateNotificationTimeout(String notificationKey)6983 private void simulateNotificationTimeout(String notificationKey) { 6984 if (Flags.allNotifsNeedTtl()) { 6985 mService.mNotificationManagerPrivate.timeoutNotification(notificationKey); 6986 } else { 6987 final Bundle extras = new Bundle(); 6988 extras.putString(EXTRA_KEY, notificationKey); 6989 final Intent intent = new Intent(ACTION_NOTIFICATION_TIMEOUT); 6990 intent.putExtras(extras); 6991 mNotificationTimeoutReceiver.onReceive(getContext(), intent); 6992 } 6993 } 6994 6995 @Test testTimeout_CancelsNotification()6996 public void testTimeout_CancelsNotification() throws Exception { 6997 final NotificationRecord notif = generateNotificationRecord( 6998 mTestNotificationChannel, 1, null, false); 6999 mService.addNotification(notif); 7000 7001 simulateNotificationTimeout(notif.getKey()); 7002 waitForIdle(); 7003 7004 // Check that the notification was cancelled. 7005 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 7006 assertThat(notifsAfter.length).isEqualTo(0); 7007 assertThat(mService.getNotificationRecord(notif.getKey())).isNull(); 7008 } 7009 7010 @Test testTimeout_NoCancelForegroundServiceNotification()7011 public void testTimeout_NoCancelForegroundServiceNotification() throws Exception { 7012 // Creates a notification with FLAG_FOREGROUND_SERVICE 7013 final NotificationRecord notif = generateNotificationRecord(null); 7014 notif.getSbn().getNotification().flags = Notification.FLAG_FOREGROUND_SERVICE; 7015 mService.addNotification(notif); 7016 7017 simulateNotificationTimeout(notif.getKey()); 7018 waitForIdle(); 7019 7020 // Check that the notification was not cancelled. 7021 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 7022 assertThat(notifsAfter.length).isEqualTo(1); 7023 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 7024 } 7025 7026 @Test testTimeout_NoCancelUserInitJobNotification()7027 public void testTimeout_NoCancelUserInitJobNotification() throws Exception { 7028 // Create a notification with FLAG_USER_INITIATED_JOB 7029 final NotificationRecord notif = generateNotificationRecord(null); 7030 notif.getSbn().getNotification().flags = Notification.FLAG_USER_INITIATED_JOB; 7031 mService.addNotification(notif); 7032 7033 simulateNotificationTimeout(notif.getKey()); 7034 waitForIdle(); 7035 7036 // Check that the notification was not cancelled. 7037 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 7038 assertThat(notifsAfter.length).isEqualTo(1); 7039 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 7040 } 7041 7042 @Test 7043 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testTimeout_NoCancelLifetimeExtensionNotification()7044 public void testTimeout_NoCancelLifetimeExtensionNotification() throws Exception { 7045 // Create a notification with FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY 7046 final NotificationRecord notif = generateNotificationRecord(null); 7047 notif.getSbn().getNotification().flags = 7048 Notification.FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7049 mService.addNotification(notif); 7050 7051 simulateNotificationTimeout(notif.getKey()); 7052 waitForIdle(); 7053 7054 // Check that the notification was not cancelled. 7055 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 7056 assertThat(notifsAfter.length).isEqualTo(1); 7057 assertThat(mService.getNotificationRecord(notif.getKey())).isEqualTo(notif); 7058 7059 // Checks that a post update is sent. 7060 verify(mWorkerHandler, times(1)) 7061 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 7062 ArgumentCaptor<NotificationRecord> captor = 7063 ArgumentCaptor.forClass(NotificationRecord.class); 7064 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 7065 anyBoolean()); 7066 assertThat(captor.getValue().getNotification().flags 7067 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 7068 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 7069 } 7070 7071 @Test testBumpFGImportance_channelChangePreOApp()7072 public void testBumpFGImportance_channelChangePreOApp() throws Exception { 7073 Notification.Builder nb = new Notification.Builder(mContext, 7074 NotificationChannel.DEFAULT_CHANNEL_ID) 7075 .setContentTitle("foo") 7076 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7077 .setFlag(FLAG_FOREGROUND_SERVICE, true) 7078 .setPriority(Notification.PRIORITY_MIN); 7079 7080 StatusBarNotification sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, 7081 "testBumpFGImportance_channelChangePreOApp", 7082 Binder.getCallingUid(), 0, nb.build(), 7083 UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); 7084 7085 mBinderService.enqueueNotificationWithTag(sbn.getPackageName(), sbn.getOpPkg(), 7086 sbn.getTag(), sbn.getId(), sbn.getNotification(), sbn.getUserId()); 7087 waitForIdle(); 7088 7089 assertEquals(IMPORTANCE_LOW, 7090 mService.getNotificationRecord(sbn.getKey()).getImportance()); 7091 assertEquals(IMPORTANCE_DEFAULT, mBinderService.getPackageImportance( 7092 sbn.getPackageName())); 7093 7094 nb = new Notification.Builder(mContext) 7095 .setContentTitle("foo") 7096 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7097 .setFlag(FLAG_FOREGROUND_SERVICE, true) 7098 .setPriority(Notification.PRIORITY_MIN); 7099 7100 sbn = new StatusBarNotification(PKG_N_MR1, PKG_N_MR1, 9, 7101 "testBumpFGImportance_channelChangePreOApp", Binder.getCallingUid(), 7102 0, nb.build(), UserHandle.getUserHandleForUid(Binder.getCallingUid()), null, 0); 7103 7104 mBinderService.enqueueNotificationWithTag(PKG_N_MR1, PKG_N_MR1, 7105 "testBumpFGImportance_channelChangePreOApp", 7106 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 7107 waitForIdle(); 7108 assertEquals(IMPORTANCE_LOW, 7109 mService.getNotificationRecord(sbn.getKey()).getImportance()); 7110 7111 NotificationChannel defaultChannel = mBinderService.getNotificationChannel( 7112 PKG_N_MR1, mContext.getUserId(), PKG_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID); 7113 assertEquals(IMPORTANCE_LOW, defaultChannel.getImportance()); 7114 } 7115 7116 @Test testStats_updatedOnDirectReply()7117 public void testStats_updatedOnDirectReply() throws Exception { 7118 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7119 mService.addNotification(r); 7120 7121 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7122 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied()); 7123 verify(mAssistants).notifyAssistantNotificationDirectReplyLocked(eq(r)); 7124 7125 assertEquals(1, mNotificationRecordLogger.numCalls()); 7126 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DIRECT_REPLIED, 7127 mNotificationRecordLogger.event(0)); 7128 } 7129 7130 @Test 7131 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_DirectReplyLifetimeExtendedPostsUpdate()7132 public void testStats_DirectReplyLifetimeExtendedPostsUpdate() throws Exception { 7133 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7134 // Marks the notification as having already been lifetime extended and canceled. 7135 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7136 r.setCanceledAfterLifetimeExtension(true); 7137 r.setPostSilently(true); 7138 mService.addNotification(r); 7139 7140 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7141 waitForIdle(); 7142 7143 // At the moment prepareNotifyPostedLocked is called on the listeners, 7144 // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial 7145 // values. 7146 doAnswer( 7147 invocation -> { 7148 int flags = ((NotificationRecord) invocation.getArgument(0)) 7149 .getSbn().getNotification().flags; 7150 assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 7151 boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0)) 7152 .shouldPostSilently(); 7153 assertThat(shouldPostSilently).isTrue(); 7154 return null; 7155 } 7156 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 7157 7158 // Checks that the record gets marked as a direct reply having occurred. 7159 assertThat(mService.getNotificationRecord(r.getKey()).getStats().hasDirectReplied()) 7160 .isTrue(); 7161 // Checks that a post update is sent. 7162 verify(mWorkerHandler, times(1)) 7163 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 7164 ArgumentCaptor<NotificationRecord> captor = 7165 ArgumentCaptor.forClass(NotificationRecord.class); 7166 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 7167 anyBoolean()); 7168 assertThat(captor.getValue().getNotification().flags 7169 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 7170 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 7171 // FLAG_ONLY_ALERT_ONCE was not present on the original notification, so it's not here. 7172 assertThat(captor.getValue().getNotification().flags 7173 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0); 7174 assertThat(captor.getValue().shouldPostSilently()).isTrue(); 7175 assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isTrue(); 7176 } 7177 7178 @Test 7179 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently()7180 public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestorePostSilently() 7181 throws Exception { 7182 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7183 // Marks the notification as having already been lifetime extended and canceled. 7184 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7185 r.setPostSilently(false); 7186 mService.addNotification(r); 7187 7188 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7189 waitForIdle(); 7190 7191 // Checks that a post update is sent with shouldPostSilently set to true. 7192 doAnswer( 7193 invocation -> { 7194 boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0)) 7195 .shouldPostSilently(); 7196 assertThat(shouldPostSilently).isTrue(); 7197 return null; 7198 } 7199 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 7200 7201 // Checks that shouldPostSilently is restored to its false state afterward. 7202 assertThat(mService.getNotificationRecord(r.getKey()).shouldPostSilently()).isFalse(); 7203 } 7204 7205 @Test 7206 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag()7207 public void testStats_DirectReplyLifetimeExtendedPostsUpdate_RestoreOnlyAlertOnceFlag() 7208 throws Exception { 7209 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7210 // Marks the notification as having already been lifetime extended and canceled. 7211 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7212 mService.addNotification(r); 7213 7214 mService.mNotificationDelegate.onNotificationDirectReplied(r.getKey()); 7215 waitForIdle(); 7216 7217 // Checks that a post update is sent with FLAG_ONLY_ALERT_ONCE set to true. 7218 doAnswer( 7219 invocation -> { 7220 int flags = ((NotificationRecord) invocation.getArgument(0)) 7221 .getSbn().getNotification().flags; 7222 assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 7223 return null; 7224 } 7225 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 7226 7227 // Checks that the flag is removed afterward. 7228 assertThat(mService.getNotificationRecord(r.getKey()).getSbn().getNotification().flags 7229 & FLAG_ONLY_ALERT_ONCE).isEqualTo(0); 7230 } 7231 7232 @Test 7233 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds()7234 public void testUpdate_DirectReplyLifetimeExtendedUpdateSucceeds() throws Exception { 7235 // Creates a lifetime extended notification. 7236 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 7237 original.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 7238 mService.addNotification(original); 7239 7240 // Post an update for that notification. 7241 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(), 7242 original.getSbn().getTag(), mUid, 0, 7243 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 7244 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7245 .setContentTitle("new title").build(), 7246 UserHandle.getUserHandleForUid(mUid), null, 0); 7247 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7248 mService.addEnqueuedNotification(update); 7249 7250 NotificationManagerService.PostNotificationRunnable runnable = 7251 mService.new PostNotificationRunnable(update.getKey(), 7252 update.getSbn().getPackageName(), 7253 update.getUid(), 7254 mPostNotificationTrackerFactory.newTracker(null)); 7255 runnable.run(); 7256 waitForIdle(); 7257 7258 // Checks the update was sent, and that update contains the new title, and does not contain 7259 // the lifetime extension flag. 7260 ArgumentCaptor<NotificationRecord> captor = 7261 ArgumentCaptor.forClass(NotificationRecord.class); 7262 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 7263 anyBoolean()); 7264 assertThat(captor.getValue().getNotification().flags 7265 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0); 7266 assertThat(captor.getValue().isCanceledAfterLifetimeExtension()).isFalse(); 7267 assertThat(captor.getValue() 7268 .getNotification().extras.getCharSequence(Notification.EXTRA_TITLE).toString()) 7269 .isEqualTo("new title"); 7270 } 7271 7272 @Test testStats_updatedOnUserExpansion()7273 public void testStats_updatedOnUserExpansion() throws Exception { 7274 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7275 mService.addNotification(r); 7276 7277 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, true, 7278 NOTIFICATION_LOCATION_UNKNOWN); 7279 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 7280 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((true))); 7281 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7282 7283 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), true, false, 7284 NOTIFICATION_LOCATION_UNKNOWN); 7285 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 7286 eq(FLAG_FILTER_TYPE_ALERTING), eq(true), eq((false))); 7287 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7288 7289 assertEquals(2, mNotificationRecordLogger.numCalls()); 7290 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_OPEN_USER, 7291 mNotificationRecordLogger.event(0)); 7292 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_DETAIL_CLOSE_USER, 7293 mNotificationRecordLogger.event(1)); 7294 } 7295 7296 @Test testStats_notUpdatedOnAutoExpansion()7297 public void testStats_notUpdatedOnAutoExpansion() throws Exception { 7298 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7299 mService.addNotification(r); 7300 7301 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 7302 NOTIFICATION_LOCATION_UNKNOWN); 7303 assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7304 verify(mAssistants).notifyAssistantExpansionChangedLocked(eq(r.getSbn()), 7305 eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((true))); 7306 7307 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, false, 7308 NOTIFICATION_LOCATION_UNKNOWN); 7309 assertFalse(mService.getNotificationRecord(r.getKey()).getStats().hasExpanded()); 7310 verify(mAssistants).notifyAssistantExpansionChangedLocked( 7311 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(false), eq((false))); 7312 } 7313 7314 @Test testStats_updatedOnViewSettings()7315 public void testStats_updatedOnViewSettings() throws Exception { 7316 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7317 mService.addNotification(r); 7318 7319 mService.mNotificationDelegate.onNotificationSettingsViewed(r.getKey()); 7320 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasViewedSettings()); 7321 } 7322 7323 @Test testStats_updatedOnVisibilityChanged()7324 public void testStats_updatedOnVisibilityChanged() throws Exception { 7325 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7326 mService.addNotification(r); 7327 7328 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 1, 2, true); 7329 mService.mNotificationDelegate.onNotificationVisibilityChanged( 7330 new NotificationVisibility[] {nv}, new NotificationVisibility[]{}); 7331 verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(true)); 7332 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen()); 7333 mService.mNotificationDelegate.onNotificationVisibilityChanged( 7334 new NotificationVisibility[] {}, new NotificationVisibility[]{nv}); 7335 verify(mAssistants).notifyAssistantVisibilityChangedLocked(eq(r), eq(false)); 7336 assertTrue(mService.getNotificationRecord(r.getKey()).getStats().hasSeen()); 7337 } 7338 7339 @Test testStats_dismissalSurface()7340 public void testStats_dismissalSurface() throws Exception { 7341 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7342 r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7343 mService.addNotification(r); 7344 7345 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); 7346 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(), 7347 r.getKey(), NotificationStats.DISMISSAL_AOD, 7348 NotificationStats.DISMISS_SENTIMENT_POSITIVE, nv); 7349 waitForIdle(); 7350 7351 assertEquals(NotificationStats.DISMISSAL_AOD, r.getStats().getDismissalSurface()); 7352 7353 // Using mService.addNotification() does not generate a NotificationRecordLogger log, 7354 // so we only get the cancel notification. 7355 assertEquals(1, mNotificationRecordLogger.numCalls()); 7356 7357 assertEquals( 7358 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_USER_AOD, 7359 mNotificationRecordLogger.event(0)); 7360 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 7361 } 7362 7363 @Test testStats_dismissalSentiment()7364 public void testStats_dismissalSentiment() throws Exception { 7365 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7366 mService.addNotification(r); 7367 7368 final NotificationVisibility nv = NotificationVisibility.obtain(r.getKey(), 0, 1, true); 7369 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, r.getUserId(), 7370 r.getKey(), NotificationStats.DISMISSAL_AOD, 7371 NotificationStats.DISMISS_SENTIMENT_NEGATIVE, nv); 7372 waitForIdle(); 7373 7374 assertEquals(NotificationStats.DISMISS_SENTIMENT_NEGATIVE, 7375 r.getStats().getDismissalSentiment()); 7376 } 7377 7378 @Test testTextChangedSet_forNewNotifs()7379 public void testTextChangedSet_forNewNotifs() throws Exception { 7380 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 7381 mService.addEnqueuedNotification(original); 7382 7383 NotificationManagerService.PostNotificationRunnable runnable = 7384 mService.new PostNotificationRunnable(original.getKey(), 7385 original.getSbn().getPackageName(), 7386 original.getUid(), 7387 mPostNotificationTrackerFactory.newTracker(null)); 7388 runnable.run(); 7389 waitForIdle(); 7390 7391 assertTrue(original.isTextChanged()); 7392 } 7393 7394 @Test testVisuallyInterruptive_notSeen()7395 public void testVisuallyInterruptive_notSeen() throws Exception { 7396 NotificationRecord original = generateNotificationRecord(mTestNotificationChannel); 7397 mService.addNotification(original); 7398 7399 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, original.getSbn().getId(), 7400 original.getSbn().getTag(), mUid, 0, 7401 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 7402 .setContentTitle("new title").build(), 7403 UserHandle.getUserHandleForUid(mUid), null, 0); 7404 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 7405 mService.addEnqueuedNotification(update); 7406 7407 NotificationManagerService.PostNotificationRunnable runnable = 7408 mService.new PostNotificationRunnable(update.getKey(), 7409 update.getSbn().getPackageName(), 7410 update.getUid(), 7411 mPostNotificationTrackerFactory.newTracker(null)); 7412 runnable.run(); 7413 waitForIdle(); 7414 7415 assertFalse(update.isInterruptive()); 7416 } 7417 7418 @Test testApplyAdjustmentMultiUser()7419 public void testApplyAdjustmentMultiUser() throws Exception { 7420 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7421 mService.addNotification(r); 7422 NotificationManagerService.WorkerHandler handler = mock( 7423 NotificationManagerService.WorkerHandler.class); 7424 mService.setHandler(handler); 7425 7426 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false); 7427 7428 Bundle signals = new Bundle(); 7429 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7430 USER_SENTIMENT_NEGATIVE); 7431 Adjustment adjustment = new Adjustment( 7432 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7433 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 7434 7435 waitForIdle(); 7436 7437 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 7438 } 7439 7440 @Test testAssistantBlockingTriggersCancel()7441 public void testAssistantBlockingTriggersCancel() throws Exception { 7442 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7443 mService.addNotification(r); 7444 NotificationManagerService.WorkerHandler handler = mock( 7445 NotificationManagerService.WorkerHandler.class); 7446 mService.setHandler(handler); 7447 7448 Bundle signals = new Bundle(); 7449 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_NONE); 7450 Adjustment adjustment = new Adjustment( 7451 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7452 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 7453 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 7454 7455 waitForIdle(); 7456 7457 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 7458 verify(handler, times(1)).scheduleCancelNotification(any(), eq(0)); 7459 } 7460 7461 @Test testApplyEnqueuedAdjustmentFromAssistant_singleUser()7462 public void testApplyEnqueuedAdjustmentFromAssistant_singleUser() throws Exception { 7463 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7464 mService.addEnqueuedNotification(r); 7465 NotificationManagerService.WorkerHandler handler = mock( 7466 NotificationManagerService.WorkerHandler.class); 7467 mService.setHandler(handler); 7468 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7469 7470 Bundle signals = new Bundle(); 7471 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7472 USER_SENTIMENT_NEGATIVE); 7473 Adjustment adjustment = new Adjustment( 7474 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7475 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7476 7477 assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment()); 7478 } 7479 7480 @Test testApplyEnqueuedAdjustmentFromAssistant_importance()7481 public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception { 7482 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7483 mService.addEnqueuedNotification(r); 7484 NotificationManagerService.WorkerHandler handler = mock( 7485 NotificationManagerService.WorkerHandler.class); 7486 mService.setHandler(handler); 7487 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7488 7489 Bundle signals = new Bundle(); 7490 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); 7491 Adjustment adjustment = new Adjustment( 7492 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7493 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7494 7495 assertEquals(IMPORTANCE_LOW, r.getImportance()); 7496 } 7497 7498 @Test testApplyEnqueuedAdjustmentFromAssistant_crossUser()7499 public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception { 7500 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7501 mService.addEnqueuedNotification(r); 7502 NotificationManagerService.WorkerHandler handler = mock( 7503 NotificationManagerService.WorkerHandler.class); 7504 mService.setHandler(handler); 7505 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(false); 7506 7507 Bundle signals = new Bundle(); 7508 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7509 USER_SENTIMENT_NEGATIVE); 7510 Adjustment adjustment = new Adjustment( 7511 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7512 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7513 7514 assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment()); 7515 7516 waitForIdle(); 7517 7518 verify(handler, timeout(300).times(0)).scheduleSendRankingUpdate(); 7519 } 7520 7521 @Test testUserSentimentChangeTriggersUpdate()7522 public void testUserSentimentChangeTriggersUpdate() throws Exception { 7523 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7524 mService.addNotification(r); 7525 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7526 7527 Bundle signals = new Bundle(); 7528 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7529 USER_SENTIMENT_NEGATIVE); 7530 Adjustment adjustment = new Adjustment( 7531 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7532 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 7533 7534 waitForIdle(); 7535 7536 verify(mRankingHandler, timeout(300).times(1)).requestSort(); 7537 } 7538 7539 @Test testTooLateAdjustmentTriggersUpdate()7540 public void testTooLateAdjustmentTriggersUpdate() throws Exception { 7541 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7542 mService.addNotification(r); 7543 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7544 7545 Bundle signals = new Bundle(); 7546 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7547 USER_SENTIMENT_NEGATIVE); 7548 Adjustment adjustment = new Adjustment( 7549 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7550 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7551 7552 waitForIdle(); 7553 7554 verify(mRankingHandler, times(1)).requestSort(); 7555 } 7556 7557 @Test testApplyAdjustmentsLogged()7558 public void testApplyAdjustmentsLogged() throws Exception { 7559 NotificationManagerService.WorkerHandler handler = mock( 7560 NotificationManagerService.WorkerHandler.class); 7561 mService.setHandler(handler); 7562 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7563 7564 // Set up notifications that will be adjusted 7565 final NotificationRecord r1 = generateNotificationRecord( 7566 mTestNotificationChannel, 1, null, true); 7567 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7568 mService.addNotification(r1); 7569 final NotificationRecord r2 = generateNotificationRecord( 7570 mTestNotificationChannel, 2, null, true); 7571 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7572 mService.addNotification(r2); 7573 7574 // Third notification that's NOT adjusted, just to make sure that doesn't get spuriously 7575 // logged. 7576 final NotificationRecord r3 = generateNotificationRecord( 7577 mTestNotificationChannel, 3, null, true); 7578 r3.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7579 mService.addNotification(r3); 7580 7581 List<Adjustment> adjustments = new ArrayList<>(); 7582 7583 // Test an adjustment that's associated with a ranking change and one that's not 7584 Bundle signals1 = new Bundle(); 7585 signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_HIGH); 7586 Adjustment adjustment1 = new Adjustment( 7587 r1.getSbn().getPackageName(), r1.getKey(), signals1, "", 7588 r1.getUser().getIdentifier()); 7589 adjustments.add(adjustment1); 7590 7591 // This one wouldn't trigger a ranking change, but should still trigger a log. 7592 Bundle signals2 = new Bundle(); 7593 signals2.putFloat(Adjustment.KEY_RANKING_SCORE, -0.5f); 7594 Adjustment adjustment2 = new Adjustment( 7595 r2.getSbn().getPackageName(), r2.getKey(), signals2, "", 7596 r2.getUser().getIdentifier()); 7597 adjustments.add(adjustment2); 7598 7599 mBinderService.applyAdjustmentsFromAssistant(null, adjustments); 7600 verify(mRankingHandler, times(1)).requestSort(); 7601 7602 // Actually apply the adjustments & recalculate importance when run 7603 doAnswer(invocationOnMock -> { 7604 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7605 .applyAdjustments(); 7606 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7607 .calculateImportance(); 7608 return null; 7609 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 7610 7611 // Now make sure that when the sort happens, we actually log the changes. 7612 mService.handleRankingSort(); 7613 7614 // Even though the ranking score change is not meant to trigger a ranking update, 7615 // during this process the package visibility & canShowBadge values are changing 7616 // in all notifications, so all 3 seem to trigger a ranking change. Here we check instead 7617 // that scheduleSendRankingUpdate is sent and that the relevant fields have been changed 7618 // accordingly to confirm the adjustments happened to the 2 relevant notifications. 7619 verify(handler, times(3)).scheduleSendRankingUpdate(); 7620 assertEquals(IMPORTANCE_HIGH, r1.getImportance()); 7621 assertTrue(r2.rankingScoreMatches(-0.5f)); 7622 assertEquals(2, mNotificationRecordLogger.numCalls()); 7623 assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(0)); 7624 assertEquals(NOTIFICATION_ADJUSTED, mNotificationRecordLogger.event(1)); 7625 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 7626 assertEquals(2, mNotificationRecordLogger.get(1).getInstanceId()); 7627 } 7628 7629 @Test testSensitiveAdjustmentsLogged()7630 public void testSensitiveAdjustmentsLogged() throws Exception { 7631 NotificationManagerService.WorkerHandler handler = mock( 7632 NotificationManagerService.WorkerHandler.class); 7633 mService.setHandler(handler); 7634 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 7635 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 7636 7637 // Set up notifications that will be adjusted 7638 final NotificationRecord r1 = spy(generateNotificationRecord( 7639 mTestNotificationChannel, 1, null, true)); 7640 when(r1.getLifespanMs(anyLong())).thenReturn(1); 7641 7642 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7643 mService.addEnqueuedNotification(r1); 7644 7645 // Test an adjustment for an enqueued notification 7646 Bundle signals = new Bundle(); 7647 signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true); 7648 Adjustment adjustment1 = new Adjustment( 7649 r1.getSbn().getPackageName(), r1.getKey(), signals, "", 7650 r1.getUser().getIdentifier()); 7651 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); 7652 assertTrue(mService.checkLastSensitiveLog(false, true, 1)); 7653 7654 // Set up notifications that will be adjusted 7655 final NotificationRecord r2 = spy(generateNotificationRecord( 7656 mTestNotificationChannel, 1, null, true)); 7657 when(r2.getLifespanMs(anyLong())).thenReturn(2); 7658 7659 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7660 mService.addNotification(r2); 7661 Adjustment adjustment2 = new Adjustment( 7662 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7663 r2.getUser().getIdentifier()); 7664 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); 7665 assertTrue(mService.checkLastSensitiveLog(true, true, 2)); 7666 7667 signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, false); 7668 Adjustment adjustment3 = new Adjustment( 7669 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7670 r2.getUser().getIdentifier()); 7671 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); 7672 assertTrue(mService.checkLastSensitiveLog(true, false, 2)); 7673 } 7674 7675 @Test 7676 @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) testClassificationChannelAdjustmentsLogged()7677 public void testClassificationChannelAdjustmentsLogged() throws Exception { 7678 NotificationManagerService.WorkerHandler handler = mock( 7679 NotificationManagerService.WorkerHandler.class); 7680 mService.setHandler(handler); 7681 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 7682 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 7683 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 7684 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 7685 7686 // Set up notifications that will be adjusted 7687 final NotificationRecord r1 = spy(generateNotificationRecord( 7688 mTestNotificationChannel, 1, null, true)); 7689 when(r1.getLifespanMs(anyLong())).thenReturn(234); 7690 7691 InstanceId instanceId1 = mNotificationInstanceIdSequence.newInstanceId(); 7692 r1.getSbn().setInstanceId(instanceId1); 7693 // Enqueues the notification to be posted, so hasPosted will be false. 7694 mService.addEnqueuedNotification(r1); 7695 7696 // Test an adjustment for an enqueued notification 7697 Bundle signals = new Bundle(); 7698 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 7699 Adjustment adjustment1 = new Adjustment( 7700 r1.getSbn().getPackageName(), r1.getKey(), signals, "", 7701 r1.getUser().getIdentifier()); 7702 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment1); 7703 assertTrue(mService.checkLastClassificationChannelLog(false /*=hasPosted*/, 7704 true /*=isAlerting*/, Adjustment.TYPE_NEWS, 234, 7705 NOTIFICATION_ADJUSTED.getId(), 7706 instanceId1.getId(), r1.getUid())); 7707 7708 // Set up notifications that will be adjusted 7709 // This notification starts on a low importance channel, so isAlerting is false. 7710 NotificationChannel mLowImportanceNotificationChannel = new NotificationChannel( 7711 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_LOW); 7712 final NotificationRecord r2 = spy(generateNotificationRecord( 7713 mLowImportanceNotificationChannel, 1, null, true)); 7714 when(r2.getLifespanMs(anyLong())).thenReturn(345); 7715 7716 InstanceId instanceId2 = mNotificationInstanceIdSequence.newInstanceId(); 7717 r2.getSbn().setInstanceId(instanceId2); 7718 // Adds the notification as already posted, so hasPosted will be true. 7719 mService.addNotification(r2); 7720 // The signal is removed when used so it has to be readded. 7721 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 7722 Adjustment adjustment2 = new Adjustment( 7723 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7724 r2.getUser().getIdentifier()); 7725 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment2); 7726 assertTrue(mService.checkLastClassificationChannelLog(true /*hasPosted*/, 7727 false /*isAlerting*/, Adjustment.TYPE_NEWS, 345, 7728 NOTIFICATION_ADJUSTED.getId(), 7729 instanceId2.getId() /*instance_id*/, r2.getUid())); 7730 7731 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_PROMOTION); 7732 Adjustment adjustment3 = new Adjustment( 7733 r2.getSbn().getPackageName(), r2.getKey(), signals, "", 7734 r2.getUser().getIdentifier()); 7735 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment3); 7736 assertTrue(mService.checkLastClassificationChannelLog(true /*=hasPosted*/, 7737 false /*=isAlerting*/, Adjustment.TYPE_PROMOTION, 345, 7738 NOTIFICATION_ADJUSTED.getId(), 7739 instanceId2.getId() /*instance_id*/, r2.getUid())); 7740 } 7741 7742 @Test testAdjustmentToImportanceNone_cancelsNotification()7743 public void testAdjustmentToImportanceNone_cancelsNotification() throws Exception { 7744 NotificationManagerService.WorkerHandler handler = mock( 7745 NotificationManagerService.WorkerHandler.class); 7746 mService.setHandler(handler); 7747 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7748 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 7749 7750 // Set up notifications: r1 is adjusted, r2 is not 7751 final NotificationRecord r1 = generateNotificationRecord( 7752 mTestNotificationChannel, 1, null, true); 7753 r1.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7754 mService.addNotification(r1); 7755 final NotificationRecord r2 = generateNotificationRecord( 7756 mTestNotificationChannel, 2, null, true); 7757 r2.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 7758 mService.addNotification(r2); 7759 7760 // Test an adjustment that sets importance to none (meaning it's cancelling) 7761 Bundle signals1 = new Bundle(); 7762 signals1.putInt(Adjustment.KEY_IMPORTANCE, IMPORTANCE_NONE); 7763 Adjustment adjustment1 = new Adjustment( 7764 r1.getSbn().getPackageName(), r1.getKey(), signals1, "", 7765 r1.getUser().getIdentifier()); 7766 7767 mBinderService.applyAdjustmentFromAssistant(null, adjustment1); 7768 7769 // Actually apply the adjustments & recalculate importance when run 7770 doAnswer(invocationOnMock -> { 7771 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7772 .applyAdjustments(); 7773 ((NotificationRecord) invocationOnMock.getArguments()[0]) 7774 .calculateImportance(); 7775 return null; 7776 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 7777 7778 // run the CancelNotificationRunnable when it happens 7779 ArgumentCaptor<NotificationManagerService.CancelNotificationRunnable> captor = 7780 ArgumentCaptor.forClass( 7781 NotificationManagerService.CancelNotificationRunnable.class); 7782 7783 verify(handler, times(1)).scheduleCancelNotification( 7784 captor.capture(), eq(0)); 7785 7786 // Run the runnable given to the cancel notification, and see if it logs properly 7787 NotificationManagerService.CancelNotificationRunnable runnable = captor.getValue(); 7788 runnable.run(); 7789 assertEquals(1, mNotificationRecordLogger.numCalls()); 7790 assertEquals( 7791 NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_ASSISTANT, 7792 mNotificationRecordLogger.event(0)); 7793 } 7794 7795 @Test testEnqueuedAdjustmentAppliesAdjustments()7796 public void testEnqueuedAdjustmentAppliesAdjustments() throws Exception { 7797 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 7798 mService.addEnqueuedNotification(r); 7799 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7800 7801 Bundle signals = new Bundle(); 7802 signals.putInt(Adjustment.KEY_USER_SENTIMENT, 7803 USER_SENTIMENT_NEGATIVE); 7804 Adjustment adjustment = new Adjustment( 7805 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 7806 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7807 7808 assertEquals(USER_SENTIMENT_NEGATIVE, r.getUserSentiment()); 7809 } 7810 7811 @Test testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications()7812 public void testEnqueuedAdjustmentAppliesAdjustments_MultiNotifications() throws Exception { 7813 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel); 7814 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel); 7815 mService.addEnqueuedNotification(r1); 7816 mService.addEnqueuedNotification(r2); 7817 when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true); 7818 7819 Bundle signals = new Bundle(); 7820 signals.putInt(Adjustment.KEY_IMPORTANCE, 7821 IMPORTANCE_HIGH); 7822 Adjustment adjustment = new Adjustment( 7823 r1.getSbn().getPackageName(), r1.getKey(), signals, 7824 "", r1.getUser().getIdentifier()); 7825 7826 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 7827 7828 assertEquals(IMPORTANCE_HIGH, r1.getImportance()); 7829 assertEquals(IMPORTANCE_HIGH, r2.getImportance()); 7830 } 7831 7832 @Test testRestore()7833 public void testRestore() throws Exception { 7834 int systemChecks = mService.countSystemChecks; 7835 mBinderService.applyRestore(null, USER_SYSTEM); 7836 assertEquals(1, mService.countSystemChecks - systemChecks); 7837 } 7838 7839 @Test testBackupEmptySound()7840 public void testBackupEmptySound() throws Exception { 7841 NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 7842 channel.setSound(Uri.EMPTY, null); 7843 7844 TypedXmlSerializer serializer = Xml.newFastSerializer(); 7845 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 7846 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 7847 channel.writeXmlForBackup(serializer, getContext()); 7848 7849 TypedXmlPullParser parser = Xml.newFastPullParser(); 7850 parser.setInput(new BufferedInputStream( 7851 new ByteArrayInputStream(baos.toByteArray())), null); 7852 NotificationChannel restored = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 7853 restored.populateFromXmlForRestore(parser, true, getContext()); 7854 7855 assertNull(restored.getSound()); 7856 } 7857 7858 @Test testBackup()7859 public void testBackup() throws Exception { 7860 mService.setPreferencesHelper(mPreferencesHelper); 7861 int systemChecks = mService.countSystemChecks; 7862 when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt())) 7863 .thenReturn(new ArraySet<>()); 7864 mBinderService.getBackupPayload(1); 7865 assertEquals(1, mService.countSystemChecks - systemChecks); 7866 } 7867 7868 @Test testEmptyVibration_noException()7869 public void testEmptyVibration_noException() throws Exception { 7870 NotificationChannel channel = new NotificationChannel("a", "ab", IMPORTANCE_DEFAULT); 7871 channel.setVibrationPattern(new long[0]); 7872 7873 TypedXmlSerializer serializer = Xml.newFastSerializer(); 7874 ByteArrayOutputStream baos = new ByteArrayOutputStream(); 7875 serializer.setOutput(new BufferedOutputStream(baos), "utf-8"); 7876 channel.writeXml(serializer); 7877 } 7878 7879 @Test updateUriPermissions_update()7880 public void updateUriPermissions_update() throws Exception { 7881 NotificationChannel c = new NotificationChannel( 7882 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 7883 c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT); 7884 Message message1 = new Message("", 0, ""); 7885 message1.setData("", 7886 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1)); 7887 Message message2 = new Message("", 1, ""); 7888 message2.setData("", 7889 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2)); 7890 7891 Notification.Builder nbA = new Notification.Builder(mContext, c.getId()) 7892 .setContentTitle("foo") 7893 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7894 .setStyle(new Notification.MessagingStyle("") 7895 .addMessage(message1) 7896 .addMessage(message2)); 7897 NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification( 7898 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid), 7899 null, 0), c); 7900 7901 // First post means we grant access to both 7902 reset(mUgm); 7903 reset(mUgmInternal); 7904 when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder()); 7905 mService.updateUriPermissions(recordA, null, mContext.getPackageName(), 7906 USER_SYSTEM); 7907 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 7908 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt()); 7909 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 7910 eq(message2.getDataUri()), anyInt(), anyInt(), anyInt()); 7911 7912 Notification.Builder nbB = new Notification.Builder(mContext, c.getId()) 7913 .setContentTitle("foo") 7914 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7915 .setStyle(new Notification.MessagingStyle("").addMessage(message2)); 7916 NotificationRecord recordB = 7917 new NotificationRecord( 7918 mContext, 7919 new StatusBarNotification( 7920 mPkg, 7921 mPkg, 7922 0, 7923 "tag", 7924 mUid, 7925 0, 7926 nbB.build(), 7927 UserHandle.getUserHandleForUid(mUid), 7928 null, 7929 0), 7930 c); 7931 7932 // Update means we drop access to first 7933 reset(mUgmInternal); 7934 mService.updateUriPermissions(recordB, recordA, mContext.getPackageName(), 7935 USER_SYSTEM); 7936 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), 7937 eq(message1.getDataUri()), anyInt(), anyInt(), eq(null), eq(-1)); 7938 7939 // Update back means we grant access to first again 7940 reset(mUgm); 7941 mService.updateUriPermissions(recordA, recordB, mContext.getPackageName(), 7942 USER_SYSTEM); 7943 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), anyInt(), any(), 7944 eq(message1.getDataUri()), anyInt(), anyInt(), anyInt()); 7945 7946 // And update to empty means we drop everything 7947 reset(mUgmInternal); 7948 mService.updateUriPermissions(null, recordB, mContext.getPackageName(), 7949 USER_SYSTEM); 7950 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner(any(), eq(null), 7951 anyInt(), anyInt()); 7952 } 7953 7954 @Test updateUriPermissions_posterDoesNotOwnUri()7955 public void updateUriPermissions_posterDoesNotOwnUri() throws Exception { 7956 NotificationChannel c = new NotificationChannel( 7957 TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT); 7958 c.setSound(null, Notification.AUDIO_ATTRIBUTES_DEFAULT); 7959 Message message1 = new Message("", 0, ""); 7960 message1.setData("", 7961 ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1)); 7962 7963 Notification.Builder nbA = new Notification.Builder(mContext, c.getId()) 7964 .setContentTitle("foo") 7965 .setSmallIcon(android.R.drawable.sym_def_app_icon) 7966 .setStyle(new Notification.MessagingStyle("") 7967 .addMessage(message1)); 7968 NotificationRecord recordA = new NotificationRecord(mContext, new StatusBarNotification( 7969 mPkg, mPkg, 0, "tag", mUid, 0, nbA.build(), UserHandle.getUserHandleForUid(mUid), 7970 null, 0), c); 7971 7972 doThrow(new SecurityException("no access")).when(mUgm) 7973 .grantUriPermissionFromOwner( 7974 any(), anyInt(), any(), any(), anyInt(), anyInt(), anyInt()); 7975 7976 when(mUgmInternal.newUriPermissionOwner(any())).thenReturn(new Binder()); 7977 mService.updateUriPermissions(recordA, null, mContext.getPackageName(), USER_SYSTEM); 7978 7979 // yay, no crash 7980 } 7981 7982 @Test testVisitUris()7983 public void testVisitUris() throws Exception { 7984 final Uri audioContents = Uri.parse("content://com.example/audio"); 7985 final Uri backgroundImage = Uri.parse("content://com.example/background"); 7986 final Icon smallIcon = Icon.createWithContentUri("content://media/small/icon"); 7987 final Icon largeIcon = Icon.createWithContentUri("content://media/large/icon"); 7988 final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); 7989 final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); 7990 final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); 7991 final Person person1 = new Person.Builder() 7992 .setName("Messaging Person") 7993 .setIcon(personIcon1) 7994 .build(); 7995 final Person person2 = new Person.Builder() 7996 .setName("People List Person 1") 7997 .setIcon(personIcon2) 7998 .build(); 7999 final Person person3 = new Person.Builder() 8000 .setName("People List Person 2") 8001 .setIcon(personIcon3) 8002 .build(); 8003 final Uri historyUri1 = Uri.parse("content://com.example/history1"); 8004 final Uri historyUri2 = Uri.parse("content://com.example/history2"); 8005 final RemoteInputHistoryItem historyItem1 = new RemoteInputHistoryItem(null, historyUri1, 8006 "a"); 8007 final RemoteInputHistoryItem historyItem2 = new RemoteInputHistoryItem(null, historyUri2, 8008 "b"); 8009 8010 Bundle extras = new Bundle(); 8011 extras.putParcelable(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents); 8012 extras.putString(Notification.EXTRA_BACKGROUND_IMAGE_URI, backgroundImage.toString()); 8013 extras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, person1); 8014 extras.putParcelableArrayList(Notification.EXTRA_PEOPLE_LIST, 8015 new ArrayList<>(Arrays.asList(person2, person3))); 8016 extras.putParcelableArray(Notification.EXTRA_REMOTE_INPUT_HISTORY_ITEMS, 8017 new RemoteInputHistoryItem[]{historyItem1, historyItem2}); 8018 8019 Notification n = new Notification.Builder(mContext, "a") 8020 .setContentTitle("notification with uris") 8021 .setSmallIcon(smallIcon) 8022 .setLargeIcon(largeIcon) 8023 .addExtras(extras) 8024 .build(); 8025 8026 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8027 n.visitUris(visitor); 8028 verify(visitor, times(1)).accept(eq(audioContents)); 8029 verify(visitor, times(1)).accept(eq(backgroundImage)); 8030 verify(visitor, times(1)).accept(eq(smallIcon.getUri())); 8031 verify(visitor, times(1)).accept(eq(largeIcon.getUri())); 8032 verify(visitor, times(1)).accept(eq(personIcon1.getUri())); 8033 verify(visitor, times(1)).accept(eq(personIcon2.getUri())); 8034 verify(visitor, times(1)).accept(eq(personIcon3.getUri())); 8035 verify(visitor, times(1)).accept(eq(historyUri1)); 8036 verify(visitor, times(1)).accept(eq(historyUri2)); 8037 } 8038 8039 @Test testVisitUris_publicVersion()8040 public void testVisitUris_publicVersion() throws Exception { 8041 final Icon smallIconPublic = Icon.createWithContentUri("content://media/small/icon"); 8042 final Icon largeIconPrivate = Icon.createWithContentUri("content://media/large/icon"); 8043 8044 Notification publicVersion = new Notification.Builder(mContext, "a") 8045 .setContentTitle("notification with uris") 8046 .setSmallIcon(smallIconPublic) 8047 .build(); 8048 Notification n = new Notification.Builder(mContext, "a") 8049 .setLargeIcon(largeIconPrivate) 8050 .setPublicVersion(publicVersion) 8051 .build(); 8052 8053 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8054 n.visitUris(visitor); 8055 verify(visitor, times(1)).accept(eq(smallIconPublic.getUri())); 8056 verify(visitor, times(1)).accept(eq(largeIconPrivate.getUri())); 8057 } 8058 8059 @Test testVisitUris_audioContentsString()8060 public void testVisitUris_audioContentsString() throws Exception { 8061 final Uri audioContents = Uri.parse("content://com.example/audio"); 8062 8063 Bundle extras = new Bundle(); 8064 extras.putString(Notification.EXTRA_AUDIO_CONTENTS_URI, audioContents.toString()); 8065 8066 Notification n = new Notification.Builder(mContext, "a") 8067 .setContentTitle("notification with uris") 8068 .setSmallIcon(android.R.drawable.sym_def_app_icon) 8069 .addExtras(extras) 8070 .build(); 8071 8072 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8073 n.visitUris(visitor); 8074 verify(visitor, times(1)).accept(eq(audioContents)); 8075 } 8076 8077 @Test testVisitUris_messagingStyle()8078 public void testVisitUris_messagingStyle() { 8079 final Icon personIcon1 = Icon.createWithContentUri("content://media/person1"); 8080 final Icon personIcon2 = Icon.createWithContentUri("content://media/person2"); 8081 final Icon personIcon3 = Icon.createWithContentUri("content://media/person3"); 8082 final Person person1 = new Person.Builder() 8083 .setName("Messaging Person 1") 8084 .setIcon(personIcon1) 8085 .build(); 8086 final Person person2 = new Person.Builder() 8087 .setName("Messaging Person 2") 8088 .setIcon(personIcon2) 8089 .build(); 8090 final Person person3 = new Person.Builder() 8091 .setName("Messaging Person 3") 8092 .setIcon(personIcon3) 8093 .build(); 8094 Icon shortcutIcon = Icon.createWithContentUri("content://media/shortcut"); 8095 8096 Notification.Builder builder = new Notification.Builder(mContext, "a") 8097 .setCategory(Notification.CATEGORY_MESSAGE) 8098 .setContentTitle("new message!") 8099 .setContentText("Conversation Notification") 8100 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8101 Notification.MessagingStyle.Message message1 = new Notification.MessagingStyle.Message( 8102 "Marco?", System.currentTimeMillis(), person2); 8103 Notification.MessagingStyle.Message message2 = new Notification.MessagingStyle.Message( 8104 "Polo!", System.currentTimeMillis(), person3); 8105 Notification.MessagingStyle style = new Notification.MessagingStyle(person1) 8106 .addMessage(message1) 8107 .addMessage(message2) 8108 .setShortcutIcon(shortcutIcon); 8109 builder.setStyle(style); 8110 Notification n = builder.build(); 8111 8112 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8113 n.visitUris(visitor); 8114 8115 verify(visitor, times(1)).accept(eq(shortcutIcon.getUri())); 8116 verify(visitor, times(1)).accept(eq(personIcon1.getUri())); 8117 verify(visitor, times(1)).accept(eq(personIcon2.getUri())); 8118 verify(visitor, times(1)).accept(eq(personIcon3.getUri())); 8119 } 8120 8121 @Test testVisitUris_callStyle()8122 public void testVisitUris_callStyle() { 8123 Icon personIcon = Icon.createWithContentUri("content://media/person"); 8124 Icon verificationIcon = Icon.createWithContentUri("content://media/verification"); 8125 Person callingPerson = new Person.Builder().setName("Someone") 8126 .setIcon(personIcon) 8127 .build(); 8128 PendingIntent hangUpIntent = PendingIntent.getActivity(mContext, 0, new Intent(), 8129 PendingIntent.FLAG_IMMUTABLE); 8130 Notification n = new Notification.Builder(mContext, "a") 8131 .setStyle(Notification.CallStyle.forOngoingCall(callingPerson, hangUpIntent) 8132 .setVerificationIcon(verificationIcon)) 8133 .setContentTitle("Calling...") 8134 .setSmallIcon(android.R.drawable.sym_def_app_icon) 8135 .build(); 8136 8137 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8138 n.visitUris(visitor); 8139 8140 verify(visitor, times(1)).accept(eq(personIcon.getUri())); 8141 verify(visitor, times(1)).accept(eq(verificationIcon.getUri())); 8142 hangUpIntent.cancel(); 8143 } 8144 8145 @Test testVisitUris_styleExtrasWithoutStyle()8146 public void testVisitUris_styleExtrasWithoutStyle() { 8147 Notification.Builder notification = new Notification.Builder(mContext, "a") 8148 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8149 8150 Bundle messagingExtras = new Bundle(); 8151 messagingExtras.putParcelable(Notification.EXTRA_MESSAGING_PERSON, 8152 personWithIcon("content://user")); 8153 messagingExtras.putParcelableArray(Notification.EXTRA_HISTORIC_MESSAGES, 8154 new Bundle[] { new Notification.MessagingStyle.Message("Heyhey!", 8155 System.currentTimeMillis() - 100, 8156 personWithIcon("content://historicalMessenger")).toBundle()}); 8157 messagingExtras.putParcelableArray(Notification.EXTRA_MESSAGES, 8158 new Bundle[] { new Notification.MessagingStyle.Message("Are you there?", 8159 System.currentTimeMillis(), 8160 personWithIcon("content://messenger")).toBundle()}); 8161 messagingExtras.putParcelable(Notification.EXTRA_CONVERSATION_ICON, 8162 Icon.createWithContentUri("content://conversationShortcut")); 8163 notification.addExtras(messagingExtras); 8164 8165 Bundle callExtras = new Bundle(); 8166 callExtras.putParcelable(Notification.EXTRA_CALL_PERSON, 8167 personWithIcon("content://caller")); 8168 callExtras.putParcelable(Notification.EXTRA_VERIFICATION_ICON, 8169 Icon.createWithContentUri("content://callVerification")); 8170 notification.addExtras(callExtras); 8171 8172 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8173 notification.build().visitUris(visitor); 8174 8175 verify(visitor).accept(eq(Uri.parse("content://user"))); 8176 verify(visitor).accept(eq(Uri.parse("content://historicalMessenger"))); 8177 verify(visitor).accept(eq(Uri.parse("content://messenger"))); 8178 verify(visitor).accept(eq(Uri.parse("content://conversationShortcut"))); 8179 verify(visitor).accept(eq(Uri.parse("content://caller"))); 8180 verify(visitor).accept(eq(Uri.parse("content://callVerification"))); 8181 } 8182 personWithIcon(String iconUri)8183 private static Person personWithIcon(String iconUri) { 8184 return new Person.Builder() 8185 .setName("Mr " + iconUri) 8186 .setIcon(Icon.createWithContentUri(iconUri)) 8187 .build(); 8188 } 8189 8190 @Test testVisitUris_wearableExtender()8191 public void testVisitUris_wearableExtender() { 8192 Icon actionIcon = Icon.createWithContentUri("content://media/action"); 8193 Icon wearActionIcon = Icon.createWithContentUri("content://media/wearAction"); 8194 PendingIntent intent = PendingIntent.getActivity(mContext, 0, new Intent(), 8195 PendingIntent.FLAG_IMMUTABLE); 8196 Notification n = new Notification.Builder(mContext, "a") 8197 .setSmallIcon(android.R.drawable.sym_def_app_icon) 8198 .addAction(new Notification.Action.Builder(actionIcon, "Hey!", intent).build()) 8199 .extend(new Notification.WearableExtender().addAction( 8200 new Notification.Action.Builder(wearActionIcon, "Wear!", intent).build())) 8201 .build(); 8202 8203 Consumer<Uri> visitor = (Consumer<Uri>) spy(Consumer.class); 8204 n.visitUris(visitor); 8205 8206 verify(visitor).accept(eq(actionIcon.getUri())); 8207 verify(visitor).accept(eq(wearActionIcon.getUri())); 8208 } 8209 8210 @Test testSetNotificationPolicy_preP_setOldFields()8211 public void testSetNotificationPolicy_preP_setOldFields() { 8212 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8213 mService.mZenModeHelper = mZenModeHelper; 8214 NotificationManager.Policy userPolicy = 8215 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8216 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8217 8218 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8219 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); 8220 8221 int expected = SUPPRESSED_EFFECT_BADGE 8222 | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF 8223 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_LIGHTS 8224 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8225 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 8226 8227 assertEquals(expected, actual); 8228 } 8229 8230 @Test testSetNotificationPolicy_preP_setNewFields()8231 public void testSetNotificationPolicy_preP_setNewFields() { 8232 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8233 mService.mZenModeHelper = mZenModeHelper; 8234 NotificationManager.Policy userPolicy = 8235 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8236 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8237 8238 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8239 SUPPRESSED_EFFECT_NOTIFICATION_LIST); 8240 8241 int expected = SUPPRESSED_EFFECT_BADGE; 8242 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 8243 8244 assertEquals(expected, actual); 8245 } 8246 8247 @Test testSetNotificationPolicy_preP_setOldNewFields()8248 public void testSetNotificationPolicy_preP_setOldNewFields() { 8249 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8250 mService.mZenModeHelper = mZenModeHelper; 8251 NotificationManager.Policy userPolicy = 8252 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8253 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8254 8255 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8256 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR); 8257 8258 int expected = 8259 SUPPRESSED_EFFECT_BADGE | SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_PEEK; 8260 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, O_MR1); 8261 8262 assertEquals(expected, actual); 8263 } 8264 8265 @Test testSetNotificationPolicy_P_setOldFields()8266 public void testSetNotificationPolicy_P_setOldFields() { 8267 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8268 mService.mZenModeHelper = mZenModeHelper; 8269 NotificationManager.Policy userPolicy = 8270 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8271 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8272 8273 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8274 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF); 8275 8276 int expected = SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_SCREEN_OFF 8277 | SUPPRESSED_EFFECT_PEEK | SUPPRESSED_EFFECT_AMBIENT 8278 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8279 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8280 8281 assertEquals(expected, actual); 8282 } 8283 8284 @Test testSetNotificationPolicy_P_setNewFields()8285 public void testSetNotificationPolicy_P_setNewFields() { 8286 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8287 mService.mZenModeHelper = mZenModeHelper; 8288 NotificationManager.Policy userPolicy = 8289 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8290 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8291 8292 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8293 SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_AMBIENT 8294 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 8295 8296 int expected = SUPPRESSED_EFFECT_NOTIFICATION_LIST | SUPPRESSED_EFFECT_SCREEN_OFF 8297 | SUPPRESSED_EFFECT_AMBIENT | SUPPRESSED_EFFECT_LIGHTS 8298 | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8299 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8300 8301 assertEquals(expected, actual); 8302 } 8303 8304 @Test testSetNotificationPolicy_P_setOldNewFields()8305 public void testSetNotificationPolicy_P_setOldNewFields() { 8306 ZenModeHelper mZenModeHelper = mock(ZenModeHelper.class); 8307 mService.mZenModeHelper = mZenModeHelper; 8308 NotificationManager.Policy userPolicy = 8309 new NotificationManager.Policy(0, 0, 0, SUPPRESSED_EFFECT_BADGE); 8310 when(mZenModeHelper.getNotificationPolicy(any())).thenReturn(userPolicy); 8311 8312 NotificationManager.Policy appPolicy = new NotificationManager.Policy(0, 0, 0, 8313 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_STATUS_BAR); 8314 8315 int expected = SUPPRESSED_EFFECT_STATUS_BAR; 8316 int actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8317 8318 assertEquals(expected, actual); 8319 8320 appPolicy = new NotificationManager.Policy(0, 0, 0, 8321 SUPPRESSED_EFFECT_SCREEN_ON | SUPPRESSED_EFFECT_AMBIENT 8322 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT); 8323 8324 expected = SUPPRESSED_EFFECT_SCREEN_OFF | SUPPRESSED_EFFECT_AMBIENT 8325 | SUPPRESSED_EFFECT_LIGHTS | SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; 8326 actual = mService.calculateSuppressedVisualEffects(appPolicy, userPolicy, P); 8327 8328 assertEquals(expected, actual); 8329 } 8330 8331 @Test testVisualDifference_foreground()8332 public void testVisualDifference_foreground() { 8333 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8334 .setContentTitle("foo"); 8335 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8336 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8337 NotificationRecord r1 = 8338 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8339 8340 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8341 .setFlag(FLAG_FOREGROUND_SERVICE, true) 8342 .setContentTitle("bar"); 8343 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8344 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8345 NotificationRecord r2 = 8346 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8347 8348 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8349 } 8350 8351 @Test testVisualDifference_diffTitle()8352 public void testVisualDifference_diffTitle() { 8353 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8354 .setContentTitle("foo"); 8355 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8356 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8357 NotificationRecord r1 = 8358 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8359 8360 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8361 .setContentTitle("bar"); 8362 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8363 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8364 NotificationRecord r2 = 8365 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8366 8367 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8368 } 8369 8370 @Test testVisualDifference_inboxStyle()8371 public void testVisualDifference_inboxStyle() { 8372 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8373 .setStyle(new Notification.InboxStyle() 8374 .addLine("line1").addLine("line2")); 8375 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8376 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8377 NotificationRecord r1 = 8378 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8379 8380 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8381 .setStyle(new Notification.InboxStyle() 8382 .addLine("line1").addLine("line2_changed")); 8383 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8384 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8385 NotificationRecord r2 = 8386 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8387 8388 assertTrue(mService.isVisuallyInterruptive(r1, r2)); // line 2 changed unnoticed 8389 8390 Notification.Builder nb3 = new Notification.Builder(mContext, "") 8391 .setStyle(new Notification.InboxStyle() 8392 .addLine("line1")); 8393 StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8394 nb3.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8395 NotificationRecord r3 = 8396 new NotificationRecord(mContext, sbn3, mock(NotificationChannel.class)); 8397 8398 assertTrue(mService.isVisuallyInterruptive(r1, r3)); // line 2 removed unnoticed 8399 8400 Notification.Builder nb4 = new Notification.Builder(mContext, "") 8401 .setStyle(new Notification.InboxStyle() 8402 .addLine("line1").addLine("line2").addLine("line3")); 8403 StatusBarNotification sbn4 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8404 nb4.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8405 NotificationRecord r4 = 8406 new NotificationRecord(mContext, sbn4, mock(NotificationChannel.class)); 8407 8408 assertTrue(mService.isVisuallyInterruptive(r1, r4)); // line 3 added unnoticed 8409 8410 Notification.Builder nb5 = new Notification.Builder(mContext, "") 8411 .setContentText("not an inbox"); 8412 StatusBarNotification sbn5 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8413 nb5.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8414 NotificationRecord r5 = 8415 new NotificationRecord(mContext, sbn5, mock(NotificationChannel.class)); 8416 8417 assertTrue(mService.isVisuallyInterruptive(r1, r5)); // changed Styles, went unnoticed 8418 } 8419 8420 @Test testVisualDifference_diffText()8421 public void testVisualDifference_diffText() { 8422 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8423 .setContentText("foo"); 8424 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8425 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8426 NotificationRecord r1 = 8427 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8428 8429 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8430 .setContentText("bar"); 8431 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8432 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8433 NotificationRecord r2 = 8434 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8435 8436 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8437 } 8438 8439 @Test testVisualDifference_sameText()8440 public void testVisualDifference_sameText() { 8441 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8442 .setContentText("foo"); 8443 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8444 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8445 NotificationRecord r1 = 8446 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8447 8448 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8449 .setContentText("foo"); 8450 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8451 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8452 NotificationRecord r2 = 8453 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8454 8455 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8456 } 8457 8458 @Test testVisualDifference_sameTextButStyled()8459 public void testVisualDifference_sameTextButStyled() { 8460 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8461 .setContentText(Html.fromHtml("<b>foo</b>")); 8462 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8463 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8464 NotificationRecord r1 = 8465 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8466 8467 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8468 .setContentText(Html.fromHtml("<b>foo</b>")); 8469 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8470 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8471 NotificationRecord r2 = 8472 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8473 8474 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8475 } 8476 8477 @Test testVisualDifference_diffTextButStyled()8478 public void testVisualDifference_diffTextButStyled() { 8479 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8480 .setContentText(Html.fromHtml("<b>foo</b>")); 8481 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8482 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8483 NotificationRecord r1 = 8484 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8485 8486 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8487 .setContentText(Html.fromHtml("<b>bar</b>")); 8488 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8489 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8490 NotificationRecord r2 = 8491 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8492 8493 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8494 } 8495 8496 @Test testVisualDifference_diffProgress()8497 public void testVisualDifference_diffProgress() { 8498 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8499 .setProgress(100, 90, false); 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 .setProgress(100, 100, false); 8507 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8508 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8509 NotificationRecord r2 = 8510 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8511 8512 assertTrue(mService.isVisuallyInterruptive(r1, r2)); 8513 } 8514 8515 @Test testVisualDifference_diffProgressNotDone()8516 public void testVisualDifference_diffProgressNotDone() { 8517 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8518 .setProgress(100, 90, false); 8519 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8520 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8521 NotificationRecord r1 = 8522 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8523 8524 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8525 .setProgress(100, 91, false); 8526 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8527 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8528 NotificationRecord r2 = 8529 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8530 8531 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8532 } 8533 8534 @Test testVisualDifference_sameProgressStillDone()8535 public void testVisualDifference_sameProgressStillDone() { 8536 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8537 .setProgress(100, 100, false); 8538 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8539 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8540 NotificationRecord r1 = 8541 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8542 8543 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8544 .setProgress(100, 100, false); 8545 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8546 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8547 NotificationRecord r2 = 8548 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8549 8550 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8551 } 8552 8553 @Test testVisualDifference_summary()8554 public void testVisualDifference_summary() { 8555 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8556 .setGroup("bananas") 8557 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 8558 .setContentText("foo"); 8559 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8560 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8561 NotificationRecord r1 = 8562 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8563 8564 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8565 .setGroup("bananas") 8566 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 8567 .setContentText("bar"); 8568 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8569 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8570 NotificationRecord r2 = 8571 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8572 8573 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8574 } 8575 8576 @Test testVisualDifference_summaryNewNotification()8577 public void testVisualDifference_summaryNewNotification() { 8578 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8579 .setGroup("bananas") 8580 .setFlag(Notification.FLAG_GROUP_SUMMARY, true) 8581 .setContentText("bar"); 8582 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8583 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8584 NotificationRecord r2 = 8585 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8586 8587 assertFalse(mService.isVisuallyInterruptive(null, r2)); 8588 } 8589 8590 @Test testVisualDifference_sameImages()8591 public void testVisualDifference_sameImages() { 8592 Icon large = Icon.createWithResource(mContext, 1); 8593 Notification n1 = new Notification.Builder(mContext, "channel") 8594 .setSmallIcon(1).setLargeIcon(large).build(); 8595 Notification n2 = new Notification.Builder(mContext, "channel") 8596 .setSmallIcon(1).setLargeIcon(large).build(); 8597 8598 NotificationRecord r1 = notificationToRecord(n1); 8599 NotificationRecord r2 = notificationToRecord(n2); 8600 8601 assertThat(mService.isVisuallyInterruptive(r1, r2)).isFalse(); 8602 } 8603 8604 @Test testVisualDifference_differentSmallImage()8605 public void testVisualDifference_differentSmallImage() { 8606 Icon large = Icon.createWithResource(mContext, 1); 8607 Notification n1 = new Notification.Builder(mContext, "channel") 8608 .setSmallIcon(1).setLargeIcon(large).build(); 8609 Notification n2 = new Notification.Builder(mContext, "channel") 8610 .setSmallIcon(2).setLargeIcon(large).build(); 8611 8612 NotificationRecord r1 = notificationToRecord(n1); 8613 NotificationRecord r2 = notificationToRecord(n2); 8614 8615 assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue(); 8616 } 8617 8618 @Test testVisualDifference_differentLargeImage()8619 public void testVisualDifference_differentLargeImage() { 8620 Icon large1 = Icon.createWithResource(mContext, 1); 8621 Icon large2 = Icon.createWithResource(mContext, 2); 8622 Notification n1 = new Notification.Builder(mContext, "channel") 8623 .setSmallIcon(1).setLargeIcon(large1).build(); 8624 Notification n2 = new Notification.Builder(mContext, "channel") 8625 .setSmallIcon(1).setLargeIcon(large2).build(); 8626 8627 NotificationRecord r1 = notificationToRecord(n1); 8628 NotificationRecord r2 = notificationToRecord(n2); 8629 8630 assertThat(mService.isVisuallyInterruptive(r1, r2)).isTrue(); 8631 } 8632 8633 @Test 8634 @EnableFlags({android.app.Flags.FLAG_SORT_SECTION_BY_TIME}) testVisualDifference_userInitiatedJob()8635 public void testVisualDifference_userInitiatedJob() { 8636 Notification.Builder nb1 = new Notification.Builder(mContext, "") 8637 .setContentTitle("foo"); 8638 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8639 nb1.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8640 NotificationRecord r1 = 8641 new NotificationRecord(mContext, sbn1, mock(NotificationChannel.class)); 8642 8643 Notification.Builder nb2 = new Notification.Builder(mContext, "") 8644 .setFlag(FLAG_USER_INITIATED_JOB, true) 8645 .setContentTitle("bar"); 8646 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, 8647 nb2.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 8648 NotificationRecord r2 = 8649 new NotificationRecord(mContext, sbn2, mock(NotificationChannel.class)); 8650 8651 assertFalse(mService.isVisuallyInterruptive(r1, r2)); 8652 } 8653 notificationToRecord(Notification n)8654 private NotificationRecord notificationToRecord(Notification n) { 8655 return new NotificationRecord( 8656 mContext, 8657 new StatusBarNotification(mPkg, mPkg, 0, "tag", mUid, 0, n, 8658 UserHandle.getUserHandleForUid(mUid), null, 0), 8659 mock(NotificationChannel.class)); 8660 } 8661 8662 @Test testHideAndUnhideNotificationsOnSuspendedPackageBroadcast()8663 public void testHideAndUnhideNotificationsOnSuspendedPackageBroadcast() { 8664 // post 2 notification from this package 8665 final NotificationRecord notif1 = generateNotificationRecord( 8666 mTestNotificationChannel, 1, null, true); 8667 final NotificationRecord notif2 = generateNotificationRecord( 8668 mTestNotificationChannel, 2, null, false); 8669 mService.addNotification(notif1); 8670 mService.addNotification(notif2); 8671 8672 // on broadcast, hide the 2 notifications 8673 simulatePackageSuspendBroadcast(true, mPkg, notif1.getUid()); 8674 ArgumentCaptor<List> captorHide = ArgumentCaptor.forClass(List.class); 8675 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 8676 assertEquals(2, captorHide.getValue().size()); 8677 8678 // on broadcast, unhide the 2 notifications 8679 simulatePackageSuspendBroadcast(false, mPkg, notif1.getUid()); 8680 ArgumentCaptor<List> captorUnhide = ArgumentCaptor.forClass(List.class); 8681 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 8682 assertEquals(2, captorUnhide.getValue().size()); 8683 } 8684 8685 @Test testNoNotificationsHiddenOnSuspendedPackageBroadcast()8686 public void testNoNotificationsHiddenOnSuspendedPackageBroadcast() { 8687 // post 2 notification from this package 8688 final NotificationRecord notif1 = generateNotificationRecord( 8689 mTestNotificationChannel, 1, null, true); 8690 final NotificationRecord notif2 = generateNotificationRecord( 8691 mTestNotificationChannel, 2, null, false); 8692 mService.addNotification(notif1); 8693 mService.addNotification(notif2); 8694 8695 // on broadcast, nothing is hidden since no notifications are of package "test_package" 8696 simulatePackageSuspendBroadcast(true, "test_package", notif1.getUid()); 8697 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 8698 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 8699 assertEquals(0, captor.getValue().size()); 8700 } 8701 8702 @Test testNotificationFromDifferentUserHidden()8703 public void testNotificationFromDifferentUserHidden() { 8704 // post 2 notification from this package 8705 final NotificationRecord notif1 = generateNotificationRecord( 8706 mTestNotificationChannel, 1, null, true); 8707 final NotificationRecord notif2 = generateNotificationRecord( 8708 mTestNotificationChannel, 2, null, false); 8709 mService.addNotification(notif1); 8710 mService.addNotification(notif2); 8711 8712 // on broadcast, nothing is hidden since no notifications are of user 10 with package PKG 8713 simulatePackageSuspendBroadcast(true, mPkg, 10); 8714 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 8715 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 8716 assertEquals(0, captor.getValue().size()); 8717 } 8718 8719 @Test testHideAndUnhideNotificationsOnDistractingPackageBroadcast()8720 public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast() { 8721 // Post 2 notifications from 2 packages 8722 NotificationRecord pkgA = new NotificationRecord(mContext, 8723 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 8724 mService.addNotification(pkgA); 8725 NotificationRecord pkgB = new NotificationRecord(mContext, 8726 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 8727 mService.addNotification(pkgB); 8728 8729 // on broadcast, hide one of the packages 8730 simulatePackageDistractionBroadcast( 8731 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a"}, 8732 new int[] {1000}); 8733 ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class); 8734 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 8735 assertEquals(1, captorHide.getValue().size()); 8736 assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName()); 8737 8738 // on broadcast, unhide the package 8739 simulatePackageDistractionBroadcast( 8740 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a"}, 8741 new int[] {1000}); 8742 ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class); 8743 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 8744 assertEquals(1, captorUnhide.getValue().size()); 8745 assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName()); 8746 } 8747 8748 @Test testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg()8749 public void testHideAndUnhideNotificationsOnDistractingPackageBroadcast_multiPkg() { 8750 // Post 2 notifications from 2 packages 8751 NotificationRecord pkgA = new NotificationRecord(mContext, 8752 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 8753 mService.addNotification(pkgA); 8754 NotificationRecord pkgB = new NotificationRecord(mContext, 8755 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 8756 mService.addNotification(pkgB); 8757 8758 // on broadcast, hide one of the packages 8759 simulatePackageDistractionBroadcast( 8760 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"a", "b"}, 8761 new int[] {1000, 1001}); 8762 ArgumentCaptor<List<NotificationRecord>> captorHide = ArgumentCaptor.forClass(List.class); 8763 8764 // should be called only once. 8765 verify(mListeners, times(1)).notifyHiddenLocked(captorHide.capture()); 8766 assertEquals(2, captorHide.getValue().size()); 8767 assertEquals("a", captorHide.getValue().get(0).getSbn().getPackageName()); 8768 assertEquals("b", captorHide.getValue().get(1).getSbn().getPackageName()); 8769 8770 // on broadcast, unhide the package 8771 simulatePackageDistractionBroadcast( 8772 PackageManager.RESTRICTION_HIDE_FROM_SUGGESTIONS, new String[] {"a", "b"}, 8773 new int[] {1000, 1001}); 8774 ArgumentCaptor<List<NotificationRecord>> captorUnhide = ArgumentCaptor.forClass(List.class); 8775 8776 // should be called only once. 8777 verify(mListeners, times(1)).notifyUnhiddenLocked(captorUnhide.capture()); 8778 assertEquals(2, captorUnhide.getValue().size()); 8779 assertEquals("a", captorUnhide.getValue().get(0).getSbn().getPackageName()); 8780 assertEquals("b", captorUnhide.getValue().get(1).getSbn().getPackageName()); 8781 } 8782 8783 @Test testNoNotificationsHiddenOnDistractingPackageBroadcast()8784 public void testNoNotificationsHiddenOnDistractingPackageBroadcast() { 8785 // post notification from this package 8786 final NotificationRecord notif1 = generateNotificationRecord( 8787 mTestNotificationChannel, 1, null, true); 8788 mService.addNotification(notif1); 8789 8790 // on broadcast, nothing is hidden since no notifications are of package "test_package" 8791 simulatePackageDistractionBroadcast( 8792 PackageManager.RESTRICTION_HIDE_NOTIFICATIONS, new String[] {"test_package"}, 8793 new int[]{notif1.getUid()}); 8794 ArgumentCaptor<List> captor = ArgumentCaptor.forClass(List.class); 8795 verify(mListeners, times(1)).notifyHiddenLocked(captor.capture()); 8796 assertEquals(0, captor.getValue().size()); 8797 } 8798 8799 @Test testCanUseManagedServicesNullPkg()8800 public void testCanUseManagedServicesNullPkg() { 8801 assertEquals(true, mService.canUseManagedServices(null, 0, null)); 8802 } 8803 8804 8805 @Test testCanUseManagedServicesNoValidPkg()8806 public void testCanUseManagedServicesNoValidPkg() { 8807 assertEquals(true, mService.canUseManagedServices("d", 0, null)); 8808 } 8809 8810 @Test testCanUseManagedServices_hasPermission()8811 public void testCanUseManagedServices_hasPermission() throws Exception { 8812 when(mPackageManager.checkPermission("perm", "pkg", 0)) 8813 .thenReturn(PackageManager.PERMISSION_GRANTED); 8814 8815 assertEquals(true, mService.canUseManagedServices("pkg", 0, "perm")); 8816 } 8817 8818 @Test testCanUseManagedServices_noPermission()8819 public void testCanUseManagedServices_noPermission() throws Exception { 8820 when(mPackageManager.checkPermission("perm", "pkg", 0)) 8821 .thenReturn(PackageManager.PERMISSION_DENIED); 8822 8823 assertEquals(false, mService.canUseManagedServices("pkg", 0, "perm")); 8824 } 8825 8826 @Test testCanUseManagedServices_permDoesNotMatter()8827 public void testCanUseManagedServices_permDoesNotMatter() { 8828 assertEquals(true, mService.canUseManagedServices("pkg", 0, null)); 8829 } 8830 8831 @Test testOnNotificationVisibilityChanged_triggersInterruptionUsageStat()8832 public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() { 8833 final NotificationRecord r = generateNotificationRecord( 8834 mTestNotificationChannel, 1, null, true); 8835 r.setTextChanged(true); 8836 mService.addNotification(r); 8837 8838 mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[] 8839 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}, 8840 new NotificationVisibility[]{}); 8841 8842 verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt()); 8843 } 8844 8845 @Test testOnNotificationVisibilityChanged_triggersVisibilityLog()8846 public void testOnNotificationVisibilityChanged_triggersVisibilityLog() { 8847 final NotificationRecord r = generateNotificationRecord( 8848 mTestNotificationChannel, 1, null, true); 8849 r.setTextChanged(true); 8850 r.getSbn().setInstanceId(mNotificationInstanceIdSequence.newInstanceId()); 8851 mService.addNotification(r); 8852 8853 mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[] 8854 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)}, 8855 new NotificationVisibility[]{}); 8856 8857 assertEquals(1, mNotificationRecordLogger.numCalls()); 8858 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_OPEN, 8859 mNotificationRecordLogger.event(0)); 8860 assertEquals(1, mNotificationRecordLogger.get(0).getInstanceId()); 8861 8862 mService.mNotificationDelegate.onNotificationVisibilityChanged( 8863 new NotificationVisibility[]{}, 8864 new NotificationVisibility[] 8865 {NotificationVisibility.obtain(r.getKey(), 1, 1, true)} 8866 ); 8867 8868 assertEquals(2, mNotificationRecordLogger.numCalls()); 8869 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLOSE, 8870 mNotificationRecordLogger.event(1)); 8871 assertEquals(1, mNotificationRecordLogger.get(1).getInstanceId()); 8872 } 8873 8874 @Test testSetNotificationsShownFromListener_triggersInterruptionUsageStat()8875 public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat() 8876 throws RemoteException { 8877 final NotificationRecord r = generateNotificationRecord( 8878 mTestNotificationChannel, 1, null, true); 8879 r.setTextChanged(true); 8880 mService.addNotification(r); 8881 8882 mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()}); 8883 8884 verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt()); 8885 } 8886 8887 @Test testSetNotificationsShownFromListener_protectsCrossUserInformation()8888 public void testSetNotificationsShownFromListener_protectsCrossUserInformation() 8889 throws RemoteException { 8890 Notification.Builder nb = new Notification.Builder( 8891 mContext, mTestNotificationChannel.getId()) 8892 .setContentTitle("foo") 8893 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8894 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 8895 "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, 8896 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), 8897 null, 0); 8898 final NotificationRecord r = 8899 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8900 r.setTextChanged(true); 8901 mService.addNotification(r); 8902 8903 // no security exception! 8904 mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()}); 8905 8906 verify(mAppUsageStats, never()).reportInterruptiveNotification( 8907 anyString(), anyString(), anyInt()); 8908 } 8909 8910 @Test testCancelNotificationsFromListener_protectsCrossUserInformation()8911 public void testCancelNotificationsFromListener_protectsCrossUserInformation() 8912 throws RemoteException { 8913 Notification.Builder nb = new Notification.Builder( 8914 mContext, mTestNotificationChannel.getId()) 8915 .setContentTitle("foo") 8916 .setSmallIcon(android.R.drawable.sym_def_app_icon); 8917 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 8918 "tag" + System.currentTimeMillis(), UserHandle.PER_USER_RANGE, 0, 8919 nb.build(), UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE), 8920 null, 0); 8921 final NotificationRecord r = 8922 new NotificationRecord(mContext, sbn, mTestNotificationChannel); 8923 r.setTextChanged(true); 8924 mService.addNotification(r); 8925 8926 // no security exception! 8927 mBinderService.cancelNotificationsFromListener(null, new String[] {r.getKey()}); 8928 8929 waitForIdle(); 8930 assertEquals(1, mService.getNotificationRecordCount()); 8931 } 8932 8933 @Test testMaybeRecordInterruptionLocked_doesNotRecordTwice()8934 public void testMaybeRecordInterruptionLocked_doesNotRecordTwice() 8935 throws RemoteException { 8936 final NotificationRecord r = generateNotificationRecord( 8937 mTestNotificationChannel, 1, null, true); 8938 r.setInterruptive(true); 8939 mService.addNotification(r); 8940 8941 mService.maybeRecordInterruptionLocked(r); 8942 mService.maybeRecordInterruptionLocked(r); 8943 8944 verify(mAppUsageStats, times(1)).reportInterruptiveNotification( 8945 anyString(), anyString(), anyInt()); 8946 verify(mHistoryManager, times(1)).addNotification(any()); 8947 } 8948 8949 @Test testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory()8950 public void testMaybeRecordInterruptionLocked_smallIconsRequiredForHistory() 8951 throws RemoteException { 8952 final NotificationRecord r = generateNotificationRecord( 8953 mTestNotificationChannel, 1, null, true); 8954 r.setInterruptive(true); 8955 r.getSbn().getNotification().setSmallIcon(null); 8956 mService.addNotification(r); 8957 8958 mService.maybeRecordInterruptionLocked(r); 8959 8960 verify(mAppUsageStats, times(1)).reportInterruptiveNotification( 8961 anyString(), anyString(), anyInt()); 8962 verify(mHistoryManager, never()).addNotification(any()); 8963 } 8964 8965 @Test testBubble()8966 public void testBubble() throws Exception { 8967 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE); 8968 assertFalse(mBinderService.areBubblesAllowed(mPkg)); 8969 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 8970 BUBBLE_PREFERENCE_NONE); 8971 } 8972 8973 @Test testUserApprovedBubblesForPackageSelected()8974 public void testUserApprovedBubblesForPackageSelected() throws Exception { 8975 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_SELECTED); 8976 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 8977 BUBBLE_PREFERENCE_SELECTED); 8978 } 8979 8980 @Test testUserApprovedBubblesForPackageAll()8981 public void testUserApprovedBubblesForPackageAll() throws Exception { 8982 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_ALL); 8983 assertTrue(mBinderService.areBubblesAllowed(mPkg)); 8984 assertEquals(mBinderService.getBubblePreferenceForPackage(mPkg, mUid), 8985 BUBBLE_PREFERENCE_ALL); 8986 } 8987 8988 @Test testUserRejectsBubblesForPackage()8989 public void testUserRejectsBubblesForPackage() throws Exception { 8990 mBinderService.setBubblesAllowed(mPkg, mUid, BUBBLE_PREFERENCE_NONE); 8991 assertFalse(mBinderService.areBubblesAllowed(mPkg)); 8992 } 8993 8994 @Test testAreBubblesEnabled()8995 public void testAreBubblesEnabled() throws Exception { 8996 Settings.Secure.putInt(mContext.getContentResolver(), 8997 Settings.Secure.NOTIFICATION_BUBBLES, 1); 8998 mService.mPreferencesHelper.updateBubblesEnabled(); 8999 assertTrue(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid))); 9000 } 9001 9002 @Test testAreBubblesEnabled_false()9003 public void testAreBubblesEnabled_false() throws Exception { 9004 Settings.Secure.putIntForUser(mContext.getContentResolver(), 9005 Settings.Secure.NOTIFICATION_BUBBLES, 0, UserHandle.getUserId(mUid)); 9006 mService.mPreferencesHelper.updateBubblesEnabled(); 9007 assertFalse(mBinderService.areBubblesEnabled(UserHandle.getUserHandleForUid(mUid))); 9008 } 9009 9010 @Test testAreBubblesEnabled_exception()9011 public void testAreBubblesEnabled_exception() throws Exception { 9012 try { 9013 assertTrue(mBinderService.areBubblesEnabled( 9014 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE))); 9015 fail("Cannot call cross user without permission"); 9016 } catch (SecurityException e) { 9017 // pass 9018 } 9019 // cross user, with permission, no problem 9020 enableInteractAcrossUsers(); 9021 assertTrue(mBinderService.areBubblesEnabled( 9022 UserHandle.getUserHandleForUid(mUid + UserHandle.PER_USER_RANGE))); 9023 } 9024 9025 @Test testIsCallerInstantApp_primaryUser()9026 public void testIsCallerInstantApp_primaryUser() throws Exception { 9027 ApplicationInfo info = new ApplicationInfo(); 9028 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 9029 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 9030 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 9031 9032 assertTrue(mService.isCallerInstantApp(45770, 0)); 9033 9034 info.privateFlags = 0; 9035 assertFalse(mService.isCallerInstantApp(575370, 0)); 9036 } 9037 9038 @Test testIsCallerInstantApp_secondaryUser()9039 public void testIsCallerInstantApp_secondaryUser() throws Exception { 9040 ApplicationInfo info = new ApplicationInfo(); 9041 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 9042 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info); 9043 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null); 9044 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 9045 9046 assertTrue(mService.isCallerInstantApp(68638450, 10)); 9047 } 9048 9049 @Test testIsCallerInstantApp_userAllNotification()9050 public void testIsCallerInstantApp_userAllNotification() throws Exception { 9051 ApplicationInfo info = new ApplicationInfo(); 9052 info.privateFlags = ApplicationInfo.PRIVATE_FLAG_INSTANT; 9053 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(USER_SYSTEM))) 9054 .thenReturn(info); 9055 when(mPackageManager.getPackagesForUid(anyInt())).thenReturn(new String[]{"any"}); 9056 9057 assertTrue(mService.isCallerInstantApp(45770, UserHandle.USER_ALL)); 9058 9059 info.privateFlags = 0; 9060 assertFalse(mService.isCallerInstantApp(575370, UserHandle.USER_ALL )); 9061 } 9062 9063 @Test testResolveNotificationUid_sameApp_nonSystemUser()9064 public void testResolveNotificationUid_sameApp_nonSystemUser() throws Exception { 9065 ApplicationInfo info = new ApplicationInfo(); 9066 info.uid = Binder.getCallingUid(); 9067 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(10))).thenReturn(info); 9068 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(null); 9069 9070 int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 10); 9071 9072 assertEquals(info.uid, actualUid); 9073 } 9074 9075 @Test testResolveNotificationUid_sameApp()9076 public void testResolveNotificationUid_sameApp() throws Exception { 9077 ApplicationInfo info = new ApplicationInfo(); 9078 info.uid = Binder.getCallingUid(); 9079 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 9080 9081 int actualUid = mService.resolveNotificationUid("caller", "caller", info.uid, 0); 9082 9083 assertEquals(info.uid, actualUid); 9084 } 9085 9086 @Test testResolveNotificationUid_sameAppDiffPackage()9087 public void testResolveNotificationUid_sameAppDiffPackage() throws Exception { 9088 ApplicationInfo info = new ApplicationInfo(); 9089 info.uid = Binder.getCallingUid(); 9090 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), eq(0))).thenReturn(info); 9091 9092 int actualUid = mService.resolveNotificationUid("caller", "callerAlso", info.uid, 0); 9093 9094 assertEquals(info.uid, actualUid); 9095 } 9096 9097 @Test testResolveNotificationUid_sameAppWrongUid()9098 public void testResolveNotificationUid_sameAppWrongUid() throws Exception { 9099 ApplicationInfo info = new ApplicationInfo(); 9100 info.uid = 1356347; 9101 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(info); 9102 9103 try { 9104 mService.resolveNotificationUid("caller", "caller", 9, 0); 9105 fail("Incorrect uid didn't throw security exception"); 9106 } catch (SecurityException e) { 9107 // yay 9108 } 9109 } 9110 9111 @Test testResolveNotificationUid_delegateAllowed()9112 public void testResolveNotificationUid_delegateAllowed() throws Exception { 9113 int expectedUid = 123; 9114 9115 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid); 9116 mService.setPreferencesHelper(mPreferencesHelper); 9117 when(mPreferencesHelper.isDelegateAllowed(anyString(), anyInt(), anyString(), anyInt())) 9118 .thenReturn(true); 9119 9120 assertEquals(expectedUid, mService.resolveNotificationUid("caller", "target", 9, 0)); 9121 } 9122 9123 @Test testResolveNotificationUid_androidAllowed()9124 public void testResolveNotificationUid_androidAllowed() throws Exception { 9125 int expectedUid = 123; 9126 9127 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(expectedUid); 9128 // no delegate 9129 9130 assertEquals(expectedUid, mService.resolveNotificationUid("android", "target", 0, 0)); 9131 } 9132 9133 @Test testPostFromAndroidForNonExistentPackage()9134 public void testPostFromAndroidForNonExistentPackage() throws Exception { 9135 final String notReal = "NOT REAL"; 9136 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())).thenThrow( 9137 PackageManager.NameNotFoundException.class); 9138 ApplicationInfo ai = new ApplicationInfo(); 9139 ai.uid = -1; 9140 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai); 9141 9142 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 9143 try { 9144 mInternalService.enqueueNotification(notReal, "android", 0, 0, 9145 "testPostFromAndroidForNonExistentPackage", 9146 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 9147 fail("can't post notifications for nonexistent packages, even if you exist"); 9148 } catch (SecurityException e) { 9149 // yay 9150 } 9151 } 9152 9153 @Test testCancelFromAndroidForNonExistentPackage()9154 public void testCancelFromAndroidForNonExistentPackage() throws Exception { 9155 final String notReal = "NOT REAL"; 9156 when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( 9157 PackageManager.NameNotFoundException.class); 9158 ApplicationInfo ai = new ApplicationInfo(); 9159 ai.uid = -1; 9160 when(mPackageManager.getApplicationInfo(anyString(), anyLong(), anyInt())).thenReturn(ai); 9161 9162 // unlike the post case, ignore instead of throwing 9163 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 9164 9165 mInternalService.cancelNotification(notReal, "android", 0, 0, "tag", 9166 sbn.getId(), sbn.getUserId()); 9167 } 9168 9169 @Test testResolveNotificationUid_delegateNotAllowed()9170 public void testResolveNotificationUid_delegateNotAllowed() throws Exception { 9171 when(mPackageManagerClient.getPackageUidAsUser("target", 0)).thenReturn(123); 9172 // no delegate 9173 9174 try { 9175 mService.resolveNotificationUid("caller", "target", 9, 0); 9176 fail("Incorrect uid didn't throw security exception"); 9177 } catch (SecurityException e) { 9178 // yay 9179 } 9180 } 9181 9182 @Test testRemoveForegroundServiceFlagFromNotification_enqueued()9183 public void testRemoveForegroundServiceFlagFromNotification_enqueued() { 9184 when(mAmi.applyForegroundServiceNotification( 9185 any(), anyString(), anyInt(), anyString(), anyInt())) 9186 .thenReturn(SHOW_IMMEDIATELY); 9187 Notification n = new Notification.Builder(mContext, "").build(); 9188 n.flags |= FLAG_FOREGROUND_SERVICE; 9189 9190 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 9191 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9192 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9193 9194 mService.addEnqueuedNotification(r); 9195 9196 mInternalService.removeForegroundServiceFlagFromNotification( 9197 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9198 9199 waitForIdle(); 9200 9201 verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); 9202 } 9203 9204 @Test testRemoveForegroundServiceFlagFromNotification_posted()9205 public void testRemoveForegroundServiceFlagFromNotification_posted() { 9206 when(mAmi.applyForegroundServiceNotification( 9207 any(), anyString(), anyInt(), anyString(), anyInt())) 9208 .thenReturn(SHOW_IMMEDIATELY); 9209 Notification n = new Notification.Builder(mContext, "").build(); 9210 n.flags |= FLAG_FOREGROUND_SERVICE; 9211 9212 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 9213 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9214 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9215 9216 mService.addNotification(r); 9217 9218 mInternalService.removeForegroundServiceFlagFromNotification( 9219 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9220 9221 waitForIdle(); 9222 9223 ArgumentCaptor<NotificationRecord> captor = 9224 ArgumentCaptor.forClass(NotificationRecord.class); 9225 verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); 9226 9227 assertEquals(0, captor.getValue().getNotification().flags); 9228 } 9229 9230 @Test testCannotRemoveForegroundFlagWhenOverLimit_enqueued()9231 public void testCannotRemoveForegroundFlagWhenOverLimit_enqueued() { 9232 when(mAmi.applyForegroundServiceNotification( 9233 any(), anyString(), anyInt(), anyString(), anyInt())) 9234 .thenReturn(SHOW_IMMEDIATELY); 9235 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 9236 Notification n = new Notification.Builder(mContext, "").build(); 9237 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 9238 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9239 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9240 mService.addEnqueuedNotification(r); 9241 } 9242 Notification n = new Notification.Builder(mContext, "").build(); 9243 n.flags |= FLAG_FOREGROUND_SERVICE; 9244 9245 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9246 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 9247 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9248 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9249 9250 mService.addEnqueuedNotification(r); 9251 9252 mInternalService.removeForegroundServiceFlagFromNotification( 9253 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9254 9255 waitForIdle(); 9256 9257 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 9258 mService.getNotificationRecordCount()); 9259 } 9260 9261 @Test testCannotRemoveForegroundFlagWhenOverLimit_posted()9262 public void testCannotRemoveForegroundFlagWhenOverLimit_posted() { 9263 when(mAmi.applyForegroundServiceNotification( 9264 any(), anyString(), anyInt(), anyString(), anyInt())) 9265 .thenReturn(SHOW_IMMEDIATELY); 9266 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 9267 Notification n = new Notification.Builder(mContext, "").build(); 9268 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 9269 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9270 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9271 mService.addNotification(r); 9272 } 9273 Notification n = new Notification.Builder(mContext, "").build(); 9274 n.flags |= FLAG_FOREGROUND_SERVICE; 9275 9276 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9277 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 9278 n, UserHandle.getUserHandleForUid(mUid), null, 0); 9279 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 9280 9281 mService.addNotification(r); 9282 9283 mInternalService.removeForegroundServiceFlagFromNotification( 9284 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 9285 9286 waitForIdle(); 9287 9288 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 9289 mService.getNotificationRecordCount()); 9290 } 9291 9292 @Test testAllowForegroundCustomToasts()9293 public void testAllowForegroundCustomToasts() throws Exception { 9294 final String testPackage = "testPackageName"; 9295 assertEquals(0, mService.mToastQueue.size()); 9296 mService.isSystemUid = false; 9297 mService.isSystemAppId = false; 9298 setToastRateIsWithinQuota(true); 9299 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9300 9301 // package is not suspended 9302 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9303 .thenReturn(false); 9304 9305 // notifications from this package are blocked by the user 9306 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 9307 9308 setAppInForegroundForToasts(mUid, true); 9309 9310 // enqueue toast -> toast should still enqueue 9311 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9312 assertEquals(1, mService.mToastQueue.size()); 9313 assertThat(wasEnqueued).isTrue(); 9314 } 9315 9316 @Test testDisallowBackgroundCustomToasts()9317 public void testDisallowBackgroundCustomToasts() throws Exception { 9318 final String testPackage = "testPackageName"; 9319 assertEquals(0, mService.mToastQueue.size()); 9320 mService.isSystemUid = false; 9321 mService.isSystemAppId = false; 9322 setToastRateIsWithinQuota(true); 9323 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9324 9325 // package is not suspended 9326 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9327 .thenReturn(false); 9328 9329 setAppInForegroundForToasts(mUid, false); 9330 9331 // enqueue toast -> no toasts enqueued 9332 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9333 assertEquals(0, mService.mToastQueue.size()); 9334 assertThat(wasEnqueued).isFalse(); 9335 } 9336 9337 @Test testDontCallShowToastAgainOnTheSameCustomToast()9338 public void testDontCallShowToastAgainOnTheSameCustomToast() throws Exception { 9339 final String testPackage = "testPackageName"; 9340 assertEquals(0, mService.mToastQueue.size()); 9341 mService.isSystemUid = false; 9342 mService.isSystemAppId = false; 9343 setToastRateIsWithinQuota(true); 9344 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9345 9346 // package is not suspended 9347 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9348 .thenReturn(false); 9349 9350 setAppInForegroundForToasts(mUid, true); 9351 9352 Binder token = new Binder(); 9353 ITransientNotification callback = mock(ITransientNotification.class); 9354 INotificationManager nmService = (INotificationManager) mService.mService; 9355 9356 // first time trying to show the toast, showToast gets called 9357 enqueueToast(nmService, testPackage, token, callback); 9358 verify(callback, times(1)).show(any()); 9359 9360 // second time trying to show the same toast, showToast isn't called again (total number of 9361 // invocations stays at one) 9362 enqueueToast(nmService, testPackage, token, callback); 9363 verify(callback, times(1)).show(any()); 9364 } 9365 9366 @Test testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground()9367 public void testToastRateLimiterWontPreventShowCallForCustomToastWhenInForeground() 9368 throws Exception { 9369 final String testPackage = "testPackageName"; 9370 assertEquals(0, mService.mToastQueue.size()); 9371 mService.isSystemUid = false; 9372 mService.isSystemAppId = false; 9373 setToastRateIsWithinQuota(false); // rate limit reached 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 Binder token = new Binder(); 9383 ITransientNotification callback = mock(ITransientNotification.class); 9384 INotificationManager nmService = (INotificationManager) mService.mService; 9385 9386 enqueueToast(nmService, testPackage, token, callback); 9387 verify(callback, times(1)).show(any()); 9388 } 9389 9390 @Test testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground()9391 public void testCustomToastPostedWhileInForeground_blockedIfAppGoesToBackground() 9392 throws Exception { 9393 final String testPackage = "testPackageName"; 9394 assertEquals(0, mService.mToastQueue.size()); 9395 mService.isSystemUid = false; 9396 mService.isSystemAppId = false; 9397 setToastRateIsWithinQuota(true); 9398 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9399 9400 // package is not suspended 9401 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9402 .thenReturn(false); 9403 9404 setAppInForegroundForToasts(mUid, true); 9405 9406 Binder token1 = new Binder(); 9407 Binder token2 = new Binder(); 9408 ITransientNotification callback1 = mock(ITransientNotification.class); 9409 ITransientNotification callback2 = mock(ITransientNotification.class); 9410 INotificationManager nmService = (INotificationManager) mService.mService; 9411 9412 enqueueToast(nmService, testPackage, token1, callback1); 9413 enqueueToast(nmService, testPackage, token2, callback2); 9414 9415 assertEquals(2, mService.mToastQueue.size()); // Both toasts enqueued. 9416 verify(callback1, times(1)).show(any()); // First toast shown. 9417 9418 setAppInForegroundForToasts(mUid, false); 9419 9420 mService.cancelToastLocked(0); // Remove the first toast, and show next. 9421 9422 assertEquals(0, mService.mToastQueue.size()); // Both toasts processed. 9423 verify(callback2, never()).show(any()); // Second toast was never shown. 9424 } 9425 9426 @Test testAllowForegroundTextToasts()9427 public void testAllowForegroundTextToasts() throws Exception { 9428 final String testPackage = "testPackageName"; 9429 assertEquals(0, mService.mToastQueue.size()); 9430 mService.isSystemUid = false; 9431 mService.isSystemAppId = false; 9432 setToastRateIsWithinQuota(true); 9433 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9434 9435 // package is not suspended 9436 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9437 .thenReturn(false); 9438 9439 setAppInForegroundForToasts(mUid, true); 9440 9441 // enqueue toast -> toast should still enqueue 9442 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9443 assertEquals(1, mService.mToastQueue.size()); 9444 assertThat(wasEnqueued).isTrue(); 9445 } 9446 9447 @Test testAllowBackgroundTextToasts()9448 public void testAllowBackgroundTextToasts() throws Exception { 9449 final String testPackage = "testPackageName"; 9450 assertEquals(0, mService.mToastQueue.size()); 9451 mService.isSystemUid = false; 9452 mService.isSystemAppId = false; 9453 setToastRateIsWithinQuota(true); 9454 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9455 9456 // package is not suspended 9457 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9458 .thenReturn(false); 9459 9460 setAppInForegroundForToasts(mUid, false); 9461 9462 // enqueue toast -> toast should still enqueue 9463 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9464 assertEquals(1, mService.mToastQueue.size()); 9465 assertThat(wasEnqueued).isTrue(); 9466 } 9467 9468 @Test testDontCallShowToastAgainOnTheSameTextToast()9469 public void testDontCallShowToastAgainOnTheSameTextToast() throws Exception { 9470 final String testPackage = "testPackageName"; 9471 assertEquals(0, mService.mToastQueue.size()); 9472 mService.isSystemUid = false; 9473 mService.isSystemAppId = false; 9474 setToastRateIsWithinQuota(true); 9475 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9476 9477 // package is not suspended 9478 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9479 .thenReturn(false); 9480 9481 setAppInForegroundForToasts(mUid, true); 9482 9483 Binder token = new Binder(); 9484 INotificationManager nmService = (INotificationManager) mService.mService; 9485 9486 // first time trying to show the toast, showToast gets called 9487 enqueueTextToast(testPackage, "Text"); 9488 verify(mStatusBar, times(1)) 9489 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9490 9491 // second time trying to show the same toast, showToast isn't called again (total number of 9492 // invocations stays at one) 9493 enqueueTextToast(testPackage, "Text"); 9494 verify(mStatusBar, times(1)) 9495 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9496 } 9497 9498 @Test testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground()9499 public void testToastRateLimiterCanPreventShowCallForTextToast_whenInBackground() 9500 throws Exception { 9501 final String testPackage = "testPackageName"; 9502 assertEquals(0, mService.mToastQueue.size()); 9503 mService.isSystemUid = false; 9504 mService.isSystemAppId = false; 9505 setToastRateIsWithinQuota(false); // rate limit reached 9506 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9507 setAppInForegroundForToasts(mUid, false); 9508 9509 // package is not suspended 9510 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9511 .thenReturn(false); 9512 9513 Binder token = new Binder(); 9514 INotificationManager nmService = (INotificationManager) mService.mService; 9515 9516 enqueueTextToast(testPackage, "Text"); 9517 verify(mStatusBar, times(0)) 9518 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9519 } 9520 9521 @Test testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground()9522 public void testToastRateLimiterWontPreventShowCallForTextToast_whenInForeground() 9523 throws Exception { 9524 final String testPackage = "testPackageName"; 9525 assertEquals(0, mService.mToastQueue.size()); 9526 mService.isSystemUid = false; 9527 mService.isSystemAppId = false; 9528 setToastRateIsWithinQuota(false); // rate limit reached 9529 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9530 setAppInForegroundForToasts(mUid, true); 9531 9532 // package is not suspended 9533 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9534 .thenReturn(false); 9535 9536 Binder token = new Binder(); 9537 INotificationManager nmService = (INotificationManager) mService.mService; 9538 9539 enqueueTextToast(testPackage, "Text"); 9540 verify(mStatusBar, times(1)) 9541 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9542 } 9543 9544 @Test testTextToastRateLimiterAllowsLimitAvoidanceWithPermission()9545 public void testTextToastRateLimiterAllowsLimitAvoidanceWithPermission() throws Exception { 9546 final String testPackage = "testPackageName"; 9547 assertEquals(0, mService.mToastQueue.size()); 9548 mService.isSystemUid = false; 9549 mService.isSystemAppId = false; 9550 setToastRateIsWithinQuota(false); // rate limit reached 9551 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, true); 9552 setAppInForegroundForToasts(mUid, false); 9553 9554 // package is not suspended 9555 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9556 .thenReturn(false); 9557 9558 Binder token = new Binder(); 9559 INotificationManager nmService = (INotificationManager) mService.mService; 9560 9561 enqueueTextToast(testPackage, "Text"); 9562 verify(mStatusBar).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 9563 anyInt()); 9564 } 9565 9566 @Test testRateLimitedToasts_windowsRemoved()9567 public void testRateLimitedToasts_windowsRemoved() throws Exception { 9568 final String testPackage = "testPackageName"; 9569 assertEquals(0, mService.mToastQueue.size()); 9570 mService.isSystemUid = false; 9571 mService.isSystemAppId = false; 9572 setToastRateIsWithinQuota(false); // rate limit reached 9573 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9574 setAppInForegroundForToasts(mUid, false); 9575 9576 // package is not suspended 9577 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9578 .thenReturn(false); 9579 9580 Binder token = new Binder(); 9581 INotificationManager nmService = (INotificationManager) mService.mService; 9582 9583 enqueueTextToast(testPackage, "Text"); 9584 9585 // window token was added when enqueued 9586 ArgumentCaptor<Binder> binderCaptor = 9587 ArgumentCaptor.forClass(Binder.class); 9588 verify(mWindowManagerInternal).addWindowToken(binderCaptor.capture(), 9589 eq(TYPE_TOAST), anyInt(), eq(null)); 9590 9591 // but never shown 9592 verify(mStatusBar, times(0)) 9593 .showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), anyInt()); 9594 9595 // and removed when rate limited 9596 verify(mWindowManagerInternal) 9597 .removeWindowToken(eq(binderCaptor.getValue()), eq(true), anyInt()); 9598 } 9599 9600 @Test backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast()9601 public void backgroundSystemCustomToast_callsSetProcessImportantAsForegroundForToast() throws 9602 Exception { 9603 final String testPackage = "testPackageName"; 9604 assertEquals(0, mService.mToastQueue.size()); 9605 mService.isSystemUid = true; 9606 setToastRateIsWithinQuota(true); 9607 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9608 9609 // package is not suspended 9610 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9611 .thenReturn(false); 9612 9613 // notifications from this package are blocked by the user 9614 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 9615 9616 setAppInForegroundForToasts(mUid, false); 9617 9618 // enqueue toast -> toast should still enqueue 9619 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9620 assertEquals(1, mService.mToastQueue.size()); 9621 assertThat(wasEnqueued).isTrue(); 9622 verify(mAm).setProcessImportant(any(), anyInt(), eq(true), any()); 9623 } 9624 9625 @Test foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9626 public void foregroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws 9627 Exception { 9628 final String testPackage = "testPackageName"; 9629 assertEquals(0, mService.mToastQueue.size()); 9630 mService.isSystemUid = false; 9631 mService.isSystemAppId = false; 9632 setToastRateIsWithinQuota(true); 9633 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9634 9635 // package is not suspended 9636 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9637 .thenReturn(false); 9638 9639 setAppInForegroundForToasts(mUid, true); 9640 9641 // enqueue toast -> toast should still enqueue 9642 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9643 assertEquals(1, mService.mToastQueue.size()); 9644 assertThat(wasEnqueued).isTrue(); 9645 verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); 9646 } 9647 9648 @Test backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast()9649 public void backgroundTextToast_callsSetProcessImportantAsNotForegroundForToast() throws 9650 Exception { 9651 final String testPackage = "testPackageName"; 9652 assertEquals(0, mService.mToastQueue.size()); 9653 mService.isSystemUid = false; 9654 mService.isSystemAppId = false; 9655 setToastRateIsWithinQuota(true); 9656 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9657 9658 // package is not suspended 9659 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9660 .thenReturn(false); 9661 9662 setAppInForegroundForToasts(mUid, false); 9663 9664 // enqueue toast -> toast should still enqueue 9665 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9666 assertEquals(1, mService.mToastQueue.size()); 9667 assertThat(wasEnqueued).isTrue(); 9668 verify(mAm).setProcessImportant(any(), anyInt(), eq(false), any()); 9669 } 9670 9671 @Test testTextToastsCallStatusBar()9672 public void testTextToastsCallStatusBar() throws Exception { 9673 allowTestPackageToToast(); 9674 9675 // enqueue toast -> no toasts enqueued 9676 boolean wasEnqueued = enqueueTextToast(TEST_PACKAGE, "Text"); 9677 assertThat(wasEnqueued).isTrue(); 9678 9679 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 9680 } 9681 9682 @Test testTextToastsCallStatusBar_nonUiContext_defaultDisplay()9683 public void testTextToastsCallStatusBar_nonUiContext_defaultDisplay() 9684 throws Exception { 9685 allowTestPackageToToast(); 9686 9687 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); 9688 9689 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 9690 } 9691 9692 @Test testTextToastsCallStatusBar_nonUiContext_secondaryDisplay()9693 public void testTextToastsCallStatusBar_nonUiContext_secondaryDisplay() 9694 throws Exception { 9695 allowTestPackageToToast(); 9696 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9697 9698 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); 9699 9700 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9701 } 9702 9703 @Test testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay()9704 public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_defaultDisplay() 9705 throws Exception { 9706 mockIsVisibleBackgroundUsersSupported(true); 9707 mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); 9708 allowTestPackageToToast(); 9709 9710 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, DEFAULT_DISPLAY); 9711 9712 verifyToastShownForTestPackage("Text", DEFAULT_DISPLAY); 9713 9714 } 9715 9716 @Test testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay()9717 public void testTextToastsCallStatusBar_visibleBgUsers_uiContext_secondaryDisplay() 9718 throws Exception { 9719 mockIsVisibleBackgroundUsersSupported(true); 9720 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9721 mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used 9722 allowTestPackageToToast(); 9723 9724 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ true, SECONDARY_DISPLAY_ID); 9725 9726 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9727 } 9728 9729 @Test testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay()9730 public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_defaultDisplay() 9731 throws Exception { 9732 mockIsVisibleBackgroundUsersSupported(true); 9733 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9734 mockDisplayAssignedToUser(SECONDARY_DISPLAY_ID); 9735 allowTestPackageToToast(); 9736 9737 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, DEFAULT_DISPLAY); 9738 9739 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9740 } 9741 9742 @Test testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay()9743 public void testTextToastsCallStatusBar_visibleBgUsers_nonUiContext_secondaryDisplay() 9744 throws Exception { 9745 mockIsVisibleBackgroundUsersSupported(true); 9746 mockIsUserVisible(SECONDARY_DISPLAY_ID, true); 9747 mockDisplayAssignedToUser(INVALID_DISPLAY); // make sure it's not used 9748 allowTestPackageToToast(); 9749 9750 enqueueTextToast(TEST_PACKAGE, "Text", /* isUiContext= */ false, SECONDARY_DISPLAY_ID); 9751 9752 verifyToastShownForTestPackage("Text", SECONDARY_DISPLAY_ID); 9753 } 9754 9755 @Test testTextToastsCallStatusBar_userNotVisibleOnDisplay()9756 public void testTextToastsCallStatusBar_userNotVisibleOnDisplay() throws Exception { 9757 final String testPackage = "testPackageName"; 9758 assertEquals(0, mService.mToastQueue.size()); 9759 mService.isSystemUid = false; 9760 mService.isSystemAppId = false; 9761 setToastRateIsWithinQuota(true); 9762 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9763 mockIsUserVisible(DEFAULT_DISPLAY, false); 9764 9765 // package is not suspended 9766 when(mPackageManager.isPackageSuspendedForUser(testPackage, UserHandle.getUserId(mUid))) 9767 .thenReturn(false); 9768 9769 // enqueue toast -> no toasts enqueued 9770 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9771 verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 9772 anyInt()); 9773 assertEquals(0, mService.mToastQueue.size()); 9774 assertThat(wasEnqueued).isFalse(); 9775 } 9776 9777 @Test testDisallowToastsFromSuspendedPackages()9778 public void testDisallowToastsFromSuspendedPackages() throws Exception { 9779 final String testPackage = "testPackageName"; 9780 assertEquals(0, mService.mToastQueue.size()); 9781 mService.isSystemUid = false; 9782 mService.isSystemAppId = false; 9783 setToastRateIsWithinQuota(true); 9784 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9785 9786 // package is suspended 9787 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9788 .thenReturn(true); 9789 9790 // notifications from this package are NOT blocked by the user 9791 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 9792 9793 // enqueue toast -> no toasts enqueued 9794 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9795 verify(mStatusBar, never()).showToast(anyInt(), any(), any(), any(), any(), anyInt(), any(), 9796 anyInt()); 9797 assertEquals(0, mService.mToastQueue.size()); 9798 assertThat(wasEnqueued).isFalse(); 9799 } 9800 9801 @Test testDisallowToastsFromBlockedApps()9802 public void testDisallowToastsFromBlockedApps() throws Exception { 9803 final String testPackage = "testPackageName"; 9804 assertEquals(0, mService.mToastQueue.size()); 9805 mService.isSystemUid = false; 9806 mService.isSystemAppId = false; 9807 setToastRateIsWithinQuota(true); 9808 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9809 9810 // package is not suspended 9811 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9812 .thenReturn(false); 9813 9814 // notifications from this package are blocked by the user 9815 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 9816 9817 setAppInForegroundForToasts(mUid, false); 9818 9819 // enqueue toast -> no toasts enqueued 9820 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9821 assertEquals(0, mService.mToastQueue.size()); 9822 assertThat(wasEnqueued).isFalse(); 9823 } 9824 9825 @Test testAlwaysAllowSystemToasts()9826 public void testAlwaysAllowSystemToasts() throws Exception { 9827 final String testPackage = "testPackageName"; 9828 assertEquals(0, mService.mToastQueue.size()); 9829 mService.isSystemUid = true; 9830 setToastRateIsWithinQuota(true); 9831 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9832 9833 // package is suspended 9834 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9835 .thenReturn(true); 9836 9837 // notifications from this package ARE blocked by the user 9838 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 9839 9840 setAppInForegroundForToasts(mUid, false); 9841 9842 // enqueue toast -> system toast can still be enqueued 9843 boolean wasEnqueued = enqueueToast(testPackage, new TestableToastCallback()); 9844 assertEquals(1, mService.mToastQueue.size()); 9845 assertThat(wasEnqueued).isTrue(); 9846 } 9847 9848 @Test testLimitNumberOfQueuedToastsFromPackage()9849 public void testLimitNumberOfQueuedToastsFromPackage() throws Exception { 9850 final String testPackage = "testPackageName"; 9851 assertEquals(0, mService.mToastQueue.size()); 9852 mService.isSystemUid = false; 9853 mService.isSystemAppId = false; 9854 setToastRateIsWithinQuota(true); 9855 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9856 9857 // package is not suspended 9858 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9859 .thenReturn(false); 9860 9861 INotificationManager nmService = (INotificationManager) mService.mService; 9862 9863 // Trying to quickly enqueue more toast than allowed. 9864 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS + 1; i++) { 9865 boolean wasEnqueued = enqueueTextToast(testPackage, "Text"); 9866 if (i < NotificationManagerService.MAX_PACKAGE_TOASTS) { 9867 assertThat(wasEnqueued).isTrue(); 9868 } else { 9869 assertThat(wasEnqueued).isFalse(); 9870 } 9871 } 9872 // Only allowed number enqueued, rest ignored. 9873 assertEquals(NotificationManagerService.MAX_PACKAGE_TOASTS, mService.mToastQueue.size()); 9874 } 9875 9876 @Test testPrioritizeSystemToasts()9877 public void testPrioritizeSystemToasts() throws Exception { 9878 // Insert non-system toasts 9879 final String testPackage = "testPackageName"; 9880 assertEquals(0, mService.mToastQueue.size()); 9881 mService.isSystemUid = false; 9882 mService.isSystemAppId = false; 9883 setToastRateIsWithinQuota(true); 9884 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackage, false); 9885 9886 // package is not suspended 9887 when(mPackageManager.isPackageSuspendedForUser(testPackage, mUserId)) 9888 .thenReturn(false); 9889 9890 INotificationManager nmService = (INotificationManager) mService.mService; 9891 9892 // Enqueue maximum number of toasts for test package 9893 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) { 9894 enqueueTextToast(testPackage, "Text"); 9895 } 9896 9897 // Enqueue system toast 9898 final String testPackageSystem = "testPackageNameSystem"; 9899 mService.isSystemUid = true; 9900 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem, false); 9901 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem, mUserId)) 9902 .thenReturn(false); 9903 9904 enqueueToast(testPackageSystem, new TestableToastCallback()); 9905 9906 // System toast is inserted at the front of the queue, behind current showing toast 9907 assertEquals(testPackageSystem, mService.mToastQueue.get(1).pkg); 9908 } 9909 9910 @Test testPrioritizeSystemToasts_enqueueAfterExistingSystemToast()9911 public void testPrioritizeSystemToasts_enqueueAfterExistingSystemToast() throws Exception { 9912 // Insert system toasts 9913 final String testPackageSystem1 = "testPackageNameSystem1"; 9914 assertEquals(0, mService.mToastQueue.size()); 9915 mService.isSystemUid = true; 9916 setToastRateIsWithinQuota(true); 9917 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem1, false); 9918 9919 // package is not suspended 9920 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem1, mUserId)) 9921 .thenReturn(false); 9922 9923 INotificationManager nmService = (INotificationManager) mService.mService; 9924 9925 // Enqueue maximum number of toasts for test package 9926 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_TOASTS; i++) { 9927 enqueueTextToast(testPackageSystem1, "Text"); 9928 } 9929 9930 // Enqueue another system toast 9931 final String testPackageSystem2 = "testPackageNameSystem2"; 9932 mService.isSystemUid = true; 9933 setIfPackageHasPermissionToAvoidToastRateLimiting(testPackageSystem2, false); 9934 when(mPackageManager.isPackageSuspendedForUser(testPackageSystem2, mUserId)) 9935 .thenReturn(false); 9936 9937 enqueueToast(testPackageSystem2, new TestableToastCallback()); 9938 9939 // System toast is inserted at the back of the queue, after the other system toasts 9940 assertEquals(testPackageSystem2, 9941 mService.mToastQueue.get(mService.mToastQueue.size() - 1).pkg); 9942 } 9943 setAppInForegroundForToasts(int uid, boolean inForeground)9944 private void setAppInForegroundForToasts(int uid, boolean inForeground) { 9945 int importance = (inForeground) ? IMPORTANCE_FOREGROUND : IMPORTANCE_NONE; 9946 when(mActivityManager.getUidImportance(mUid)).thenReturn(importance); 9947 when(mAtm.hasResumedActivity(uid)).thenReturn(inForeground); 9948 } 9949 setToastRateIsWithinQuota(boolean isWithinQuota)9950 private void setToastRateIsWithinQuota(boolean isWithinQuota) { 9951 when(mToastRateLimiter.isWithinQuota( 9952 anyInt(), 9953 anyString(), 9954 eq(NotificationManagerService.TOAST_QUOTA_TAG))) 9955 .thenReturn(isWithinQuota); 9956 } 9957 setIfPackageHasPermissionToAvoidToastRateLimiting( String pkg, boolean hasPermission)9958 private void setIfPackageHasPermissionToAvoidToastRateLimiting( 9959 String pkg, boolean hasPermission) throws Exception { 9960 when(mPackageManager.checkPermission(android.Manifest.permission.UNLIMITED_TOASTS, 9961 pkg, mUserId)) 9962 .thenReturn(hasPermission ? PERMISSION_GRANTED : PERMISSION_DENIED); 9963 } 9964 9965 @Test testOnPanelRevealedAndHidden()9966 public void testOnPanelRevealedAndHidden() { 9967 int items = 5; 9968 mService.mNotificationDelegate.onPanelRevealed(false, items); 9969 verify(mAssistants, times(1)).onPanelRevealed(eq(items)); 9970 9971 mService.mNotificationDelegate.onPanelHidden(); 9972 verify(mAssistants, times(1)).onPanelHidden(); 9973 9974 assertEquals(2, mNotificationRecordLogger.numCalls()); 9975 assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_OPEN, 9976 mNotificationRecordLogger.event(0)); 9977 assertEquals(NotificationRecordLogger.NotificationPanelEvent.NOTIFICATION_PANEL_CLOSE, 9978 mNotificationRecordLogger.event(1)); 9979 } 9980 9981 @Test 9982 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testOnNotificationSmartReplySent()9983 public void testOnNotificationSmartReplySent() { 9984 final int replyIndex = 2; 9985 final String reply = "Hello"; 9986 final boolean modifiedBeforeSending = true; 9987 final boolean generatedByAssistant = true; 9988 9989 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 9990 r.setSuggestionsGeneratedByAssistant(generatedByAssistant); 9991 mService.addNotification(r); 9992 9993 mService.mNotificationDelegate.onNotificationSmartReplySent( 9994 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN, 9995 modifiedBeforeSending); 9996 verify(mAssistants).notifyAssistantSuggestedReplySent( 9997 eq(r.getSbn()), eq(FLAG_FILTER_TYPE_ALERTING), eq(reply), eq(generatedByAssistant)); 9998 assertEquals(1, mNotificationRecordLogger.numCalls()); 9999 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_SMART_REPLIED, 10000 mNotificationRecordLogger.event(0)); 10001 // Check that r.recordSmartReplied was called. 10002 assertThat(r.getSbn().getNotification().flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY) 10003 .isGreaterThan(0); 10004 assertThat(r.getStats().hasSmartReplied()).isTrue(); 10005 } 10006 10007 @Test 10008 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate()10009 public void testStats_SmartReplyAlreadyLifetimeExtendedPostsUpdate() throws Exception { 10010 final int replyIndex = 2; 10011 final String reply = "Hello"; 10012 final boolean modifiedBeforeSending = true; 10013 10014 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10015 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 10016 r.getSbn().getNotification().flags |= FLAG_ONLY_ALERT_ONCE; 10017 r.setSuggestionsGeneratedByAssistant(true); 10018 r.setCanceledAfterLifetimeExtension(true); 10019 r.setPostSilently(true); 10020 mService.addNotification(r); 10021 10022 mService.mNotificationDelegate.onNotificationSmartReplySent( 10023 r.getKey(), replyIndex, reply, NOTIFICATION_LOCATION_UNKNOWN, 10024 modifiedBeforeSending); 10025 waitForIdle(); 10026 10027 // At the moment prepareNotifyPostedLocked is called on the listeners, 10028 // verify that FLAG_ONLY_ALERT_ONCE and shouldPostSilently are set, regardless of initial 10029 // values. 10030 doAnswer( 10031 invocation -> { 10032 int flags = ((NotificationRecord) invocation.getArgument(0)) 10033 .getSbn().getNotification().flags; 10034 assertThat(flags & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 10035 boolean shouldPostSilently = ((NotificationRecord) invocation.getArgument(0)) 10036 .shouldPostSilently(); 10037 assertThat(shouldPostSilently).isTrue(); 10038 return null; 10039 } 10040 ).when(mListeners).prepareNotifyPostedLocked(any(), any(), anyBoolean()); 10041 10042 // Checks that a post update is sent. 10043 verify(mWorkerHandler, times(1)) 10044 .post(any(NotificationManagerService.PostNotificationRunnable.class)); 10045 ArgumentCaptor<NotificationRecord> captor = 10046 ArgumentCaptor.forClass(NotificationRecord.class); 10047 verify(mListeners, times(1)).prepareNotifyPostedLocked(captor.capture(), any(), 10048 anyBoolean()); 10049 assertThat(captor.getValue().getNotification().flags 10050 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo( 10051 FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY); 10052 // Flag was present before, so it's set afterward 10053 assertThat(captor.getValue().getNotification().flags 10054 & FLAG_ONLY_ALERT_ONCE).isEqualTo(FLAG_ONLY_ALERT_ONCE); 10055 // Should post silently was set before, so it's set afterward. 10056 assertThat(captor.getValue().shouldPostSilently()).isTrue(); 10057 } 10058 10059 @Test testOnNotificationActionClick()10060 public void testOnNotificationActionClick() { 10061 final int actionIndex = 2; 10062 final Notification.Action action = 10063 new Notification.Action.Builder(null, "text", mActivityIntent).build(); 10064 final boolean generatedByAssistant = false; 10065 10066 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10067 mService.addNotification(r); 10068 10069 NotificationVisibility notificationVisibility = 10070 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10071 mService.mNotificationDelegate.onNotificationActionClick( 10072 10, 10, r.getKey(), actionIndex, action, notificationVisibility, 10073 generatedByAssistant); 10074 verify(mAssistants).notifyAssistantActionClicked( 10075 eq(r), eq(action), eq(generatedByAssistant)); 10076 10077 assertEquals(1, mNotificationRecordLogger.numCalls()); 10078 assertEquals( 10079 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ACTION_CLICKED_2, 10080 mNotificationRecordLogger.event(0)); 10081 } 10082 10083 @Test 10084 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testActionClickLifetimeExtendedCancel()10085 public void testActionClickLifetimeExtendedCancel() throws Exception { 10086 final Notification.Action action = 10087 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 10088 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 10089 10090 // Creates a notification marked as being lifetime extended. 10091 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10092 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 10093 mService.addNotification(r); 10094 10095 StatusBarNotification[] notifs = 10096 mBinderService.getActiveNotifications(mPkg); 10097 assertThat(notifs.length).isEqualTo(1); 10098 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10099 10100 // Call on action click. 10101 NotificationVisibility notificationVisibility = 10102 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10103 mService.mNotificationDelegate.onNotificationActionClick( 10104 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 10105 /*generatedByAssistant=*/false); 10106 10107 // Lifetime extended flag persists. 10108 assertThat(r.getSbn().getNotification().flags 10109 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 10110 10111 mTestableLooper.moveTimeForward(210); 10112 waitForIdle(); 10113 verify(mWorkerHandler, times(1)) 10114 .scheduleCancelNotification( 10115 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 10116 10117 // Check that the cancelation occurred and the notification is gone. 10118 notifs = mBinderService.getActiveNotifications(mPkg); 10119 assertThat(notifs.length).isEqualTo(0); 10120 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 10121 } 10122 10123 @Test 10124 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testActionClickLifetimeExtendedCancel_PreventByNoDismiss()10125 public void testActionClickLifetimeExtendedCancel_PreventByNoDismiss() throws Exception { 10126 final Notification.Action action = 10127 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 10128 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 10129 10130 // Creates a notification marked as being lifetime extended. 10131 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10132 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 10133 // Make the notification non-dismissable 10134 r.getSbn().getNotification().flags |= FLAG_NO_DISMISS; 10135 mService.addNotification(r); 10136 10137 StatusBarNotification[] notifs = 10138 mBinderService.getActiveNotifications(mPkg); 10139 assertThat(notifs.length).isEqualTo(1); 10140 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10141 10142 // Call on action click. 10143 NotificationVisibility notificationVisibility = 10144 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10145 mService.mNotificationDelegate.onNotificationActionClick( 10146 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 10147 /*generatedByAssistant=*/false); 10148 10149 // Lifetime extended flag persists. 10150 assertThat(r.getSbn().getNotification().flags 10151 & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 10152 10153 mTestableLooper.moveTimeForward(210); 10154 waitForIdle(); 10155 verify(mWorkerHandler, times(1)) 10156 .scheduleCancelNotification( 10157 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 10158 10159 // The cancellation is dropped and the notification is still present, with the update. 10160 notifs = mBinderService.getActiveNotifications(mPkg); 10161 assertThat(notifs.length).isEqualTo(1); 10162 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10163 } 10164 10165 @Test 10166 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) testUpdateOnActionClickDropsLifetimeExtendedCancel()10167 public void testUpdateOnActionClickDropsLifetimeExtendedCancel() throws Exception { 10168 final Notification.Action action = 10169 new Notification.Action.Builder(null, "text", PendingIntent.getActivity( 10170 mContext, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE)).build(); 10171 10172 // Creates a notification marked as being lifetime extended. 10173 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10174 r.getSbn().getNotification().flags |= FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY; 10175 mService.addNotification(r); 10176 10177 StatusBarNotification[] notifs = 10178 mBinderService.getActiveNotifications(mPkg); 10179 assertThat(notifs.length).isEqualTo(1); 10180 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10181 10182 // Call on action click. 10183 NotificationVisibility notificationVisibility = 10184 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10185 mService.mNotificationDelegate.onNotificationActionClick( 10186 10, 10, r.getKey(), /*actionIndex=*/2, action, notificationVisibility, 10187 /*generatedByAssistant=*/false); 10188 10189 // The "app" sends an update of the notification in response. 10190 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 10191 r.getSbn().getId(), r.getSbn().getNotification(), r.getSbn().getUserId()); 10192 10193 mTestableLooper.moveTimeForward(210); 10194 waitForIdle(); 10195 verify(mWorkerHandler, times(1)) 10196 .scheduleCancelNotification( 10197 any(NotificationManagerService.CancelNotificationRunnable.class), eq(200)); 10198 10199 // The cancellation is dropped and the notification is still present, with the update. 10200 notifs = mBinderService.getActiveNotifications(mPkg); 10201 assertThat(notifs.length).isEqualTo(1); 10202 assertThat(mService.getNotificationRecordCount()).isEqualTo(1); 10203 } 10204 10205 @Test testOnAssistantNotificationActionClick()10206 public void testOnAssistantNotificationActionClick() { 10207 final int actionIndex = 1; 10208 final Notification.Action action = 10209 new Notification.Action.Builder(null, "text", mActivityIntent).build(); 10210 final boolean generatedByAssistant = true; 10211 10212 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10213 mService.addNotification(r); 10214 10215 NotificationVisibility notificationVisibility = 10216 NotificationVisibility.obtain(r.getKey(), 1, 2, true); 10217 mService.mNotificationDelegate.onNotificationActionClick( 10218 10, 10, r.getKey(), actionIndex, action, notificationVisibility, 10219 generatedByAssistant); 10220 verify(mAssistants).notifyAssistantActionClicked( 10221 eq(r), eq(action), eq(generatedByAssistant)); 10222 10223 assertEquals(1, mNotificationRecordLogger.numCalls()); 10224 assertEquals( 10225 NotificationRecordLogger.NotificationEvent.NOTIFICATION_ASSIST_ACTION_CLICKED_1, 10226 mNotificationRecordLogger.event(0)); 10227 } 10228 10229 10230 @Test testLogSmartSuggestionsVisible_triggerOnExpandAndVisible()10231 public void testLogSmartSuggestionsVisible_triggerOnExpandAndVisible() { 10232 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10233 mService.addNotification(r); 10234 10235 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 10236 NOTIFICATION_LOCATION_UNKNOWN); 10237 NotificationVisibility[] notificationVisibility = new NotificationVisibility[] { 10238 NotificationVisibility.obtain(r.getKey(), 0, 0, true) 10239 }; 10240 mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility, 10241 new NotificationVisibility[0]); 10242 10243 assertEquals(1, mService.countLogSmartSuggestionsVisible); 10244 } 10245 10246 @Test testLogSmartSuggestionsVisible_noTriggerOnExpand()10247 public void testLogSmartSuggestionsVisible_noTriggerOnExpand() { 10248 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10249 mService.addNotification(r); 10250 10251 mService.mNotificationDelegate.onNotificationExpansionChanged(r.getKey(), false, true, 10252 NOTIFICATION_LOCATION_UNKNOWN); 10253 10254 assertEquals(0, mService.countLogSmartSuggestionsVisible); 10255 } 10256 10257 @Test testLogSmartSuggestionsVisible_noTriggerOnVisible()10258 public void testLogSmartSuggestionsVisible_noTriggerOnVisible() { 10259 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10260 mService.addNotification(r); 10261 10262 NotificationVisibility[] notificationVisibility = new NotificationVisibility[]{ 10263 NotificationVisibility.obtain(r.getKey(), 0, 0, true) 10264 }; 10265 mService.mNotificationDelegate.onNotificationVisibilityChanged(notificationVisibility, 10266 new NotificationVisibility[0]); 10267 10268 assertEquals(0, mService.countLogSmartSuggestionsVisible); 10269 } 10270 10271 @Test testReportSeen_delegated()10272 public void testReportSeen_delegated() { 10273 Notification.Builder nb = 10274 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 10275 .setContentTitle("foo") 10276 .setSmallIcon(android.R.drawable.sym_def_app_icon); 10277 10278 StatusBarNotification sbn = new StatusBarNotification(mPkg, "opPkg", 0, "tag", mUid, 0, 10279 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10280 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10281 10282 mService.reportSeen(r); 10283 verify(mAppUsageStats, never()).reportEvent(anyString(), anyInt(), anyInt()); 10284 10285 } 10286 10287 @Test testReportSeen_notDelegated()10288 public void testReportSeen_notDelegated() { 10289 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10290 10291 mService.reportSeen(r); 10292 verify(mAppUsageStats, times(1)).reportEvent(anyString(), anyInt(), anyInt()); 10293 } 10294 10295 @Test testNotificationStats_notificationError()10296 public void testNotificationStats_notificationError() { 10297 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10298 mService.addNotification(r); 10299 10300 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, r.getSbn().getId(), 10301 r.getSbn().getTag(), mUid, 0, 10302 new Notification.Builder(mContext, mTestNotificationChannel.getId()).build(), 10303 UserHandle.getUserHandleForUid(mUid), null, 0); 10304 NotificationRecord update = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10305 mService.addEnqueuedNotification(update); 10306 assertNull(update.getSbn().getNotification().getSmallIcon()); 10307 10308 NotificationManagerService.PostNotificationRunnable runnable = 10309 mService.new PostNotificationRunnable(update.getKey(), r.getSbn().getPackageName(), 10310 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 10311 runnable.run(); 10312 waitForIdle(); 10313 10314 ArgumentCaptor<NotificationStats> captor = ArgumentCaptor.forClass(NotificationStats.class); 10315 verify(mListeners).notifyRemovedLocked(any(), anyInt(), captor.capture()); 10316 assertNotNull(captor.getValue()); 10317 } 10318 10319 @Test testCanNotifyAsUser_crossUser()10320 public void testCanNotifyAsUser_crossUser() throws Exception { 10321 // same user no problem 10322 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId()); 10323 10324 // cross user, no permission, problem 10325 try { 10326 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1); 10327 fail("Should not be callable cross user without cross user permission"); 10328 } catch (SecurityException e) { 10329 // good 10330 } 10331 10332 // cross user, with permission, no problem 10333 enableInteractAcrossUsers(); 10334 mBinderService.canNotifyAsPackage("src", "target", mContext.getUserId() + 1); 10335 } 10336 10337 @Test testGetNotificationChannels_crossUser()10338 public void testGetNotificationChannels_crossUser() throws Exception { 10339 // same user no problem 10340 mBinderService.getNotificationChannels("src", "target", mContext.getUserId()); 10341 10342 // cross user, no permission, problem 10343 try { 10344 mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1); 10345 fail("Should not be callable cross user without cross user permission"); 10346 } catch (SecurityException e) { 10347 // good 10348 } 10349 10350 // cross user, with permission, no problem 10351 enableInteractAcrossUsers(); 10352 mBinderService.getNotificationChannels("src", "target", mContext.getUserId() + 1); 10353 } 10354 10355 @Test setDefaultAssistantForUser_fromConfigXml()10356 public void setDefaultAssistantForUser_fromConfigXml() { 10357 ComponentName xmlConfig = new ComponentName("config", "xml"); 10358 ArraySet<ComponentName> components = new ArraySet<>(Arrays.asList(xmlConfig)); 10359 when(mResources 10360 .getString( 10361 com.android.internal.R.string.config_defaultAssistantAccessComponent)) 10362 .thenReturn(xmlConfig.flattenToString()); 10363 when(mContext.getResources()).thenReturn(mResources); 10364 when(mAssistants.queryPackageForServices(eq(null), anyInt(), anyInt())) 10365 .thenReturn(components); 10366 when(mAssistants.getDefaultComponents()) 10367 .thenReturn(components); 10368 mService.setNotificationAssistantAccessGrantedCallback( 10369 mNotificationAssistantAccessGrantedCallback); 10370 10371 10372 mService.setDefaultAssistantForUser(0); 10373 10374 verify(mNotificationAssistantAccessGrantedCallback) 10375 .onGranted(eq(xmlConfig), eq(0), eq(true), eq(false)); 10376 } 10377 10378 @Test clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne()10379 public void clearMultipleDefaultAssistantPackagesShouldEnableOnlyOne() throws RemoteException { 10380 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 10381 generateResetComponentValues(); 10382 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners); 10383 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 10384 ComponentName deviceConfig1 = new ComponentName("device", "config1"); 10385 ComponentName deviceConfig2 = new ComponentName("device", "config2"); 10386 changes.put(true, new ArrayList(Arrays.asList(deviceConfig1, deviceConfig2))); 10387 changes.put(false, new ArrayList()); 10388 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes); 10389 mService.getBinderService().clearData("device", 0, false); 10390 verify(mAssistants, times(1)) 10391 .setPackageOrComponentEnabled( 10392 eq("device/config2"), 10393 eq(0), eq(true), eq(false)); 10394 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 10395 eq("device"), eq(0), eq(false), eq(true)); 10396 } 10397 10398 @Test testNASSettingUpgrade_userSetNull()10399 public void testNASSettingUpgrade_userSetNull() throws RemoteException { 10400 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 10401 TestableNotificationManagerService service = spy(mService); 10402 int userId = 11; 10403 setUsers(new int[]{userId}); 10404 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 10405 setNASMigrationDone(false, userId); 10406 when(mAssistants.getDefaultFromConfig()) 10407 .thenReturn(newDefaultComponent); 10408 when(mAssistants.getAllowedComponents(anyInt())) 10409 .thenReturn(new ArrayList<>()); 10410 when(mAssistants.hasUserSet(userId)).thenReturn(true); 10411 10412 service.migrateDefaultNAS(); 10413 assertTrue(service.isNASMigrationDone(userId)); 10414 verify(mAssistants, times(1)).clearDefaults(); 10415 } 10416 10417 @Test testNASSettingUpgrade_userSet()10418 public void testNASSettingUpgrade_userSet() throws RemoteException { 10419 ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component1"); 10420 TestableNotificationManagerService service = spy(mService); 10421 int userId = 11; 10422 setUsers(new int[]{userId}); 10423 when(mUm.getProfileIds(userId, false)).thenReturn(new int[]{userId}); 10424 setNASMigrationDone(false, userId); 10425 when(mAssistants.getDefaultFromConfig()) 10426 .thenReturn(defaultComponent); 10427 when(mAssistants.getAllowedComponents(anyInt())) 10428 .thenReturn(new ArrayList(Arrays.asList(defaultComponent))); 10429 when(mAssistants.hasUserSet(userId)).thenReturn(true); 10430 10431 service.migrateDefaultNAS(); 10432 verify(mAssistants, times(1)).setUserSet(userId, false); 10433 //resetDefaultAssistantsIfNecessary should invoke from readPolicyXml() and migration 10434 verify(mAssistants, times(2)).resetDefaultAssistantsIfNecessary(); 10435 } 10436 10437 @Test testNASSettingUpgrade_multiUser()10438 public void testNASSettingUpgrade_multiUser() throws RemoteException { 10439 ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 10440 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2"); 10441 TestableNotificationManagerService service = spy(mService); 10442 int userId1 = 11; 10443 int userId2 = 12; 10444 setUsers(new int[]{userId1, userId2}); 10445 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1}); 10446 when(mUm.getProfileIds(userId2, false)).thenReturn(new int[]{userId2}); 10447 10448 setNASMigrationDone(false, userId1); 10449 setNASMigrationDone(false, userId2); 10450 when(mAssistants.getDefaultComponents()) 10451 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent))); 10452 when(mAssistants.getDefaultFromConfig()) 10453 .thenReturn(newDefaultComponent); 10454 //User1: set different NAS 10455 when(mAssistants.getAllowedComponents(userId1)) 10456 .thenReturn(Arrays.asList(oldDefaultComponent)); 10457 //User2: set to none 10458 when(mAssistants.getAllowedComponents(userId2)) 10459 .thenReturn(new ArrayList<>()); 10460 10461 when(mAssistants.hasUserSet(userId1)).thenReturn(true); 10462 when(mAssistants.hasUserSet(userId2)).thenReturn(true); 10463 10464 service.migrateDefaultNAS(); 10465 // user1's setting get reset 10466 verify(mAssistants, times(1)).setUserSet(userId1, false); 10467 verify(mAssistants, times(0)).setUserSet(eq(userId2), anyBoolean()); 10468 assertTrue(service.isNASMigrationDone(userId2)); 10469 10470 } 10471 10472 @Test testNASSettingUpgrade_multiProfile()10473 public void testNASSettingUpgrade_multiProfile() throws RemoteException { 10474 ComponentName oldDefaultComponent = ComponentName.unflattenFromString("package/Component1"); 10475 ComponentName newDefaultComponent = ComponentName.unflattenFromString("package/Component2"); 10476 TestableNotificationManagerService service = spy(mService); 10477 int userId1 = 11; 10478 int userId2 = 12; //work profile 10479 setUsers(new int[]{userId1, userId2}); 10480 when(mUm.isManagedProfile(userId2)).thenReturn(true); 10481 when(mUm.getProfileIds(userId1, false)).thenReturn(new int[]{userId1, userId2}); 10482 10483 setNASMigrationDone(false, userId1); 10484 setNASMigrationDone(false, userId2); 10485 when(mAssistants.getDefaultComponents()) 10486 .thenReturn(new ArraySet<>(Arrays.asList(oldDefaultComponent))); 10487 when(mAssistants.getDefaultFromConfig()) 10488 .thenReturn(newDefaultComponent); 10489 //Both profiles: set different NAS 10490 when(mAssistants.getAllowedComponents(userId1)) 10491 .thenReturn(Arrays.asList(oldDefaultComponent)); 10492 when(mAssistants.getAllowedComponents(userId2)) 10493 .thenReturn(Arrays.asList(oldDefaultComponent)); 10494 10495 when(mAssistants.hasUserSet(userId1)).thenReturn(true); 10496 when(mAssistants.hasUserSet(userId2)).thenReturn(true); 10497 10498 service.migrateDefaultNAS(); 10499 assertFalse(service.isNASMigrationDone(userId1)); 10500 assertFalse(service.isNASMigrationDone(userId2)); 10501 } 10502 10503 10504 10505 @Test testNASSettingUpgrade_clearDataAfterMigrationIsDone()10506 public void testNASSettingUpgrade_clearDataAfterMigrationIsDone() throws RemoteException { 10507 ComponentName defaultComponent = ComponentName.unflattenFromString("package/Component"); 10508 TestableNotificationManagerService service = spy(mService); 10509 int userId = 12; 10510 setUsers(new int[]{userId}); 10511 when(mAssistants.getDefaultComponents()) 10512 .thenReturn(new ArraySet<>(Arrays.asList(defaultComponent))); 10513 when(mAssistants.hasUserSet(userId)).thenReturn(true); 10514 setNASMigrationDone(true, userId); 10515 10516 //Test User clear data 10517 ArrayMap<Boolean, ArrayList<ComponentName>> changedListeners = 10518 generateResetComponentValues(); 10519 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changedListeners); 10520 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 10521 changes.put(true, new ArrayList(Arrays.asList(defaultComponent))); 10522 changes.put(false, new ArrayList()); 10523 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changes); 10524 10525 //Clear data 10526 service.getBinderService().clearData("package", userId, false); 10527 //Test migrate flow again 10528 service.migrateDefaultNAS(); 10529 10530 //Migration should not happen again 10531 verify(mAssistants, times(0)).setUserSet(userId, false); 10532 verify(mAssistants, times(0)).clearDefaults(); 10533 //resetDefaultAssistantsIfNecessary should only invoke once from readPolicyXml() 10534 verify(mAssistants, times(1)).resetDefaultAssistantsIfNecessary(); 10535 10536 } 10537 setNASMigrationDone(boolean done, int userId)10538 private void setNASMigrationDone(boolean done, int userId) { 10539 Settings.Secure.putIntForUser(mContext.getContentResolver(), 10540 Settings.Secure.NAS_SETTINGS_UPDATED, done ? 1 : 0, userId); 10541 } 10542 setUsers(int[] userIds)10543 private void setUsers(int[] userIds) { 10544 List<UserInfo> users = new ArrayList<>(); 10545 for (int id: userIds) { 10546 users.add(new UserInfo(id, String.valueOf(id), 0)); 10547 } 10548 for (UserInfo user : users) { 10549 when(mUm.getUserInfo(eq(user.id))).thenReturn(user); 10550 } 10551 when(mUm.getUsers()).thenReturn(users); 10552 } 10553 10554 @Test clearDefaultListenersPackageShouldEnableIt()10555 public void clearDefaultListenersPackageShouldEnableIt() throws RemoteException { 10556 ArrayMap<Boolean, ArrayList<ComponentName>> changedAssistants = 10557 generateResetComponentValues(); 10558 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changedAssistants); 10559 ComponentName deviceConfig = new ComponentName("device", "config"); 10560 ArrayMap<Boolean, ArrayList<ComponentName>> changes = new ArrayMap<>(); 10561 changes.put(true, new ArrayList(Arrays.asList(deviceConfig))); 10562 changes.put(false, new ArrayList()); 10563 when(mListeners.resetComponents(anyString(), anyInt())) 10564 .thenReturn(changes); 10565 mService.getBinderService().clearData("device", 0, false); 10566 verify(mConditionProviders, times(1)).setPackageOrComponentEnabled( 10567 eq("device"), eq(0), eq(false), eq(true)); 10568 } 10569 10570 @Test clearDefaultDnDPackageShouldEnableIt()10571 public void clearDefaultDnDPackageShouldEnableIt() throws RemoteException { 10572 ArrayMap<Boolean, ArrayList<ComponentName>> changed = generateResetComponentValues(); 10573 when(mAssistants.resetComponents(anyString(), anyInt())).thenReturn(changed); 10574 when(mListeners.resetComponents(anyString(), anyInt())).thenReturn(changed); 10575 mService.getBinderService().clearData("pkgName", 0, false); 10576 verify(mConditionProviders, times(1)).resetPackage( 10577 eq("pkgName"), eq(0)); 10578 } 10579 10580 @Test testFlagBubble()10581 public void testFlagBubble() throws RemoteException { 10582 setUpPrefsForBubbles(mPkg, mUid, 10583 true /* global */, 10584 BUBBLE_PREFERENCE_ALL /* app */, 10585 true /* channel */); 10586 10587 NotificationRecord nr = 10588 generateMessageBubbleNotifRecord(mTestNotificationChannel, "testFlagBubble"); 10589 10590 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10591 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10592 waitForIdle(); 10593 10594 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10595 assertEquals(1, notifs.length); 10596 assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0); 10597 assertTrue(mService.getNotificationRecord( 10598 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10599 } 10600 10601 @Test testFlagBubble_noFlag_appNotAllowed()10602 public void testFlagBubble_noFlag_appNotAllowed() throws RemoteException { 10603 setUpPrefsForBubbles(mPkg, mUid, 10604 true /* global */, 10605 BUBBLE_PREFERENCE_NONE /* app */, 10606 true /* channel */); 10607 10608 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10609 "testFlagBubble_noFlag_appNotAllowed"); 10610 10611 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10612 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10613 waitForIdle(); 10614 10615 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10616 assertEquals(1, notifs.length); 10617 assertEquals((notifs[0].getNotification().flags & FLAG_BUBBLE), 0); 10618 assertFalse(mService.getNotificationRecord( 10619 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10620 } 10621 10622 @Test testFlagBubbleNotifs_noFlag_whenAppForeground()10623 public void testFlagBubbleNotifs_noFlag_whenAppForeground() throws RemoteException { 10624 setUpPrefsForBubbles(mPkg, mUid, 10625 true /* global */, 10626 BUBBLE_PREFERENCE_ALL /* app */, 10627 true /* channel */); 10628 10629 // Notif with bubble metadata but not our other misc requirements 10630 Notification.Builder nb = new Notification.Builder(mContext, 10631 mTestNotificationChannel.getId()) 10632 .setContentTitle("foo") 10633 .setSmallIcon(android.R.drawable.sym_def_app_icon) 10634 .setBubbleMetadata(getBubbleMetadata()); 10635 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 0, 10636 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10637 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10638 10639 // Say we're foreground 10640 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 10641 IMPORTANCE_FOREGROUND); 10642 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10643 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10644 waitForIdle(); 10645 10646 // if notif isn't configured properly it doesn't get to bubble just because app is 10647 // foreground. 10648 assertFalse(mService.getNotificationRecord( 10649 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10650 } 10651 10652 @Test testFlagBubbleNotifs_flag_messaging()10653 public void testFlagBubbleNotifs_flag_messaging() throws RemoteException { 10654 setUpPrefsForBubbles(mPkg, mUid, 10655 true /* global */, 10656 BUBBLE_PREFERENCE_ALL /* app */, 10657 true /* channel */); 10658 10659 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10660 "testFlagBubbleNotifs_flag_messaging"); 10661 10662 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10663 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10664 waitForIdle(); 10665 10666 // yes allowed, yes messaging, yes bubble 10667 assertTrue(mService.getNotificationRecord( 10668 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10669 } 10670 10671 @Test testFlagBubbleNotifs_noFlag_noShortcut()10672 public void testFlagBubbleNotifs_noFlag_noShortcut() throws RemoteException { 10673 setUpPrefsForBubbles(mPkg, mUid, 10674 true /* global */, 10675 BUBBLE_PREFERENCE_ALL /* app */, 10676 true /* channel */); 10677 10678 Notification.Builder nb = getMessageStyleNotifBuilder(true, null, false, true); 10679 nb.setShortcutId(null); 10680 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 10681 null, mUid, 0, 10682 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10683 10684 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 10685 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 10686 waitForIdle(); 10687 10688 // no shortcut no bubble 10689 assertFalse(mService.getNotificationRecord( 10690 sbn.getKey()).getNotification().isBubbleNotification()); 10691 } 10692 10693 @Test testFlagBubbleNotifs_noFlag_messaging_appNotAllowed()10694 public void testFlagBubbleNotifs_noFlag_messaging_appNotAllowed() throws RemoteException { 10695 setUpPrefsForBubbles(mPkg, mUid, 10696 true /* global */, 10697 BUBBLE_PREFERENCE_NONE /* app */, 10698 true /* channel */); 10699 10700 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10701 "testFlagBubbleNotifs_noFlag_messaging_appNotAllowed"); 10702 10703 // Post the notification 10704 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10705 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10706 waitForIdle(); 10707 10708 // not allowed, no bubble 10709 assertFalse(mService.getNotificationRecord( 10710 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10711 } 10712 10713 @Test testFlagBubbleNotifs_noFlag_notBubble()10714 public void testFlagBubbleNotifs_noFlag_notBubble() throws RemoteException { 10715 setUpPrefsForBubbles(mPkg, mUid, 10716 true /* global */, 10717 BUBBLE_PREFERENCE_ALL /* app */, 10718 true /* channel */); 10719 10720 // Messaging notif WITHOUT bubble metadata 10721 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addBubbleMetadata */, 10722 null /* groupKey */, false /* isSummary */, true); 10723 10724 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 10725 "testFlagBubbleNotifs_noFlag_notBubble", mUid, 0, 10726 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 10727 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 10728 10729 // Post the notification 10730 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10731 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10732 waitForIdle(); 10733 10734 // no bubble metadata, no bubble 10735 assertFalse(mService.getNotificationRecord( 10736 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10737 } 10738 10739 @Test testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed()10740 public void testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed() throws RemoteException { 10741 setUpPrefsForBubbles(mPkg, mUid, 10742 true /* global */, 10743 BUBBLE_PREFERENCE_ALL /* app */, 10744 false /* channel */); 10745 10746 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 10747 "testFlagBubbleNotifs_noFlag_messaging_channelNotAllowed"); 10748 nr.getChannel().lockFields(USER_LOCKED_ALLOW_BUBBLE); 10749 10750 // Post the notification 10751 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10752 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10753 waitForIdle(); 10754 10755 // channel not allowed, no bubble 10756 assertFalse(mService.getNotificationRecord( 10757 nr.getSbn().getKey()).getNotification().isBubbleNotification()); 10758 } 10759 10760 @Test testCancelNotificationsFromApp_cancelsBubbles()10761 public void testCancelNotificationsFromApp_cancelsBubbles() throws Exception { 10762 final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel); 10763 nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE; 10764 10765 // Post the notification 10766 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 10767 "testAppCancelNotifications_cancelsBubbles", 10768 nrBubble.getSbn().getId(), nrBubble.getSbn().getNotification(), 10769 nrBubble.getSbn().getUserId()); 10770 waitForIdle(); 10771 10772 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10773 assertEquals(1, notifs.length); 10774 assertEquals(1, mService.getNotificationRecordCount()); 10775 10776 mBinderService.cancelNotificationWithTag(mPkg, mPkg, 10777 "testAppCancelNotifications_cancelsBubbles", nrBubble.getSbn().getId(), 10778 nrBubble.getSbn().getUserId()); 10779 waitForIdle(); 10780 10781 StatusBarNotification[] notifs2 = mBinderService.getActiveNotifications(mPkg); 10782 assertEquals(0, notifs2.length); 10783 assertEquals(0, mService.getNotificationRecordCount()); 10784 } 10785 10786 @Test testCancelAllNotificationsFromApp_cancelsBubble()10787 public void testCancelAllNotificationsFromApp_cancelsBubble() throws Exception { 10788 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10789 nr.getSbn().getNotification().flags |= FLAG_BUBBLE; 10790 mService.addNotification(nr); 10791 10792 mBinderService.cancelAllNotifications(mPkg, nr.getSbn().getUserId()); 10793 waitForIdle(); 10794 10795 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10796 assertEquals(0, notifs.length); 10797 assertEquals(0, mService.getNotificationRecordCount()); 10798 } 10799 10800 @Test testCancelAllNotificationsFromListener_ignoresBubbles()10801 public void testCancelAllNotificationsFromListener_ignoresBubbles() throws Exception { 10802 final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel); 10803 final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel); 10804 nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE; 10805 10806 mService.addNotification(nrNormal); 10807 mService.addNotification(nrBubble); 10808 10809 mService.getBinderService().cancelNotificationsFromListener(null, null); 10810 waitForIdle(); 10811 10812 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10813 assertEquals(1, notifs.length); 10814 assertEquals(1, mService.getNotificationRecordCount()); 10815 } 10816 10817 @Test testCancelNotificationsFromListener_cancelsNonBubble()10818 public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception { 10819 // Add non-bubble notif 10820 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10821 mService.addNotification(nr); 10822 10823 // Cancel via listener 10824 String[] keys = {nr.getSbn().getKey()}; 10825 mService.getBinderService().cancelNotificationsFromListener(null, keys); 10826 waitForIdle(); 10827 10828 // Notif not active anymore 10829 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10830 assertEquals(0, notifs.length); 10831 assertEquals(0, mService.getNotificationRecordCount()); 10832 // Cancel event is logged 10833 assertEquals(1, mNotificationRecordLogger.numCalls()); 10834 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 10835 .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0)); 10836 } 10837 10838 @Test testCancelNotificationsFromListener_suppressesBubble()10839 public void testCancelNotificationsFromListener_suppressesBubble() throws Exception { 10840 // Add bubble notif 10841 setUpPrefsForBubbles(mPkg, mUid, 10842 true /* global */, 10843 BUBBLE_PREFERENCE_ALL /* app */, 10844 true /* channel */); 10845 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 10846 10847 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 10848 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 10849 waitForIdle(); 10850 10851 // Cancel via listener 10852 String[] keys = {nr.getSbn().getKey()}; 10853 mService.getBinderService().cancelNotificationsFromListener(null, keys); 10854 waitForIdle(); 10855 10856 // Bubble notif active and suppressed 10857 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10858 assertEquals(1, notifs.length); 10859 assertEquals(1, mService.getNotificationRecordCount()); 10860 assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed()); 10861 } 10862 10863 @Test testCancelAllNotificationsFromStatusBar_ignoresBubble()10864 public void testCancelAllNotificationsFromStatusBar_ignoresBubble() throws Exception { 10865 // GIVEN a notification bubble 10866 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 10867 nr.getSbn().getNotification().flags |= FLAG_BUBBLE; 10868 mService.addNotification(nr); 10869 10870 // WHEN the status bar clears all notifications 10871 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 10872 nr.getSbn().getUserId()); 10873 waitForIdle(); 10874 10875 // THEN the bubble notification does not get removed 10876 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 10877 assertEquals(1, notifs.length); 10878 assertEquals(1, mService.getNotificationRecordCount()); 10879 } 10880 10881 10882 @Test testGetAllowedAssistantAdjustments()10883 public void testGetAllowedAssistantAdjustments() throws Exception { 10884 List<String> adjustments = mBinderService.getAllowedAssistantAdjustments(null); 10885 assertNotNull(adjustments); 10886 } 10887 10888 @Test testAdjustRestrictedKey()10889 public void testAdjustRestrictedKey() throws Exception { 10890 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 10891 mService.addNotification(r); 10892 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 10893 10894 when(mAssistants.isAdjustmentAllowed(KEY_IMPORTANCE)).thenReturn(true); 10895 when(mAssistants.isAdjustmentAllowed(KEY_USER_SENTIMENT)).thenReturn(false); 10896 10897 Bundle signals = new Bundle(); 10898 signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW); 10899 signals.putInt(KEY_USER_SENTIMENT, USER_SENTIMENT_NEGATIVE); 10900 signals.putInt(KEY_TYPE, TYPE_PROMOTION); 10901 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 10902 "", r.getUser().getIdentifier()); 10903 10904 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 10905 r.applyAdjustments(); 10906 10907 assertEquals(IMPORTANCE_LOW, r.getAssistantImportance()); 10908 assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment()); 10909 } 10910 10911 @Test testAutomaticZenRuleValidation_policyFilterAgreement()10912 public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception { 10913 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10914 .thenReturn(true); 10915 mService.setZenHelper(mock(ZenModeHelper.class)); 10916 ComponentName owner = new ComponentName(mContext, this.getClass()); 10917 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10918 boolean isEnabled = true; 10919 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10920 zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); 10921 10922 try { 10923 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 10924 fail("Zen policy only applies to priority only mode"); 10925 } catch (IllegalArgumentException e) { 10926 // yay 10927 } 10928 10929 rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10930 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10931 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 10932 10933 rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10934 null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled); 10935 mBinderService.addAutomaticZenRule(rule, mContext.getPackageName(), false); 10936 } 10937 10938 @Test testAddAutomaticZenRule_systemCallTakesPackageFromOwner()10939 public void testAddAutomaticZenRule_systemCallTakesPackageFromOwner() throws Exception { 10940 mService.isSystemUid = true; 10941 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 10942 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10943 .thenReturn(true); 10944 mService.setZenHelper(mockZenModeHelper); 10945 ComponentName owner = new ComponentName("android", "ProviderName"); 10946 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10947 boolean isEnabled = true; 10948 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10949 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10950 mBinderService.addAutomaticZenRule(rule, "com.android.settings", false); 10951 10952 // verify that zen mode helper gets passed in a package name of "android" 10953 verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule), 10954 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt()); 10955 } 10956 10957 @Test testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner()10958 public void testAddAutomaticZenRule_systemAppIdCallTakesPackageFromOwner() throws Exception { 10959 // The multi-user case: where the calling uid doesn't match the system uid, but the calling 10960 // *appid* is the system. 10961 mService.isSystemUid = false; 10962 mService.isSystemAppId = true; 10963 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 10964 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10965 .thenReturn(true); 10966 mService.setZenHelper(mockZenModeHelper); 10967 ComponentName owner = new ComponentName("android", "ProviderName"); 10968 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10969 boolean isEnabled = true; 10970 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10971 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10972 mBinderService.addAutomaticZenRule(rule, "com.android.settings", false); 10973 10974 // verify that zen mode helper gets passed in a package name of "android" 10975 verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("android"), eq(rule), 10976 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt()); 10977 } 10978 10979 @Test testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg()10980 public void testAddAutomaticZenRule_nonSystemCallTakesPackageFromArg() throws Exception { 10981 mService.isSystemUid = false; 10982 mService.isSystemAppId = false; 10983 ZenModeHelper mockZenModeHelper = mock(ZenModeHelper.class); 10984 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 10985 .thenReturn(true); 10986 mService.setZenHelper(mockZenModeHelper); 10987 ComponentName owner = new ComponentName("android", "ProviderName"); 10988 ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build(); 10989 boolean isEnabled = true; 10990 AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class), 10991 zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled); 10992 mBinderService.addAutomaticZenRule(rule, "another.package", false); 10993 10994 // verify that zen mode helper gets passed in the package name from the arg, not the owner 10995 verify(mockZenModeHelper).addAutomaticZenRule(any(), eq("another.package"), eq(rule), 10996 eq(ZenModeConfig.ORIGIN_APP), anyString(), 10997 anyInt()); // doesn't count as a system/systemui call 10998 } 10999 11000 @Test testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners()11001 public void testAddAutomaticZenRule_typeManagedCanBeUsedByDeviceOwners() throws Exception { 11002 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11003 mService.setCallerIsNormalPackage(); 11004 11005 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 11006 .setType(AutomaticZenRule.TYPE_MANAGED) 11007 .setOwner(new ComponentName(mPkg, "cls")) 11008 .build(); 11009 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); 11010 11011 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 11012 11013 verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(), 11014 anyInt()); 11015 } 11016 11017 @Test testAddAutomaticZenRule_typeManagedCanBeUsedBySystem()11018 public void testAddAutomaticZenRule_typeManagedCanBeUsedBySystem() throws Exception { 11019 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_MANAGED); 11020 } 11021 11022 @Test testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps()11023 public void testAddAutomaticZenRule_typeManagedCannotBeUsedByRegularApps() throws Exception { 11024 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 11025 AutomaticZenRule.TYPE_MANAGED); 11026 } 11027 11028 @Test testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing()11029 public void testAddAutomaticZenRule_typeBedtimeCanBeUsedByWellbeing() throws Exception { 11030 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11031 mService.setCallerIsNormalPackage(); 11032 reset(mPackageManagerInternal); 11033 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 11034 when(mResources 11035 .getString(com.android.internal.R.string.config_systemWellbeing)) 11036 .thenReturn(mPkg); 11037 when(mContext.getResources()).thenReturn(mResources); 11038 11039 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 11040 .setType(AutomaticZenRule.TYPE_BEDTIME) 11041 .setOwner(new ComponentName(mPkg, "cls")) 11042 .build(); 11043 11044 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 11045 11046 verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(), 11047 anyInt()); 11048 } 11049 11050 @Test testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem()11051 public void testAddAutomaticZenRule_typeBedtimeCanBeUsedBySystem() throws Exception { 11052 reset(mPackageManagerInternal); 11053 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 11054 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem(AutomaticZenRule.TYPE_BEDTIME); 11055 } 11056 11057 @Test testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps()11058 public void testAddAutomaticZenRule_typeBedtimeCannotBeUsedByRegularApps() throws Exception { 11059 reset(mPackageManagerInternal); 11060 when(mPackageManagerInternal.isSameApp(eq(mPkg), eq(mUid), anyInt())).thenReturn(true); 11061 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 11062 AutomaticZenRule.TYPE_BEDTIME); 11063 } 11064 addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( @utomaticZenRule.Type int ruleType)11065 private void addAutomaticZenRule_restrictedRuleTypeCanBeUsedBySystem( 11066 @AutomaticZenRule.Type int ruleType) throws Exception { 11067 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11068 mService.isSystemUid = true; 11069 11070 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 11071 .setType(ruleType) 11072 .setOwner(new ComponentName(mPkg, "cls")) 11073 .build(); 11074 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(true); 11075 11076 mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false); 11077 11078 verify(zenModeHelper).addAutomaticZenRule(any(), eq(mPkg), eq(rule), anyInt(), any(), 11079 anyInt()); 11080 } 11081 addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( @utomaticZenRule.Type int ruleType)11082 private void addAutomaticZenRule_restrictedRuleTypeCannotBeUsedByRegularApps( 11083 @AutomaticZenRule.Type int ruleType) { 11084 mService.setCallerIsNormalPackage(); 11085 mService.setZenHelper(mock(ZenModeHelper.class)); 11086 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 11087 .thenReturn(true); 11088 11089 AutomaticZenRule rule = new AutomaticZenRule.Builder("rule", Uri.parse("uri")) 11090 .setType(ruleType) 11091 .setOwner(new ComponentName(mPkg, "cls")) 11092 .build(); 11093 when(mDevicePolicyManager.isActiveDeviceOwner(anyInt())).thenReturn(false); 11094 11095 assertThrows(IllegalArgumentException.class, 11096 () -> mBinderService.addAutomaticZenRule(rule, mPkg, /* fromUser= */ false)); 11097 } 11098 11099 @Test addAutomaticZenRule_fromUser_mappedToOriginUser()11100 public void addAutomaticZenRule_fromUser_mappedToOriginUser() throws Exception { 11101 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11102 mService.isSystemUid = true; 11103 11104 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true); 11105 11106 verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE), 11107 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt()); 11108 } 11109 11110 @Test addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem()11111 public void addAutomaticZenRule_fromSystemNotUser_mappedToOriginSystem() throws Exception { 11112 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11113 mService.isSystemUid = true; 11114 11115 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false); 11116 11117 verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE), 11118 eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), anyInt()); 11119 } 11120 11121 @Test addAutomaticZenRule_fromApp_mappedToOriginApp()11122 public void addAutomaticZenRule_fromApp_mappedToOriginApp() throws Exception { 11123 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11124 mService.setCallerIsNormalPackage(); 11125 11126 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ false); 11127 11128 verify(zenModeHelper).addAutomaticZenRule(any(), eq("pkg"), eq(SOME_ZEN_RULE), 11129 eq(ZenModeConfig.ORIGIN_APP), anyString(), anyInt()); 11130 } 11131 11132 @Test addAutomaticZenRule_fromAppFromUser_blocked()11133 public void addAutomaticZenRule_fromAppFromUser_blocked() throws Exception { 11134 setUpMockZenTest(); 11135 mService.setCallerIsNormalPackage(); 11136 11137 assertThrows(SecurityException.class, () -> 11138 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true)); 11139 } 11140 11141 @Test updateAutomaticZenRule_fromUserFromSystem_allowed()11142 public void updateAutomaticZenRule_fromUserFromSystem_allowed() throws Exception { 11143 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11144 mService.isSystemUid = true; 11145 11146 mBinderService.updateAutomaticZenRule("id", SOME_ZEN_RULE, /* fromUser= */ true); 11147 11148 verify(zenModeHelper).updateAutomaticZenRule(any(), eq("id"), eq(SOME_ZEN_RULE), 11149 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt()); 11150 } 11151 11152 @Test updateAutomaticZenRule_fromUserFromApp_blocked()11153 public void updateAutomaticZenRule_fromUserFromApp_blocked() throws Exception { 11154 setUpMockZenTest(); 11155 mService.setCallerIsNormalPackage(); 11156 11157 assertThrows(SecurityException.class, () -> 11158 mBinderService.addAutomaticZenRule(SOME_ZEN_RULE, "pkg", /* fromUser= */ true)); 11159 } 11160 11161 @Test removeAutomaticZenRule_fromUserFromSystem_allowed()11162 public void removeAutomaticZenRule_fromUserFromSystem_allowed() throws Exception { 11163 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11164 mService.isSystemUid = true; 11165 11166 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true); 11167 11168 verify(zenModeHelper).removeAutomaticZenRule(any(), eq("id"), 11169 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyString(), anyInt()); 11170 } 11171 11172 @Test removeAutomaticZenRule_fromUserFromApp_blocked()11173 public void removeAutomaticZenRule_fromUserFromApp_blocked() throws Exception { 11174 setUpMockZenTest(); 11175 mService.setCallerIsNormalPackage(); 11176 11177 assertThrows(SecurityException.class, () -> 11178 mBinderService.removeAutomaticZenRule("id", /* fromUser= */ true)); 11179 } 11180 11181 @Test setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp()11182 public void setAutomaticZenRuleState_fromAppWithConditionFromUser_originUserInApp() 11183 throws Exception { 11184 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11185 mService.setCallerIsNormalPackage(); 11186 11187 Condition withSourceUser = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11188 SOURCE_USER_ACTION); 11189 mBinderService.setAutomaticZenRuleState("id", withSourceUser); 11190 11191 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceUser), 11192 eq(ZenModeConfig.ORIGIN_USER_IN_APP), anyInt()); 11193 } 11194 11195 @Test setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp()11196 public void setAutomaticZenRuleState_fromAppWithConditionNotFromUser_originApp() 11197 throws Exception { 11198 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11199 mService.setCallerIsNormalPackage(); 11200 11201 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11202 SOURCE_CONTEXT); 11203 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 11204 11205 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext), 11206 eq(ZenModeConfig.ORIGIN_APP), anyInt()); 11207 } 11208 11209 @Test setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi()11210 public void setAutomaticZenRuleState_fromSystemWithConditionFromUser_originUserInSystemUi() 11211 throws Exception { 11212 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11213 mService.isSystemUid = true; 11214 11215 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11216 SOURCE_USER_ACTION); 11217 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 11218 11219 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext), 11220 eq(ZenModeConfig.ORIGIN_USER_IN_SYSTEMUI), anyInt()); 11221 } 11222 @Test setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem()11223 public void setAutomaticZenRuleState_fromSystemWithConditionNotFromUser_originSystem() 11224 throws Exception { 11225 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11226 mService.isSystemUid = true; 11227 11228 Condition withSourceContext = new Condition(Uri.parse("uri"), "summary", STATE_TRUE, 11229 SOURCE_CONTEXT); 11230 mBinderService.setAutomaticZenRuleState("id", withSourceContext); 11231 11232 verify(zenModeHelper).setAutomaticZenRuleState(any(), eq("id"), eq(withSourceContext), 11233 eq(ZenModeConfig.ORIGIN_SYSTEM), anyInt()); 11234 } 11235 11236 11237 @Test 11238 @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER) getAutomaticZenRules_fromSystem_readsWithCurrentUser()11239 public void getAutomaticZenRules_fromSystem_readsWithCurrentUser() throws Exception { 11240 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11241 mService.isSystemUid = true; 11242 11243 // Representative used to verify getCallingZenUser(). 11244 mBinderService.getAutomaticZenRules(); 11245 11246 verify(zenModeHelper).getAutomaticZenRules(eq(UserHandle.CURRENT), anyInt()); 11247 } 11248 11249 @Test 11250 @EnableFlags(android.app.Flags.FLAG_MODES_MULTIUSER) getAutomaticZenRules_fromNormalPackage_readsWithBinderUser()11251 public void getAutomaticZenRules_fromNormalPackage_readsWithBinderUser() throws Exception { 11252 ZenModeHelper zenModeHelper = setUpMockZenTest(); 11253 mService.setCallerIsNormalPackage(); 11254 11255 // Representative used to verify getCallingZenUser(). 11256 mBinderService.getAutomaticZenRules(); 11257 11258 verify(zenModeHelper).getAutomaticZenRules(eq(Binder.getCallingUserHandle()), anyInt()); 11259 } 11260 11261 /** Prepares for a zen-related test that uses a mocked {@link ZenModeHelper}. */ setUpMockZenTest()11262 private ZenModeHelper setUpMockZenTest() { 11263 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 11264 mService.setZenHelper(zenModeHelper); 11265 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 11266 .thenReturn(true); 11267 return zenModeHelper; 11268 } 11269 11270 @Test 11271 @DisableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS) onZenModeChanged_sendsBroadcasts_oldBehavior()11272 public void onZenModeChanged_sendsBroadcasts_oldBehavior() throws Exception { 11273 when(mAmi.getCurrentUserId()).thenReturn(100); 11274 when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102}); 11275 when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() { 11276 @Override 11277 public List<String> answer(InvocationOnMock invocation) { 11278 int userId = invocation.getArgument(0); 11279 switch (userId) { 11280 case 100: 11281 return Lists.newArrayList("a", "b", "c"); 11282 case 101: 11283 return Lists.newArrayList(); 11284 case 102: 11285 return Lists.newArrayList("b"); 11286 default: 11287 throw new IllegalArgumentException( 11288 "Why would you ask for packages of userId " + userId + "?"); 11289 } 11290 } 11291 }); 11292 11293 mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null, 11294 "testing!", false); 11295 waitForIdle(); 11296 11297 InOrder inOrder = inOrder(mContext); 11298 // Verify broadcasts for registered receivers 11299 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 11300 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 11301 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(100)), eq(null)); 11302 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 11303 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 11304 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(101)), eq(null)); 11305 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent( 11306 new Intent(ACTION_INTERRUPTION_FILTER_CHANGED).setFlags( 11307 Intent.FLAG_RECEIVER_REGISTERED_ONLY)), eq(UserHandle.of(102)), eq(null)); 11308 11309 // Verify broadcast for packages that manage DND. 11310 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11311 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("a").setFlags( 11312 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 11313 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11314 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( 11315 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 11316 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11317 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("c").setFlags( 11318 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(100))); 11319 inOrder.verify(mContext).sendBroadcastAsUser(eqIntent(new Intent( 11320 ACTION_INTERRUPTION_FILTER_CHANGED).setPackage("b").setFlags( 11321 Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT)), eq(UserHandle.of(102))); 11322 } 11323 11324 @Test 11325 @EnableFlags(Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS) onZenModeChanged_sendsBroadcasts()11326 public void onZenModeChanged_sendsBroadcasts() throws Exception { 11327 when(mAmi.getCurrentUserId()).thenReturn(100); 11328 when(mUmInternal.getProfileIds(eq(100), anyBoolean())).thenReturn(new int[]{100, 101, 102}); 11329 when(mConditionProviders.getAllowedPackages(anyInt())).then(new Answer<List<String>>() { 11330 @Override 11331 public List<String> answer(InvocationOnMock invocation) { 11332 int userId = invocation.getArgument(0); 11333 switch (userId) { 11334 case 100: 11335 return Lists.newArrayList("a", "b", "c"); 11336 case 101: 11337 return Lists.newArrayList(); 11338 case 102: 11339 return Lists.newArrayList("b"); 11340 default: 11341 throw new IllegalArgumentException( 11342 "Why would you ask for packages of userId " + userId + "?"); 11343 } 11344 } 11345 }); 11346 Context context100 = mock(Context.class); 11347 doReturn(context100).when(mContext).createContextAsUser(eq(UserHandle.of(100)), anyInt()); 11348 Context context101 = mock(Context.class); 11349 doReturn(context101).when(mContext).createContextAsUser(eq(UserHandle.of(101)), anyInt()); 11350 Context context102 = mock(Context.class); 11351 doReturn(context102).when(mContext).createContextAsUser(eq(UserHandle.of(102)), anyInt()); 11352 11353 mService.getBinderService().setZenMode(Settings.Global.ZEN_MODE_NO_INTERRUPTIONS, null, 11354 "testing!", false); 11355 waitForIdle(); 11356 11357 // Verify broadcasts per user: registered receivers first, then DND packages. 11358 InOrder inOrder = inOrder(context100, context101, context102); 11359 11360 inOrder.verify(context100).sendBroadcastMultiplePermissions( 11361 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) 11362 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)), 11363 eq(new String[0]), eq(new String[0]), eq(new String[] {"a", "b", "c"})); 11364 inOrder.verify(context100).sendBroadcast( 11365 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) 11366 .setPackage("a") 11367 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); 11368 inOrder.verify(context100).sendBroadcast( 11369 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) 11370 .setPackage("b") 11371 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); 11372 inOrder.verify(context100).sendBroadcast( 11373 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) 11374 .setPackage("c") 11375 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); 11376 11377 inOrder.verify(context101).sendBroadcastMultiplePermissions( 11378 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) 11379 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)), 11380 eq(new String[0]), eq(new String[0]), eq(new String[] {})); 11381 11382 inOrder.verify(context102).sendBroadcastMultiplePermissions( 11383 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) 11384 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)), 11385 eq(new String[0]), eq(new String[0]), eq(new String[] {"b"})); 11386 inOrder.verify(context102).sendBroadcast( 11387 eqIntent(new Intent(ACTION_INTERRUPTION_FILTER_CHANGED) 11388 .setPackage("b") 11389 .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT))); 11390 } 11391 11392 @Test onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner()11393 public void onAutomaticRuleStatusChanged_sendsBroadcastToRuleOwner() throws Exception { 11394 mService.mZenModeHelper.getCallbacks().forEach(c -> c.onAutomaticRuleStatusChanged( 11395 mUserId, "rule.owner.pkg", "rule_id", AUTOMATIC_RULE_STATUS_ACTIVATED)); 11396 11397 Intent expected = new Intent(ACTION_AUTOMATIC_ZEN_RULE_STATUS_CHANGED) 11398 .setPackage("rule.owner.pkg") 11399 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_ID, "rule_id") 11400 .putExtra(EXTRA_AUTOMATIC_ZEN_RULE_STATUS, AUTOMATIC_RULE_STATUS_ACTIVATED) 11401 .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); 11402 11403 verify(mContext).sendBroadcastAsUser(eqIntent(expected), eq(UserHandle.of(mUserId))); 11404 } 11405 isIntentWithAction(String wantedAction)11406 private static Intent isIntentWithAction(String wantedAction) { 11407 return argThat( 11408 intent -> intent != null && wantedAction.equals(intent.getAction()) 11409 ); 11410 } 11411 eqIntent(Intent wanted)11412 private static Intent eqIntent(Intent wanted) { 11413 return argThat( 11414 new ArgumentMatcher<Intent>() { 11415 @Override 11416 public boolean matches(Intent argument) { 11417 return wanted.filterEquals(argument) 11418 && wanted.getFlags() == argument.getFlags() 11419 && equalBundles(wanted.getExtras(), argument.getExtras()); 11420 } 11421 11422 @Override 11423 public String toString() { 11424 return wanted.toString(); 11425 } 11426 11427 private boolean equalBundles(Bundle one, Bundle two) { 11428 if (one == null && two == null) { 11429 return true; 11430 } 11431 if ((one == null) != (two == null)) { 11432 return false; 11433 } 11434 if (one.size() != two.size()) { 11435 return false; 11436 } 11437 11438 HashSet<String> setOne = new HashSet<>(one.keySet()); 11439 setOne.addAll(two.keySet()); 11440 11441 for (String key : setOne) { 11442 if (!one.containsKey(key) || !two.containsKey(key)) { 11443 return false; 11444 } 11445 11446 Object valueOne = one.get(key); 11447 Object valueTwo = two.get(key); 11448 if (valueOne instanceof Bundle 11449 && valueTwo instanceof Bundle 11450 && !equalBundles((Bundle) valueOne, (Bundle) valueTwo)) { 11451 return false; 11452 } else if (valueOne == null) { 11453 if (valueTwo != null) { 11454 return false; 11455 } 11456 } else if (!valueOne.equals(valueTwo)) { 11457 return false; 11458 } 11459 } 11460 return true; 11461 } 11462 }); 11463 } 11464 11465 @Test 11466 public void testAreNotificationsEnabledForPackage() throws Exception { 11467 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 11468 mUid); 11469 11470 verify(mPermissionHelper).hasPermission(mUid); 11471 } 11472 11473 @Test 11474 public void testAreNotificationsEnabledForPackage_crossUser() throws Exception { 11475 try { 11476 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 11477 mUid + UserHandle.PER_USER_RANGE); 11478 fail("Cannot call cross user without permission"); 11479 } catch (SecurityException e) { 11480 // pass 11481 } 11482 verify(mPermissionHelper, never()).hasPermission(anyInt()); 11483 11484 // cross user, with permission, no problem 11485 enableInteractAcrossUsers(); 11486 mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(), 11487 mUid + UserHandle.PER_USER_RANGE); 11488 11489 verify(mPermissionHelper).hasPermission(mUid + UserHandle.PER_USER_RANGE); 11490 } 11491 11492 @Test 11493 public void testAreNotificationsEnabledForPackage_viaInternalService() { 11494 mInternalService.areNotificationsEnabledForPackage(mContext.getPackageName(), mUid); 11495 verify(mPermissionHelper).hasPermission(mUid); 11496 } 11497 11498 @Test 11499 public void testGetPackageImportance() throws Exception { 11500 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 11501 assertThat(mBinderService.getPackageImportance(mContext.getPackageName())) 11502 .isEqualTo(IMPORTANCE_DEFAULT); 11503 11504 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 11505 assertThat(mBinderService.getPackageImportance(mContext.getPackageName())) 11506 .isEqualTo(IMPORTANCE_NONE); 11507 } 11508 11509 @Test 11510 public void testAreBubblesAllowedForPackage_crossUser() throws Exception { 11511 try { 11512 mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), 11513 mUid + UserHandle.PER_USER_RANGE); 11514 fail("Cannot call cross user without permission"); 11515 } catch (SecurityException e) { 11516 // pass 11517 } 11518 11519 // cross user, with permission, no problem 11520 enableInteractAcrossUsers(); 11521 mBinderService.getBubblePreferenceForPackage(mContext.getPackageName(), 11522 mUid + UserHandle.PER_USER_RANGE); 11523 } 11524 11525 private void enableInteractAcrossUsers() { 11526 TestablePermissions perms = mContext.getTestablePermissions(); 11527 perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED); 11528 } 11529 11530 @Test 11531 public void testNotificationBubbleChanged_false() throws Exception { 11532 setUpPrefsForBubbles(mPkg, mUid, 11533 true /* global */, 11534 BUBBLE_PREFERENCE_ALL /* app */, 11535 true /* channel */); 11536 11537 // Notif with bubble metadata 11538 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11539 "testNotificationBubbleChanged_false"); 11540 11541 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11542 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11543 waitForIdle(); 11544 11545 // Reset as this is called when the notif is first sent 11546 reset(mListeners); 11547 11548 // First we were a bubble 11549 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11550 assertEquals(1, notifsBefore.length); 11551 assertTrue((notifsBefore[0].getNotification().flags & FLAG_BUBBLE) != 0); 11552 11553 // Notify we're not a bubble 11554 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 11555 waitForIdle(); 11556 11557 // Make sure we are not a bubble 11558 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11559 assertEquals(1, notifsAfter.length); 11560 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 11561 } 11562 11563 @Test 11564 public void testNotificationBubbleChanged_true() throws Exception { 11565 setUpPrefsForBubbles(mPkg, mUid, 11566 true /* global */, 11567 BUBBLE_PREFERENCE_ALL /* app */, 11568 true /* channel */); 11569 11570 // Notif that is not a bubble 11571 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 11572 1, null, false); 11573 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11574 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11575 waitForIdle(); 11576 11577 // Would be a normal notification because wouldn't have met requirements to bubble 11578 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11579 assertEquals(1, notifsBefore.length); 11580 assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0); 11581 11582 // Update the notification to be message style / meet bubble requirements 11583 NotificationRecord nr2 = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11584 nr.getSbn().getTag()); 11585 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr2.getSbn().getTag(), 11586 nr2.getSbn().getId(), nr2.getSbn().getNotification(), nr2.getSbn().getUserId()); 11587 waitForIdle(); 11588 11589 // Reset as this is called when the notif is first sent 11590 reset(mListeners); 11591 11592 // Notify we are now a bubble 11593 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 11594 waitForIdle(); 11595 11596 // Make sure we are a bubble 11597 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11598 assertEquals(1, notifsAfter.length); 11599 assertTrue((notifsAfter[0].getNotification().flags & FLAG_BUBBLE) != 0); 11600 } 11601 11602 @Test 11603 public void testNotificationBubbleChanged_true_notAllowed() throws Exception { 11604 setUpPrefsForBubbles(mPkg, mUid, 11605 true /* global */, 11606 BUBBLE_PREFERENCE_ALL /* app */, 11607 true /* channel */); 11608 11609 // Notif that is not a bubble 11610 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 11611 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11612 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11613 waitForIdle(); 11614 11615 // Reset as this is called when the notif is first sent 11616 reset(mListeners); 11617 11618 // Would be a normal notification because wouldn't have met requirements to bubble 11619 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11620 assertEquals(1, notifsBefore.length); 11621 assertEquals((notifsBefore[0].getNotification().flags & FLAG_BUBBLE), 0); 11622 11623 // Notify we are now a bubble 11624 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 11625 waitForIdle(); 11626 11627 // We still wouldn't be a bubble because the notification didn't meet requirements 11628 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11629 assertEquals(1, notifsAfter.length); 11630 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 11631 } 11632 11633 @Test 11634 public void testNotificationBubbleIsFlagRemoved_resetOnUpdate() throws Exception { 11635 setUpPrefsForBubbles(mPkg, mUid, 11636 true /* global */, 11637 BUBBLE_PREFERENCE_ALL /* app */, 11638 true /* channel */); 11639 11640 // Notif with bubble metadata 11641 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11642 "testNotificationBubbleIsFlagRemoved_resetOnUpdate"); 11643 11644 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11645 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11646 waitForIdle(); 11647 // Flag shouldn't be modified 11648 NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11649 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11650 11651 // Notify we're not a bubble 11652 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 11653 waitForIdle(); 11654 // Flag should be modified 11655 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11656 assertTrue(recordToCheck.isFlagBubbleRemoved()); 11657 11658 11659 // Update the notif 11660 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11661 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11662 waitForIdle(); 11663 // And the flag is reset 11664 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11665 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11666 } 11667 11668 @Test 11669 public void testNotificationBubbleIsFlagRemoved_resetOnBubbleChangedTrue() throws Exception { 11670 setUpPrefsForBubbles(mPkg, mUid, 11671 true /* global */, 11672 BUBBLE_PREFERENCE_ALL /* app */, 11673 true /* channel */); 11674 11675 // Notif with bubble metadata 11676 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11677 "testNotificationBubbleIsFlagRemoved_trueOnBubbleChangedTrue"); 11678 11679 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11680 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11681 waitForIdle(); 11682 // Flag shouldn't be modified 11683 NotificationRecord recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11684 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11685 11686 // Notify we're not a bubble 11687 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), false, 0); 11688 waitForIdle(); 11689 // Flag should be modified 11690 recordToCheck = mService.getNotificationRecord(nr.getSbn().getKey()); 11691 assertTrue(recordToCheck.isFlagBubbleRemoved()); 11692 11693 // Notify we are a bubble 11694 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), true, 0); 11695 waitForIdle(); 11696 // And the flag is reset 11697 assertFalse(recordToCheck.isFlagBubbleRemoved()); 11698 } 11699 11700 @Test 11701 public void testOnBubbleMetadataFlagChanged() throws Exception { 11702 setUpPrefsForBubbles(mPkg, mUid, 11703 true /* global */, 11704 BUBBLE_PREFERENCE_ALL /* app */, 11705 true /* channel */); 11706 11707 // Post a bubble notification 11708 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 11709 // Set this so that the bubble can be suppressed 11710 nr.getNotification().getBubbleMetadata().setFlags( 11711 Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE); 11712 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11713 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11714 waitForIdle(); 11715 11716 // Check the flags 11717 Notification n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 11718 assertFalse(n.getBubbleMetadata().isNotificationSuppressed()); 11719 assertFalse(n.getBubbleMetadata().getAutoExpandBubble()); 11720 assertFalse(n.getBubbleMetadata().isBubbleSuppressed()); 11721 assertTrue(n.getBubbleMetadata().isBubbleSuppressable()); 11722 11723 // Reset as this is called when the notif is first sent 11724 reset(mListeners); 11725 11726 // Test: change the flags 11727 int flags = Notification.BubbleMetadata.FLAG_SUPPRESSABLE_BUBBLE; 11728 flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; 11729 flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; 11730 flags |= Notification.BubbleMetadata.FLAG_SUPPRESS_BUBBLE; 11731 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), flags); 11732 waitForIdle(); 11733 11734 // Check 11735 n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 11736 assertEquals(flags, n.getBubbleMetadata().getFlags()); 11737 11738 // Reset to check again 11739 reset(mListeners); 11740 11741 // Test: clear flags 11742 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 0); 11743 waitForIdle(); 11744 11745 // Check 11746 n = mBinderService.getActiveNotifications(mPkg)[0].getNotification(); 11747 assertEquals(0, n.getBubbleMetadata().getFlags()); 11748 } 11749 11750 @Test 11751 public void testOnBubbleMetadataChangedToSuppressNotification_soundStopped() 11752 throws RemoteException { 11753 11754 setUpPrefsForBubbles(mPkg, mUid, 11755 true /* global */, 11756 BUBBLE_PREFERENCE_ALL /* app */, 11757 true /* channel */); 11758 11759 // Post a bubble notification 11760 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); 11761 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11762 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11763 waitForIdle(); 11764 11765 // Test: suppress notification via bubble metadata update 11766 mService.mNotificationDelegate.onBubbleMetadataFlagChanged(nr.getKey(), 11767 Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 11768 waitForIdle(); 11769 11770 // Check audio is stopped 11771 verify(mAttentionHelper).clearEffectsLocked(nr.getKey()); 11772 } 11773 11774 @Test 11775 public void testGrantInlineReplyUriPermission_recordExists() throws Exception { 11776 int userId = UserManager.isHeadlessSystemUserMode() 11777 ? UserHandle.getUserId(UID_HEADLESS) 11778 : USER_SYSTEM; 11779 11780 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 11781 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 11782 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11783 waitForIdle(); 11784 11785 // A notification exists for the given record 11786 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11787 assertEquals(1, notifsBefore.length); 11788 11789 reset(mPackageManager); 11790 11791 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11792 11793 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11794 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11795 nr.getSbn().getUid()); 11796 11797 // Grant permission called for the UID of SystemUI under the target user ID 11798 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11799 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 11800 anyInt(), eq(nr.getSbn().getUserId())); 11801 } 11802 11803 @Test 11804 public void testGrantInlineReplyUriPermission_noRecordExists() throws Exception { 11805 int userId = UserManager.isHeadlessSystemUserMode() 11806 ? UserHandle.getUserId(UID_HEADLESS) 11807 : USER_SYSTEM; 11808 11809 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 11810 waitForIdle(); 11811 11812 // No notifications exist for the given record 11813 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11814 assertEquals(0, notifsBefore.length); 11815 11816 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11817 11818 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11819 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11820 nr.getSbn().getUid()); 11821 11822 // Grant permission still called if no NotificationRecord exists for the given key 11823 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11824 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 11825 anyInt(), eq(nr.getSbn().getUserId())); 11826 } 11827 11828 @Test 11829 public void testGrantInlineReplyUriPermission_userAll() throws Exception { 11830 // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM 11831 NotificationRecord nr = 11832 generateNotificationRecord(mTestNotificationChannel, UserHandle.USER_ALL); 11833 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 11834 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11835 waitForIdle(); 11836 11837 // A notification exists for the given record 11838 StatusBarNotification[] notifsBefore = mBinderService.getActiveNotifications(mPkg); 11839 assertEquals(1, notifsBefore.length); 11840 11841 reset(mPackageManager); 11842 11843 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11844 11845 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11846 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11847 nr.getSbn().getUid()); 11848 11849 // Target user for the grant is USER_ALL instead of USER_SYSTEM 11850 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11851 eq(nr.getSbn().getUid()), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), 11852 anyInt(), UserManager.isHeadlessSystemUserMode() 11853 ? eq(UserHandle.getUserId(UID_HEADLESS)) 11854 : eq(USER_SYSTEM)); 11855 } 11856 11857 @Test 11858 public void testGrantInlineReplyUriPermission_acrossUsers() throws Exception { 11859 // generate a NotificationRecord for USER_ALL to make sure it's converted into USER_SYSTEM 11860 int otherUserId = 11; 11861 NotificationRecord nr = 11862 generateNotificationRecord(mTestNotificationChannel, otherUserId); 11863 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 11864 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11865 waitForIdle(); 11866 11867 // A notification exists for the given record 11868 List<StatusBarNotification> notifsBefore = 11869 mBinderService.getAppActiveNotifications(mPkg, nr.getSbn().getUserId()).getList(); 11870 assertEquals(1, notifsBefore.size()); 11871 11872 reset(mPackageManager); 11873 11874 Uri uri = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11875 11876 int uid = 0; // sysui on primary user 11877 int otherUserUid = (otherUserId * 100000) + 1; // sysui as a different user 11878 String sysuiPackage = "sysui"; 11879 final String[] sysuiPackages = new String[] { sysuiPackage }; 11880 when(mPackageManager.getPackagesForUid(uid)).thenReturn(sysuiPackages); 11881 11882 // Make sure to mock call for USER_SYSTEM and not USER_ALL, since it's been replaced by the 11883 // time this is called 11884 when(mPackageManager.getPackageUid(sysuiPackage, 0, otherUserId)) 11885 .thenReturn(otherUserUid); 11886 11887 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11888 nr.getKey(), uri, nr.getSbn().getUser(), nr.getSbn().getPackageName(), uid); 11889 11890 // Target user for the grant is USER_ALL instead of USER_SYSTEM 11891 verify(mUgm, times(1)).grantUriPermissionFromOwner(any(), 11892 eq(otherUserUid), eq(nr.getSbn().getPackageName()), eq(uri), anyInt(), anyInt(), 11893 eq(otherUserId)); 11894 } 11895 11896 @Test 11897 public void testClearInlineReplyUriPermission_uriRecordExists() throws Exception { 11898 int userId = UserManager.isHeadlessSystemUserMode() 11899 ? UserHandle.getUserId(UID_HEADLESS) 11900 : USER_SYSTEM; 11901 11902 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, userId); 11903 reset(mPackageManager); 11904 11905 Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11906 Uri uri2 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 2); 11907 11908 // create an inline record with two uris in it 11909 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11910 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11911 nr.getSbn().getUid()); 11912 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11913 nr.getKey(), uri2, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11914 nr.getSbn().getUid()); 11915 11916 InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey()); 11917 assertNotNull(record); // record exists 11918 assertEquals(record.getUris().size(), 2); // record has two uris in it 11919 11920 mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), 11921 nr.getSbn().getUid()); 11922 11923 // permissionOwner destroyed 11924 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner( 11925 eq(record.getPermissionOwner()), eq(null), eq(~0), eq(nr.getUserId())); 11926 } 11927 11928 11929 @Test 11930 public void testClearInlineReplyUriPermission_noUriRecordExists() throws Exception { 11931 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 0); 11932 reset(mPackageManager); 11933 11934 mService.mNotificationDelegate.clearInlineReplyUriPermissions(nr.getKey(), 11935 nr.getSbn().getUid()); 11936 11937 // no permissionOwner destroyed 11938 verify(mUgmInternal, times(0)).revokeUriPermissionFromOwner( 11939 any(), eq(null), eq(~0), eq(nr.getUserId())); 11940 } 11941 11942 @Test 11943 public void testClearInlineReplyUriPermission_userAll() throws Exception { 11944 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 11945 UserHandle.USER_ALL); 11946 reset(mPackageManager); 11947 11948 Uri uri1 = ContentUris.withAppendedId(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 1); 11949 11950 // create an inline record a uri in it 11951 mService.mNotificationDelegate.grantInlineReplyUriPermission( 11952 nr.getKey(), uri1, nr.getSbn().getUser(), nr.getSbn().getPackageName(), 11953 nr.getSbn().getUid()); 11954 11955 InlineReplyUriRecord record = mService.mInlineReplyRecordsByKey.get(nr.getKey()); 11956 assertNotNull(record); // record exists 11957 11958 mService.mNotificationDelegate.clearInlineReplyUriPermissions( 11959 nr.getKey(), nr.getSbn().getUid()); 11960 11961 // permissionOwner destroyed for USER_SYSTEM, not USER_ALL 11962 verify(mUgmInternal, times(1)).revokeUriPermissionFromOwner( 11963 eq(record.getPermissionOwner()), eq(null), eq(~0), 11964 UserManager.isHeadlessSystemUserMode() 11965 ? eq(UserHandle.getUserId(UID_HEADLESS)) 11966 : eq(USER_SYSTEM)); 11967 } 11968 11969 @Test 11970 public void testNotificationBubbles_disabled_lowRamDevice() throws Exception { 11971 setUpPrefsForBubbles(mPkg, mUid, 11972 true /* global */, 11973 BUBBLE_PREFERENCE_ALL /* app */, 11974 true /* channel */); 11975 11976 // And we are low ram 11977 when(mActivityManager.isLowRamDevice()).thenReturn(true); 11978 11979 // Notification that would typically bubble 11980 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 11981 "testNotificationBubbles_disabled_lowRamDevice"); 11982 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 11983 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 11984 waitForIdle(); 11985 11986 // But we wouldn't be a bubble because the device is low ram & all bubbles are disabled. 11987 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 11988 assertEquals(1, notifsAfter.length); 11989 assertEquals((notifsAfter[0].getNotification().flags & FLAG_BUBBLE), 0); 11990 } 11991 11992 @Test 11993 @DisableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS) 11994 public void testRemoveLargeRemoteViews() throws Exception { 11995 // Cast to long to mock RemoteViews.estimateMemoryUsage which returns long. 11996 long removeSize = mContext.getResources().getInteger( 11997 com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); 11998 11999 RemoteViews rv = mock(RemoteViews.class); 12000 when(rv.estimateMemoryUsage()).thenReturn(removeSize); 12001 when(rv.clone()).thenReturn(rv); 12002 RemoteViews rv1 = mock(RemoteViews.class); 12003 when(rv1.estimateMemoryUsage()).thenReturn(removeSize); 12004 when(rv1.clone()).thenReturn(rv1); 12005 RemoteViews rv2 = mock(RemoteViews.class); 12006 when(rv2.estimateMemoryUsage()).thenReturn(removeSize); 12007 when(rv2.clone()).thenReturn(rv2); 12008 RemoteViews rv3 = mock(RemoteViews.class); 12009 when(rv3.estimateMemoryUsage()).thenReturn(removeSize); 12010 when(rv3.clone()).thenReturn(rv3); 12011 RemoteViews rv4 = mock(RemoteViews.class); 12012 when(rv4.estimateMemoryUsage()).thenReturn(removeSize); 12013 when(rv4.clone()).thenReturn(rv4); 12014 // note: different! 12015 RemoteViews rv5 = mock(RemoteViews.class); 12016 when(rv5.estimateMemoryUsage()).thenReturn(removeSize - 1); 12017 when(rv5.clone()).thenReturn(rv5); 12018 12019 Notification np = new Notification.Builder(mContext, "test") 12020 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12021 .setContentText("test") 12022 .setCustomContentView(rv) 12023 .setCustomBigContentView(rv1) 12024 .setCustomHeadsUpContentView(rv2) 12025 .build(); 12026 Notification n = new Notification.Builder(mContext, "test") 12027 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12028 .setContentText("test") 12029 .setCustomContentView(rv3) 12030 .setCustomBigContentView(rv4) 12031 .setCustomHeadsUpContentView(rv5) 12032 .setPublicVersion(np) 12033 .build(); 12034 12035 assertNotNull(np.contentView); 12036 assertNotNull(np.bigContentView); 12037 assertNotNull(np.headsUpContentView); 12038 12039 assertTrue(n.publicVersion.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); 12040 assertNotNull(n.publicVersion.contentView); 12041 assertNotNull(n.publicVersion.bigContentView); 12042 assertNotNull(n.publicVersion.headsUpContentView); 12043 12044 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 12045 12046 assertNull(n.contentView); 12047 assertNull(n.bigContentView); 12048 assertNotNull(n.headsUpContentView); 12049 assertNull(n.publicVersion.contentView); 12050 assertNull(n.publicVersion.bigContentView); 12051 assertNull(n.publicVersion.headsUpContentView); 12052 12053 verify(mUsageStats, times(5)).registerImageRemoved(mPkg); 12054 } 12055 12056 @Test 12057 @EnableFlags(android.app.Flags.FLAG_REMOVE_REMOTE_VIEWS) 12058 public void testRemoveRemoteViews() throws Exception { 12059 Notification np = new Notification.Builder(mContext, "test") 12060 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12061 .setContentText("test") 12062 .setCustomContentView(mock(RemoteViews.class)) 12063 .setCustomBigContentView(mock(RemoteViews.class)) 12064 .setCustomHeadsUpContentView(mock(RemoteViews.class)) 12065 .build(); 12066 Notification n = new Notification.Builder(mContext, "test") 12067 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12068 .setContentText("test") 12069 .setCustomContentView(mock(RemoteViews.class)) 12070 .setCustomBigContentView(mock(RemoteViews.class)) 12071 .setCustomHeadsUpContentView(mock(RemoteViews.class)) 12072 .setPublicVersion(np) 12073 .build(); 12074 12075 assertNotNull(n.contentView); 12076 assertNotNull(n.bigContentView); 12077 assertNotNull(n.headsUpContentView); 12078 12079 assertTrue(np.extras.containsKey(Notification.EXTRA_CONTAINS_CUSTOM_VIEW)); 12080 assertNotNull(np.contentView); 12081 assertNotNull(np.bigContentView); 12082 assertNotNull(np.headsUpContentView); 12083 12084 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 12085 12086 assertNull(n.contentView); 12087 assertNull(n.bigContentView); 12088 assertNull(n.headsUpContentView); 12089 assertNull(n.publicVersion.contentView); 12090 assertNull(n.publicVersion.bigContentView); 12091 assertNull(n.publicVersion.headsUpContentView); 12092 12093 verify(mUsageStats, times(1)).registerImageRemoved(mPkg); 12094 } 12095 12096 @Test 12097 public void testNotificationBubbles_flagAutoExpandForeground_fails_notForeground() 12098 throws Exception { 12099 setUpPrefsForBubbles(mPkg, mUid, 12100 true /* global */, 12101 BUBBLE_PREFERENCE_ALL /* app */, 12102 true /* channel */); 12103 12104 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 12105 "testNotificationBubbles_flagAutoExpandForeground_fails_notForeground"); 12106 // Modify metadata flags 12107 nr.getSbn().getNotification().getBubbleMetadata().setFlags( 12108 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE 12109 | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 12110 12111 // Ensure we're not foreground 12112 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 12113 IMPORTANCE_VISIBLE); 12114 12115 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12116 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12117 waitForIdle(); 12118 12119 // yes allowed, yes messaging, yes bubble 12120 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12121 assertTrue(notif.isBubbleNotification()); 12122 12123 // The flag should have failed since we're not foreground 12124 assertFalse(notif.getBubbleMetadata().getAutoExpandBubble()); 12125 } 12126 12127 @Test 12128 public void testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground() 12129 throws RemoteException { 12130 setUpPrefsForBubbles(mPkg, mUid, 12131 true /* global */, 12132 BUBBLE_PREFERENCE_ALL /* app */, 12133 true /* channel */); 12134 12135 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 12136 "testNotificationBubbles_flagAutoExpandForeground_succeeds_foreground"); 12137 // Modify metadata flags 12138 nr.getSbn().getNotification().getBubbleMetadata().setFlags( 12139 Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE 12140 | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION); 12141 12142 // Ensure we are in the foreground 12143 when(mActivityManager.getPackageImportance(nr.getSbn().getPackageName())).thenReturn( 12144 IMPORTANCE_FOREGROUND); 12145 12146 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12147 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12148 waitForIdle(); 12149 12150 // yes allowed, yes messaging, yes bubble 12151 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12152 assertTrue(notif.isBubbleNotification()); 12153 12154 // Our flags should have passed since we are foreground 12155 assertTrue(notif.getBubbleMetadata().getAutoExpandBubble()); 12156 assertTrue(notif.getBubbleMetadata().isNotificationSuppressed()); 12157 } 12158 12159 @Test 12160 public void testNotificationBubbles_flagRemoved_whenShortcutRemoved() 12161 throws RemoteException { 12162 setUpPrefsForBubbles(mPkg, mUid, 12163 true /* global */, 12164 BUBBLE_PREFERENCE_ALL /* app */, 12165 true /* channel */); 12166 12167 ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback = 12168 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class); 12169 12170 // Messaging notification with shortcut info 12171 Notification.BubbleMetadata metadata = 12172 new Notification.BubbleMetadata.Builder(VALID_CONVO_SHORTCUT_ID).build(); 12173 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12174 null /* groupKey */, false /* isSummary */, true); 12175 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12176 nb.setBubbleMetadata(metadata); 12177 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12178 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12179 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12180 12181 // Test: Send the bubble notification 12182 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12183 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12184 waitForIdle(); 12185 12186 // Verify: 12187 12188 // Make sure we register the callback for shortcut changes 12189 verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback( 12190 shortcutChangeCallback.capture()); 12191 12192 // yes allowed, yes messaging w/shortcut, yes bubble 12193 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12194 assertTrue(notif.isBubbleNotification()); 12195 12196 // Make sure the shortcut is cached. 12197 verify(mShortcutServiceInternal).cacheShortcuts( 12198 anyInt(), any(), eq(mPkg), eq(singletonList(VALID_CONVO_SHORTCUT_ID)), 12199 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); 12200 12201 // Test: Remove the shortcut 12202 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12203 ArrayList<ShortcutInfo> removedShortcuts = new ArrayList<>(); 12204 removedShortcuts.add(createMockConvoShortcut()); 12205 shortcutChangeCallback.getValue().onShortcutsRemoved(mPkg, removedShortcuts, 12206 UserHandle.getUserHandleForUid(mUid)); 12207 waitForIdle(); 12208 12209 // Verify: 12210 12211 // Make sure callback is unregistered 12212 verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback( 12213 shortcutChangeCallback.getValue()); 12214 12215 // We're no longer a bubble 12216 NotificationRecord notif2 = mService.getNotificationRecord( 12217 nr.getSbn().getKey()); 12218 assertNull(notif2.getShortcutInfo()); 12219 assertFalse(notif2.getNotification().isBubbleNotification()); 12220 } 12221 12222 @Test 12223 public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved() 12224 throws RemoteException { 12225 final String shortcutId = "someshortcutId"; 12226 setUpPrefsForBubbles(mPkg, mUid, 12227 true /* global */, 12228 BUBBLE_PREFERENCE_ALL /* app */, 12229 true /* channel */); 12230 12231 ArgumentCaptor<LauncherApps.ShortcutChangeCallback> shortcutChangeCallback = 12232 ArgumentCaptor.forClass(LauncherApps.ShortcutChangeCallback.class); 12233 12234 // Messaging notification with shortcut info 12235 Notification.BubbleMetadata metadata = new Notification.BubbleMetadata.Builder( 12236 shortcutId).build(); 12237 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12238 null /* groupKey */, false /* isSummary */, true); 12239 nb.setShortcutId(shortcutId); 12240 nb.setBubbleMetadata(metadata); 12241 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12242 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12243 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12244 12245 // Pretend the shortcut exists 12246 List<ShortcutInfo> shortcutInfos = new ArrayList<>(); 12247 ShortcutInfo info = mock(ShortcutInfo.class); 12248 when(info.getPackage()).thenReturn(mPkg); 12249 when(info.getId()).thenReturn(shortcutId); 12250 when(info.getUserId()).thenReturn(USER_SYSTEM); 12251 when(info.isLongLived()).thenReturn(true); 12252 when(info.isEnabled()).thenReturn(true); 12253 shortcutInfos.add(info); 12254 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcutInfos); 12255 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 12256 anyString(), anyInt(), any())).thenReturn(true); 12257 12258 // Test: Send the bubble notification 12259 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12260 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12261 waitForIdle(); 12262 12263 // Verify: 12264 12265 // Make sure we register the callback for shortcut changes 12266 verify(mShortcutServiceInternal, times(1)).addShortcutChangeCallback( 12267 shortcutChangeCallback.capture()); 12268 12269 // yes allowed, yes messaging w/shortcut, yes bubble 12270 Notification notif = mService.getNotificationRecord(nr.getSbn().getKey()).getNotification(); 12271 assertTrue(notif.isBubbleNotification()); 12272 12273 // Make sure the shortcut is cached. 12274 verify(mShortcutServiceInternal).cacheShortcuts( 12275 anyInt(), any(), eq(mPkg), eq(singletonList(shortcutId)), 12276 eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); 12277 12278 // Test: Remove the notification 12279 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12280 nr.getSbn().getId(), nr.getSbn().getUserId()); 12281 waitForIdle(); 12282 12283 // Verify: 12284 12285 // Make sure callback is unregistered 12286 verify(mShortcutServiceInternal, times(1)).removeShortcutChangeCallback( 12287 shortcutChangeCallback.getValue()); 12288 } 12289 12290 @Test 12291 public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryDismissed() 12292 throws Exception { 12293 setUpPrefsForBubbles(mPkg, mUid, 12294 true /* global */, 12295 BUBBLE_PREFERENCE_ALL /* app */, 12296 true /* channel */); 12297 12298 NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( 12299 true /* summaryAutoCancel */); 12300 12301 // Dismiss summary 12302 final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, 12303 true); 12304 mService.mNotificationDelegate.onNotificationClear(mUid, 0, mPkg, 12305 nrSummary.getUserId(), nrSummary.getKey(), 12306 NotificationStats.DISMISSAL_SHADE, 12307 NotificationStats.DISMISS_SENTIMENT_NEUTRAL, nv); 12308 waitForIdle(); 12309 12310 // The bubble should still exist 12311 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12312 assertEquals(1, notifsAfter.length); 12313 } 12314 12315 @Test 12316 public void testNotificationBubbles_bubbleChildrenStay_whenGroupSummaryClicked() 12317 throws Exception { 12318 setUpPrefsForBubbles(mPkg, mUid, 12319 true /* global */, 12320 BUBBLE_PREFERENCE_ALL /* app */, 12321 true /* channel */); 12322 12323 NotificationRecord nrSummary = addGroupWithBubblesAndValidateAdded( 12324 true /* summaryAutoCancel */); 12325 12326 // Click summary 12327 final NotificationVisibility nv = NotificationVisibility.obtain(nrSummary.getKey(), 1, 2, 12328 true); 12329 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 12330 nrSummary.getKey(), nv); 12331 waitForIdle(); 12332 12333 // The bubble should still exist 12334 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12335 assertEquals(1, notifsAfter.length); 12336 12337 // Check we got the click log and associated dismissal logs 12338 assertEquals(6, mNotificationRecordLogger.numCalls()); 12339 // Skip the notification-creation logs 12340 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 12341 mNotificationRecordLogger.event(3)); 12342 assertEquals(NotificationRecordLogger.NotificationCancelledEvent.NOTIFICATION_CANCEL_CLICK, 12343 mNotificationRecordLogger.event(4)); 12344 assertEquals(NotificationRecordLogger.NotificationCancelledEvent 12345 .NOTIFICATION_CANCEL_GROUP_SUMMARY_CANCELED, 12346 mNotificationRecordLogger.event(5)); 12347 } 12348 12349 @Test 12350 public void testNotificationBubbles_bubbleStays_whenClicked() 12351 throws Exception { 12352 setUpPrefsForBubbles(mPkg, mUid, 12353 true /* global */, 12354 BUBBLE_PREFERENCE_ALL /* app */, 12355 true /* channel */); 12356 12357 // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble 12358 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 12359 nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL; 12360 mService.addNotification(nr); 12361 12362 // WHEN we click the notification 12363 final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true); 12364 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 12365 nr.getKey(), nv); 12366 waitForIdle(); 12367 12368 // THEN the bubble should still exist 12369 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12370 assertEquals(1, notifsAfter.length); 12371 12372 // Check we got the click log 12373 assertEquals(1, mNotificationRecordLogger.numCalls()); 12374 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 12375 mNotificationRecordLogger.event(0)); 12376 } 12377 12378 /** 12379 * When something is bubble'd and the bubble is dismissed, but the notification is still 12380 * visible, clicking on the notification shouldn't auto-cancel it because clicking on 12381 * it will produce a bubble. 12382 */ 12383 @Test 12384 public void testNotificationBubbles_bubbleStays_whenClicked_afterBubbleDismissed() 12385 throws Exception { 12386 setUpPrefsForBubbles(mPkg, mUid, 12387 true /* global */, 12388 BUBBLE_PREFERENCE_ALL /* app */, 12389 true /* channel */); 12390 12391 // GIVEN a notification that has the auto cancels flag (cancel on click) and is a bubble 12392 final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); 12393 nr.getSbn().getNotification().flags |= FLAG_BUBBLE | FLAG_AUTO_CANCEL; 12394 nr.setAllowBubble(true); 12395 mService.addNotification(nr); 12396 12397 // And the bubble is dismissed 12398 mService.mNotificationDelegate.onNotificationBubbleChanged(nr.getKey(), 12399 false /* isBubble */, 0 /* bubbleFlags */); 12400 waitForIdle(); 12401 assertTrue(nr.isFlagBubbleRemoved()); 12402 12403 // WHEN we click the notification 12404 final NotificationVisibility nv = NotificationVisibility.obtain(nr.getKey(), 1, 2, true); 12405 mService.mNotificationDelegate.onNotificationClick(mUid, Binder.getCallingPid(), 12406 nr.getKey(), nv); 12407 waitForIdle(); 12408 12409 // THEN the bubble should still exist 12410 StatusBarNotification[] notifsAfter = mBinderService.getActiveNotifications(mPkg); 12411 assertEquals(1, notifsAfter.length); 12412 12413 // Check we got the click log 12414 assertEquals(1, mNotificationRecordLogger.numCalls()); 12415 assertEquals(NotificationRecordLogger.NotificationEvent.NOTIFICATION_CLICKED, 12416 mNotificationRecordLogger.event(0)); 12417 } 12418 12419 @Test 12420 public void testLoadDefaultApprovedServices_emptyResources() { 12421 TestableResources tr = mContext.getOrCreateTestableResources(); 12422 tr.addOverride(com.android.internal.R.string.config_defaultListenerAccessPackages, ""); 12423 tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, ""); 12424 tr.addOverride(com.android.internal.R.string.config_defaultAssistantAccessComponent, ""); 12425 12426 mService.loadDefaultApprovedServices(USER_SYSTEM); 12427 12428 verify(mListeners, never()).addDefaultComponentOrPackage(anyString()); 12429 verify(mConditionProviders, never()).addDefaultComponentOrPackage(anyString()); 12430 verify(mAssistants, never()).addDefaultComponentOrPackage(anyString()); 12431 } 12432 12433 @Test 12434 public void testLoadDefaultApprovedServices_dnd() { 12435 TestableResources tr = mContext.getOrCreateTestableResources(); 12436 tr.addOverride(com.android.internal.R.string.config_defaultDndAccessPackages, "test"); 12437 when(mListeners.queryPackageForServices(anyString(), anyInt(), anyInt())) 12438 .thenReturn(new ArraySet<>()); 12439 12440 mService.loadDefaultApprovedServices(USER_SYSTEM); 12441 12442 verify(mConditionProviders, times(1)).loadDefaultsFromConfig(); 12443 } 12444 12445 // TODO: add tests for the rest of the non-empty cases 12446 12447 @Test 12448 public void testOnUnlockUser() { 12449 UserInfo ui = new UserInfo(); 12450 ui.id = 10; 12451 mService.onUserUnlocked(new TargetUser(ui)); 12452 waitForIdle(); 12453 12454 verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserUnlocked(ui.id); 12455 } 12456 12457 @Test 12458 public void testOnStopUser() { 12459 UserInfo ui = new UserInfo(); 12460 ui.id = 10; 12461 mService.onUserStopping(new TargetUser(ui)); 12462 waitForIdle(); 12463 12464 verify(mHistoryManager, timeout(MAX_POST_DELAY).times(1)).onUserStopped(ui.id); 12465 } 12466 12467 @Test 12468 public void testHandleOnPackageChanged() { 12469 String[] pkgs = new String[] {mPkg, PKG_N_MR1}; 12470 int[] uids = new int[] {mUid, UserHandle.PER_USER_RANGE + 1}; 12471 12472 mService.handleOnPackageChanged(false, USER_SYSTEM, pkgs, uids); 12473 12474 verify(mHistoryManager, never()).onPackageRemoved(anyInt(), anyString()); 12475 12476 mService.handleOnPackageChanged(true, USER_SYSTEM, pkgs, uids); 12477 12478 verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[0]), pkgs[0]); 12479 verify(mHistoryManager, times(1)).onPackageRemoved(UserHandle.getUserId(uids[1]), pkgs[1]); 12480 } 12481 12482 @Test 12483 public void testHandleOnPackageRemoved_ClearsHistory() throws Exception { 12484 // Enables Notification History setting 12485 setUpPrefsForHistory(mUserId, true /* =enabled */); 12486 12487 // Posts a notification to the mTestNotificationChannel. 12488 final NotificationRecord notif = generateNotificationRecord( 12489 mTestNotificationChannel, 1, null, false); 12490 mService.addNotification(notif); 12491 StatusBarNotification[] notifs = mBinderService.getActiveNotifications( 12492 notif.getSbn().getPackageName()); 12493 assertEquals(1, notifs.length); 12494 12495 // Cancels all notifications. 12496 mService.cancelAllNotificationsInt(mUid, 0, mPkg, null, 0, 0, 12497 notif.getUserId(), REASON_CANCEL); 12498 waitForIdle(); 12499 notifs = mBinderService.getActiveNotifications(notif.getSbn().getPackageName()); 12500 assertEquals(0, notifs.length); 12501 12502 // Checks that notification history's recently canceled archive contains the notification. 12503 notifs = mBinderService.getHistoricalNotificationsWithAttribution(mPkg, 12504 mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); 12505 waitForIdle(); 12506 assertEquals(1, notifs.length); 12507 12508 // Remove sthe package that contained the channel 12509 simulatePackageRemovedBroadcast(mPkg, mUid); 12510 waitForIdle(); 12511 12512 // Checks that notification history no longer contains the notification. 12513 notifs = mBinderService.getHistoricalNotificationsWithAttribution( 12514 mPkg, mContext.getAttributionTag(), 5 /* count */, false /* includeSnoozed */); 12515 waitForIdle(); 12516 assertEquals(0, notifs.length); 12517 } 12518 12519 @Test 12520 public void testNotificationHistory_addNoisyNotification() throws Exception { 12521 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, 12522 null /* tvExtender */); 12523 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12524 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12525 waitForIdle(); 12526 12527 verify(mHistoryManager, times(1)).addNotification(any()); 12528 } 12529 12530 @Test 12531 public void createConversationNotificationChannel() throws Exception { 12532 int userId = UserManager.isHeadlessSystemUserMode() 12533 ? UserHandle.getUserId(UID_HEADLESS) 12534 : USER_SYSTEM; 12535 12536 NotificationChannel original = new NotificationChannel("a", "a", IMPORTANCE_HIGH); 12537 original.setAllowBubbles(!original.canBubble()); 12538 original.setShowBadge(!original.canShowBadge()); 12539 12540 Parcel parcel = Parcel.obtain(); 12541 original.writeToParcel(parcel, 0); 12542 parcel.setDataPosition(0); 12543 NotificationChannel orig = NotificationChannel.CREATOR.createFromParcel(parcel); 12544 assertEquals(original, orig); 12545 assertFalse(TextUtils.isEmpty(orig.getName())); 12546 12547 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice(Arrays.asList( 12548 orig))); 12549 12550 mBinderService.createConversationNotificationChannelForPackage( 12551 mPkg, mUid, orig, "friend"); 12552 12553 NotificationChannel friendChannel = mBinderService.getConversationNotificationChannel( 12554 mPkg, userId, mPkg, original.getId(), false, "friend"); 12555 12556 assertEquals(original.getName(), friendChannel.getName()); 12557 assertEquals(original.getId(), friendChannel.getParentChannelId()); 12558 assertEquals("friend", friendChannel.getConversationId()); 12559 assertEquals(null, original.getConversationId()); 12560 assertEquals(original.canShowBadge(), friendChannel.canShowBadge()); 12561 assertFalse(friendChannel.canBubble()); // can't be modified by app 12562 assertFalse(original.getId().equals(friendChannel.getId())); 12563 assertNotNull(friendChannel.getId()); 12564 } 12565 12566 @Test 12567 public void testCorrectCategory_systemOn_appCannotTurnOff() { 12568 int requested = 0; 12569 int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12570 12571 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12572 system); 12573 12574 assertEquals(PRIORITY_CATEGORY_CONVERSATIONS, actual); 12575 } 12576 12577 @Test 12578 public void testCorrectCategory_systemOff_appTurnOff_noChanges() { 12579 int requested = PRIORITY_CATEGORY_CALLS; 12580 int system = PRIORITY_CATEGORY_CALLS; 12581 12582 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12583 system); 12584 12585 assertEquals(PRIORITY_CATEGORY_CALLS, actual); 12586 } 12587 12588 @Test 12589 public void testCorrectCategory_systemOn_appTurnOn_noChanges() { 12590 int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12591 int system = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12592 12593 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12594 system); 12595 12596 assertEquals(PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS, actual); 12597 } 12598 12599 @Test 12600 public void testCorrectCategory_systemOff_appCannotTurnOn() { 12601 int requested = PRIORITY_CATEGORY_CALLS | PRIORITY_CATEGORY_CONVERSATIONS; 12602 int system = PRIORITY_CATEGORY_CALLS; 12603 12604 int actual = mService.correctCategory(requested, PRIORITY_CATEGORY_CONVERSATIONS, 12605 system); 12606 12607 assertEquals(PRIORITY_CATEGORY_CALLS, actual); 12608 } 12609 12610 @Test 12611 public void testRestoreConversationChannel_deleted() throws Exception { 12612 // Create parent channel 12613 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12614 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12615 IMPORTANCE_DEFAULT); 12616 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12617 NotificationChannel.CREATOR); 12618 assertEquals(originalChannel, parentChannel); 12619 mBinderService.createNotificationChannels(mPkg, 12620 new ParceledListSlice(Arrays.asList(parentChannel))); 12621 12622 //Create deleted conversation channel 12623 mBinderService.createConversationNotificationChannelForPackage( 12624 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 12625 final NotificationChannel conversationChannel = 12626 mBinderService.getConversationNotificationChannel( 12627 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 12628 conversationChannel.setDeleted(true); 12629 12630 //Create notification record 12631 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12632 null /* groupKey */, false /* isSummary */, true); 12633 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12634 nb.setChannelId(originalChannel.getId()); 12635 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12636 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12637 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12638 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12639 12640 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12641 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12642 waitForIdle(); 12643 12644 // Verify that the channel was changed to the conversation channel and restored 12645 assertThat(mService.getNotificationRecord(nr.getKey()).isConversation()).isTrue(); 12646 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 12647 conversationChannel); 12648 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().isDeleted()).isFalse(); 12649 assertThat(mService.getNotificationRecord(nr.getKey()).getChannel().getDeletedTimeMs()) 12650 .isEqualTo(-1); 12651 } 12652 12653 @Test 12654 public void testDoNotRestoreParentChannel_deleted() throws Exception { 12655 // Create parent channel and set as deleted 12656 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12657 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12658 IMPORTANCE_DEFAULT); 12659 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12660 NotificationChannel.CREATOR); 12661 assertEquals(originalChannel, parentChannel); 12662 mBinderService.createNotificationChannels(mPkg, 12663 new ParceledListSlice(Arrays.asList(parentChannel))); 12664 parentChannel.setDeleted(true); 12665 12666 //Create notification record 12667 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12668 null /* groupKey */, false /* isSummary */, true); 12669 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12670 nb.setChannelId(originalChannel.getId()); 12671 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12672 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12673 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12674 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12675 12676 when(mPermissionHelper.hasPermission(mUid)).thenReturn(true); 12677 12678 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12679 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12680 waitForIdle(); 12681 12682 // Verify that the channel was not restored and the notification was not posted 12683 assertThat(mService.mChannelToastsSent).contains(mUid); 12684 assertThat(mService.getNotificationRecord(nr.getKey())).isNull(); 12685 assertThat(parentChannel.isDeleted()).isTrue(); 12686 } 12687 12688 @Test 12689 public void testEnqueueToConversationChannel_notDeleted_doesNotRestore() throws Exception { 12690 TestableNotificationManagerService service = spy(mService); 12691 PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper); 12692 service.setPreferencesHelper(preferencesHelper); 12693 // Create parent channel 12694 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12695 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12696 IMPORTANCE_DEFAULT); 12697 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12698 NotificationChannel.CREATOR); 12699 assertEquals(originalChannel, parentChannel); 12700 mBinderService.createNotificationChannels(mPkg, 12701 new ParceledListSlice(Arrays.asList(parentChannel))); 12702 12703 //Create conversation channel 12704 mBinderService.createConversationNotificationChannelForPackage( 12705 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 12706 final NotificationChannel conversationChannel = 12707 mBinderService.getConversationNotificationChannel( 12708 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 12709 12710 //Create notification record 12711 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12712 null /* groupKey */, false /* isSummary */, true); 12713 nb.setShortcutId(VALID_CONVO_SHORTCUT_ID); 12714 nb.setChannelId(originalChannel.getId()); 12715 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12716 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12717 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12718 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12719 12720 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12721 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12722 waitForIdle(); 12723 12724 // Verify that the channel was changed to the conversation channel and not restored 12725 assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isTrue(); 12726 assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 12727 conversationChannel); 12728 verify(service, never()).handleSavePolicyFile(); 12729 verify(preferencesHelper, never()).createNotificationChannel(anyString(), 12730 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()); 12731 } 12732 12733 @Test 12734 public void testEnqueueToParentChannel_notDeleted_doesNotRestore() throws Exception { 12735 TestableNotificationManagerService service = spy(mService); 12736 PreferencesHelper preferencesHelper = spy(mService.mPreferencesHelper); 12737 service.setPreferencesHelper(preferencesHelper); 12738 // Create parent channel 12739 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 12740 final NotificationChannel originalChannel = new NotificationChannel("id", "name", 12741 IMPORTANCE_DEFAULT); 12742 NotificationChannel parentChannel = parcelAndUnparcel(originalChannel, 12743 NotificationChannel.CREATOR); 12744 assertEquals(originalChannel, parentChannel); 12745 mBinderService.createNotificationChannels(mPkg, 12746 new ParceledListSlice(Arrays.asList(parentChannel))); 12747 12748 //Create deleted conversation channel 12749 mBinderService.createConversationNotificationChannelForPackage( 12750 mPkg, mUid, parentChannel, VALID_CONVO_SHORTCUT_ID); 12751 final NotificationChannel conversationChannel = 12752 mBinderService.getConversationNotificationChannel( 12753 mPkg, mUserId, mPkg, originalChannel.getId(), false, VALID_CONVO_SHORTCUT_ID); 12754 12755 //Create notification record without a shortcutId 12756 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12757 null /* groupKey */, false /* isSummary */, true); 12758 nb.setShortcutId(null); 12759 nb.setChannelId(originalChannel.getId()); 12760 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12761 "tag", mUid, 0, nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 12762 NotificationRecord nr = new NotificationRecord(mContext, sbn, originalChannel); 12763 assertThat(nr.getChannel()).isEqualTo(originalChannel); 12764 12765 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12766 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12767 waitForIdle(); 12768 12769 // Verify that the channel is the parent channel and no channel was restored 12770 //assertThat(service.getNotificationRecord(nr.getKey()).isConversation()).isFalse(); 12771 assertThat(service.getNotificationRecord(nr.getKey()).getChannel()).isEqualTo( 12772 parentChannel); 12773 verify(service, never()).handleSavePolicyFile(); 12774 verify(preferencesHelper, never()).createNotificationChannel(anyString(), 12775 anyInt(), any(), anyBoolean(), anyBoolean(), anyInt(), anyBoolean()); 12776 } 12777 12778 @Test 12779 public void testGetConversationsForPackage_hasShortcut() throws Exception { 12780 mService.setPreferencesHelper(mPreferencesHelper); 12781 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 12782 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 12783 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 12784 channel1.setConversationId("parent1", "convo 1"); 12785 convo1.setNotificationChannel(channel1); 12786 convos.add(convo1); 12787 12788 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 12789 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 12790 channel2.setConversationId("parent1", "convo 2"); 12791 convo2.setNotificationChannel(channel2); 12792 convos.add(convo2); 12793 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 12794 12795 ShortcutInfo si = mock(ShortcutInfo.class); 12796 when(si.getPackage()).thenReturn(PKG_P); 12797 when(si.getId()).thenReturn("convo"); 12798 when(si.getUserId()).thenReturn(USER_SYSTEM); 12799 when(si.getLabel()).thenReturn("Hello"); 12800 when(si.isLongLived()).thenReturn(true); 12801 when(si.isEnabled()).thenReturn(true); 12802 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); 12803 when(mShortcutServiceInternal.isSharingShortcut(anyInt(), anyString(), anyString(), 12804 anyString(), anyInt(), any())).thenReturn(true); 12805 12806 List<ConversationChannelWrapper> conversations = 12807 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12808 assertEquals(si, conversations.get(0).getShortcutInfo()); 12809 assertEquals(si, conversations.get(1).getShortcutInfo()); 12810 12811 // Returns null shortcuts when locked. 12812 when(mUserManager.isUserUnlocked(any(UserHandle.class))).thenReturn(false); 12813 conversations = 12814 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12815 assertThat(conversations.get(0).getShortcutInfo()).isNull(); 12816 assertThat(conversations.get(1).getShortcutInfo()).isNull(); 12817 } 12818 12819 @Test 12820 public void testGetConversationsForPackage_shortcut_notLongLived() throws Exception { 12821 mService.setPreferencesHelper(mPreferencesHelper); 12822 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 12823 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 12824 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 12825 channel1.setConversationId("parent1", "convo 1"); 12826 convo1.setNotificationChannel(channel1); 12827 convos.add(convo1); 12828 12829 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 12830 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 12831 channel2.setConversationId("parent1", "convo 2"); 12832 convo2.setNotificationChannel(channel2); 12833 convos.add(convo2); 12834 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 12835 12836 ShortcutInfo si = mock(ShortcutInfo.class); 12837 when(si.getPackage()).thenReturn(PKG_P); 12838 when(si.getId()).thenReturn("convo"); 12839 when(si.getUserId()).thenReturn(USER_SYSTEM); 12840 when(si.getLabel()).thenReturn("Hello"); 12841 when(si.isLongLived()).thenReturn(false); 12842 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(Arrays.asList(si)); 12843 12844 List<ConversationChannelWrapper> conversations = 12845 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12846 assertNull(conversations.get(0).getShortcutInfo()); 12847 assertNull(conversations.get(1).getShortcutInfo()); 12848 } 12849 12850 @Test 12851 public void testGetConversationsForPackage_doesNotHaveShortcut() throws Exception { 12852 mService.setPreferencesHelper(mPreferencesHelper); 12853 ArrayList<ConversationChannelWrapper> convos = new ArrayList<>(); 12854 ConversationChannelWrapper convo1 = new ConversationChannelWrapper(); 12855 NotificationChannel channel1 = new NotificationChannel("a", "a", 1); 12856 channel1.setConversationId("parent1", "convo 1"); 12857 convo1.setNotificationChannel(channel1); 12858 convos.add(convo1); 12859 12860 ConversationChannelWrapper convo2 = new ConversationChannelWrapper(); 12861 NotificationChannel channel2 = new NotificationChannel("b", "b", 1); 12862 channel2.setConversationId("parent1", "convo 2"); 12863 convo2.setNotificationChannel(channel2); 12864 convos.add(convo2); 12865 when(mPreferencesHelper.getConversations(anyString(), anyInt())).thenReturn(convos); 12866 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12867 12868 List<ConversationChannelWrapper> conversations = 12869 mBinderService.getConversationsForPackage(PKG_P, mUid).getList(); 12870 assertNull(conversations.get(0).getShortcutInfo()); 12871 assertNull(conversations.get(1).getShortcutInfo()); 12872 } 12873 12874 @Test 12875 public void testShortcutHelperNull_doesntCrashEnqueue() throws RemoteException { 12876 mService.setShortcutHelper(null); 12877 NotificationRecord nr = 12878 generateMessageBubbleNotifRecord(mTestNotificationChannel, 12879 "testShortcutHelperNull_doesntCrashEnqueue"); 12880 try { 12881 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12882 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12883 waitForIdle(); 12884 } catch (Exception e) { 12885 fail(e.getMessage()); 12886 } 12887 } 12888 12889 @Test 12890 public void testRecordMessages_invalidMsg() throws RemoteException { 12891 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12892 null /* groupKey */, false /* isSummary */, true); 12893 nb.setShortcutId(null); 12894 StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1, 12895 "testRecordMessages_invalidMsg", mUid, 0, nb.build(), 12896 UserHandle.getUserHandleForUid(mUid), null, 0); 12897 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12898 12899 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12900 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 12901 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12902 waitForIdle(); 12903 12904 assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 12905 } 12906 12907 @Test 12908 public void testRecordMessages_invalidMsg_notMessageStyle() throws RemoteException { 12909 Notification.Builder nb = new Notification.Builder(mContext, 12910 mTestNotificationChannel.getId()) 12911 .setContentTitle("foo") 12912 .setShortcutId(null) 12913 .setSmallIcon(android.R.drawable.sym_def_app_icon) 12914 .setCategory(Notification.CATEGORY_MESSAGE); 12915 StatusBarNotification sbn = new StatusBarNotification(PKG_O, PKG_O, 1, 12916 "testRecordMessages_invalidMsg_notMessageStyle", mUid, 0, nb.build(), 12917 UserHandle.getUserHandleForUid(mUid), null, 0); 12918 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12919 12920 when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); 12921 mBinderService.enqueueNotificationWithTag(PKG_O, PKG_O, nr.getSbn().getTag(), 12922 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12923 waitForIdle(); 12924 12925 // PKG_O is allowed to be in conversation space b/c of override in 12926 // TestableNotificationManagerService 12927 assertTrue(mBinderService.isInInvalidMsgState(PKG_O, mUid)); 12928 } 12929 12930 @Test 12931 public void testRecordMessages_validMsg() throws RemoteException { 12932 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12933 null /* groupKey */, false /* isSummary */, true); 12934 nb.setShortcutId(null); 12935 StatusBarNotification sbn = new StatusBarNotification(PKG_P, PKG_P, 1, 12936 "testRecordMessages_validMsg", mUid, 0, nb.build(), 12937 UserHandle.getUserHandleForUid(mUid), null, 0); 12938 NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12939 12940 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 12941 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12942 waitForIdle(); 12943 12944 assertTrue(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 12945 12946 nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 12947 "testRecordMessages_validMsg"); 12948 12949 mBinderService.enqueueNotificationWithTag(PKG_P, PKG_P, nr.getSbn().getTag(), 12950 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12951 waitForIdle(); 12952 12953 assertFalse(mBinderService.isInInvalidMsgState(PKG_P, mUid)); 12954 } 12955 12956 @Test 12957 public void testRecordMessages_invalidMsg_afterValidMsg() throws RemoteException { 12958 NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, 12959 "testRecordMessages_invalidMsg_afterValidMsg_1"); 12960 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12961 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12962 waitForIdle(); 12963 assertTrue(mService.getNotificationRecord(nr.getKey()).isConversation()); 12964 12965 mBinderService.cancelAllNotifications(mPkg, mUid); 12966 waitForIdle(); 12967 12968 Notification.Builder nb = getMessageStyleNotifBuilder(false /* addDefaultMetadata */, 12969 null /* groupKey */, false /* isSummary */, true); 12970 nb.setShortcutId(null); 12971 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 1, 12972 "testRecordMessages_invalidMsg_afterValidMsg_2", mUid, 0, nb.build(), 12973 UserHandle.getUserHandleForUid(mUid), null, 0); 12974 nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 12975 12976 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 12977 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 12978 waitForIdle(); 12979 12980 assertFalse(mService.getNotificationRecord(nr.getKey()).isConversation()); 12981 } 12982 12983 @Test 12984 public void testCanPostFgsWhenOverLimit() throws RemoteException { 12985 when(mAmi.applyForegroundServiceNotification( 12986 any(), anyString(), anyInt(), anyString(), anyInt())) 12987 .thenReturn(SHOW_IMMEDIATELY); 12988 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 12989 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 12990 i, null, false).getSbn(); 12991 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12992 "testCanPostFgsWhenOverLimit", 12993 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 12994 } 12995 12996 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 12997 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 12998 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 12999 "testCanPostFgsWhenOverLimit - fgs over limit!", 13000 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13001 13002 waitForIdle(); 13003 13004 StatusBarNotification[] notifs = 13005 mBinderService.getActiveNotifications(sbn.getPackageName()); 13006 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 13007 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 13008 mService.getNotificationRecordCount()); 13009 } 13010 13011 @Test 13012 public void testCannotPostNonFgsWhenOverLimit() throws RemoteException { 13013 when(mAmi.applyForegroundServiceNotification( 13014 any(), anyString(), anyInt(), anyString(), anyInt())) 13015 .thenReturn(SHOW_IMMEDIATELY); 13016 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 13017 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 13018 i, null, false).getSbn(); 13019 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 13020 "testCanPostFgsWhenOverLimit", 13021 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13022 waitForIdle(); 13023 } 13024 13025 final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 13026 100, null, false).getSbn(); 13027 sbn.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 13028 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 13029 "testCanPostFgsWhenOverLimit - fgs over limit!", 13030 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 13031 13032 final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel, 13033 101, null, false).getSbn(); 13034 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 13035 "testCanPostFgsWhenOverLimit - non fgs over limit!", 13036 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId()); 13037 13038 13039 when(mAmi.applyForegroundServiceNotification( 13040 any(), anyString(), anyInt(), anyString(), anyInt())) 13041 .thenReturn(NOT_FOREGROUND_SERVICE); 13042 final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel, 13043 101, null, false).getSbn(); 13044 sbn3.getNotification().flags |= FLAG_FOREGROUND_SERVICE; 13045 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 13046 "testCanPostFgsWhenOverLimit - fake fgs over limit!", 13047 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId()); 13048 13049 waitForIdle(); 13050 13051 StatusBarNotification[] notifs = 13052 mBinderService.getActiveNotifications(sbn.getPackageName()); 13053 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 13054 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 13055 mService.getNotificationRecordCount()); 13056 } 13057 13058 @Test 13059 public void testIsVisibleToListener_notEnabled() { 13060 StatusBarNotification sbn = mock(StatusBarNotification.class); 13061 when(sbn.getUserId()).thenReturn(10); 13062 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13063 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 13064 info.userid = 10; 13065 when(info.isSameUser(anyInt())).thenReturn(true); 13066 when(assistant.isSameUser(anyInt())).thenReturn(true); 13067 when(info.enabledAndUserMatches(info.userid)).thenReturn(false); 13068 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 13069 13070 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 13071 } 13072 13073 @Test 13074 public void testIsVisibleToListener_noAssistant() { 13075 StatusBarNotification sbn = mock(StatusBarNotification.class); 13076 when(sbn.getUserId()).thenReturn(10); 13077 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13078 info.userid = 10; 13079 when(info.isSameUser(anyInt())).thenReturn(true); 13080 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 13081 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(null); 13082 13083 assertTrue(mService.isVisibleToListener(sbn, 0, info)); 13084 } 13085 13086 @Test 13087 public void testIsVisibleToListener_assistant_differentUser() { 13088 StatusBarNotification sbn = mock(StatusBarNotification.class); 13089 when(sbn.getUserId()).thenReturn(10); 13090 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13091 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 13092 info.userid = 0; 13093 when(info.isSameUser(anyInt())).thenReturn(true); 13094 when(assistant.isSameUser(anyInt())).thenReturn(true); 13095 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 13096 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 13097 13098 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 13099 } 13100 13101 @Test 13102 public void testIsVisibleToListener_assistant_sameUser() { 13103 StatusBarNotification sbn = mock(StatusBarNotification.class); 13104 when(sbn.getUserId()).thenReturn(10); 13105 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13106 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 13107 info.userid = 10; 13108 when(info.isSameUser(anyInt())).thenReturn(true); 13109 when(assistant.isSameUser(anyInt())).thenReturn(true); 13110 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 13111 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 13112 13113 assertTrue(mService.isVisibleToListener(sbn, 0, info)); 13114 } 13115 13116 @Test 13117 public void testIsVisibleToListener_mismatchedType() { 13118 when(mNlf.isTypeAllowed(anyInt())).thenReturn(false); 13119 13120 StatusBarNotification sbn = mock(StatusBarNotification.class); 13121 when(sbn.getUserId()).thenReturn(10); 13122 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13123 ManagedServices.ManagedServiceInfo assistant = mock(ManagedServices.ManagedServiceInfo.class); 13124 info.userid = 10; 13125 when(info.isSameUser(anyInt())).thenReturn(true); 13126 when(assistant.isSameUser(anyInt())).thenReturn(true); 13127 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 13128 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 13129 13130 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 13131 } 13132 13133 @Test 13134 public void testIsVisibleToListener_disallowedPackage() { 13135 when(mNlf.isPackageAllowed(any())).thenReturn(false); 13136 13137 StatusBarNotification sbn = mock(StatusBarNotification.class); 13138 when(sbn.getUserId()).thenReturn(10); 13139 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13140 ManagedServices.ManagedServiceInfo assistant = 13141 mock(ManagedServices.ManagedServiceInfo.class); 13142 info.userid = 10; 13143 when(info.isSameUser(anyInt())).thenReturn(true); 13144 when(assistant.isSameUser(anyInt())).thenReturn(true); 13145 when(info.enabledAndUserMatches(info.userid)).thenReturn(true); 13146 when(mAssistants.checkServiceTokenLocked(any())).thenReturn(assistant); 13147 13148 assertFalse(mService.isVisibleToListener(sbn, 0, info)); 13149 } 13150 13151 @Test 13152 public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedFirst() { 13153 final NotificationRecord parent = spy(generateNotificationRecord( 13154 mTestNotificationChannel, 1, "group", true)); 13155 final NotificationRecord child = spy(generateNotificationRecord( 13156 mTestNotificationChannel, 2, "group", false)); 13157 mService.addNotification(parent); 13158 mService.addNotification(child); 13159 13160 InOrder inOrder = inOrder(parent, child); 13161 13162 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 13163 parent.getUserId()); 13164 waitForIdle(); 13165 inOrder.verify(parent).recordDismissalSentiment(anyInt()); 13166 inOrder.verify(child).recordDismissalSentiment(anyInt()); 13167 } 13168 13169 @Test 13170 public void testUserInitiatedCancelAll_groupCancellationOrder_groupPostedSecond() { 13171 final NotificationRecord parent = spy(generateNotificationRecord( 13172 mTestNotificationChannel, 1, "group", true)); 13173 final NotificationRecord child = spy(generateNotificationRecord( 13174 mTestNotificationChannel, 2, "group", false)); 13175 mService.addNotification(child); 13176 mService.addNotification(parent); 13177 13178 InOrder inOrder = inOrder(parent, child); 13179 13180 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), 13181 parent.getUserId()); 13182 waitForIdle(); 13183 inOrder.verify(parent).recordDismissalSentiment(anyInt()); 13184 inOrder.verify(child).recordDismissalSentiment(anyInt()); 13185 } 13186 13187 @Test 13188 public void testImmutableBubbleIntent() throws Exception { 13189 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13190 NotificationRecord r = generateMessageBubbleNotifRecord(true, 13191 mTestNotificationChannel, 7, "testImmutableBubbleIntent", null, false, false); 13192 try { 13193 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13194 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13195 13196 waitForIdle(); 13197 fail("Allowed a bubble with an immutable intent to be posted"); 13198 } catch (IllegalArgumentException e) { 13199 // good 13200 } 13201 } 13202 13203 @Test 13204 public void testMutableBubbleIntent() throws Exception { 13205 NotificationRecord r = generateMessageBubbleNotifRecord(true, 13206 mTestNotificationChannel, 7, "testMutableBubbleIntent", null, false, true); 13207 13208 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13209 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13210 13211 waitForIdle(); 13212 StatusBarNotification[] notifs = 13213 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 13214 assertEquals(1, notifs.length); 13215 } 13216 13217 @Test 13218 public void testImmutableDirectReplyActionIntent() throws Exception { 13219 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13220 NotificationRecord r = generateMessageBubbleNotifRecord(false, 13221 mTestNotificationChannel, 7, "testImmutableDirectReplyActionIntent", null, false, 13222 false); 13223 try { 13224 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13225 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13226 13227 waitForIdle(); 13228 fail("Allowed a direct reply with an immutable intent to be posted"); 13229 } catch (IllegalArgumentException e) { 13230 // good 13231 } 13232 } 13233 13234 @Test 13235 public void testMutableDirectReplyActionIntent() throws Exception { 13236 NotificationRecord r = generateMessageBubbleNotifRecord(false, 13237 mTestNotificationChannel, 7, "testMutableDirectReplyActionIntent", null, false, 13238 true); 13239 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13240 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13241 13242 waitForIdle(); 13243 StatusBarNotification[] notifs = 13244 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 13245 assertEquals(1, notifs.length); 13246 } 13247 13248 @Test 13249 public void testImmutableDirectReplyContextualActionIntent() throws Exception { 13250 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13251 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13252 13253 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13254 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 13255 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 13256 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 13257 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 13258 mActivityIntentImmutable).addRemoteInput(remoteInput) 13259 .build(); 13260 extraAction.add(replyAction); 13261 Bundle signals = new Bundle(); 13262 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 13263 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 13264 r.getUser()); 13265 r.addAdjustment(adjustment); 13266 r.applyAdjustments(); 13267 13268 try { 13269 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 13270 r.getSbn().getTag(), r, false, false); 13271 fail("Allowed a contextual direct reply with an immutable intent to be posted"); 13272 } catch (IllegalArgumentException e) { 13273 // good 13274 } 13275 } 13276 13277 @Test 13278 public void testMutableDirectReplyContextualActionIntent() throws Exception { 13279 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13280 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13281 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 13282 RemoteInput remoteInput = new RemoteInput.Builder("reply_key").setLabel("reply").build(); 13283 Icon icon = Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon); 13284 Notification.Action replyAction = new Notification.Action.Builder(icon, "Reply", 13285 mActivityIntent).addRemoteInput(remoteInput) 13286 .build(); 13287 extraAction.add(replyAction); 13288 Bundle signals = new Bundle(); 13289 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 13290 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 13291 r.getUser()); 13292 r.addAdjustment(adjustment); 13293 r.applyAdjustments(); 13294 13295 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 13296 r.getSbn().getTag(), r, false, false); 13297 } 13298 13299 @Test 13300 public void testImmutableActionIntent() throws Exception { 13301 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13302 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13303 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 13304 r.getSbn().getId(), r.getNotification(), r.getSbn().getUserId()); 13305 13306 waitForIdle(); 13307 StatusBarNotification[] notifs = 13308 mBinderService.getActiveNotifications(r.getSbn().getPackageName()); 13309 assertEquals(1, notifs.length); 13310 } 13311 13312 @Test 13313 public void testImmutableContextualActionIntent() throws Exception { 13314 when(mAmi.getPendingIntentFlags(any())).thenReturn(FLAG_IMMUTABLE | FLAG_ONE_SHOT); 13315 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13316 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 13317 ArrayList<Notification.Action> extraAction = new ArrayList<>(); 13318 extraAction.add(new Notification.Action(0, "hello", mActivityIntentImmutable)); 13319 Bundle signals = new Bundle(); 13320 signals.putParcelableArrayList(Adjustment.KEY_CONTEXTUAL_ACTIONS, extraAction); 13321 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, "", 13322 r.getUser()); 13323 r.addAdjustment(adjustment); 13324 r.applyAdjustments(); 13325 13326 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), r.getSbn().getId(), 13327 r.getSbn().getTag(), r, false, false); 13328 } 13329 13330 @Test 13331 public void testMigrateNotificationFilter_migrationAllAllowed() throws Exception { 13332 int uid = 9000; 13333 int[] userIds = new int[] {mUserId, 1000}; 13334 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13335 List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); 13336 for (int userId : userIds) { 13337 for (String pkg : disallowedApps) { 13338 when(mPackageManager.getPackageUid(pkg, 0, userId)).thenReturn(uid++); 13339 } 13340 } 13341 13342 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 13343 new NotificationListenerFilter()); 13344 13345 mBinderService.migrateNotificationFilter(null, 13346 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13347 disallowedApps); 13348 13349 ArgumentCaptor<NotificationListenerFilter> captor = 13350 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13351 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13352 13353 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13354 captor.getValue().getTypes()); 13355 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9000))); 13356 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9002))); 13357 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 9003))); 13358 13359 // hypothetical other user untouched 13360 assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 10000))); 13361 } 13362 13363 @Test 13364 public void testMigrateNotificationFilter_invalidPackage() throws Exception { 13365 int[] userIds = new int[] {mUserId, 1000}; 13366 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13367 List<String> disallowedApps = ImmutableList.of("apples", "bananas", "cherries"); 13368 for (int userId : userIds) { 13369 when(mPackageManager.getPackageUid("apples", 0, userId)).thenThrow( 13370 new RemoteException("")); 13371 when(mPackageManager.getPackageUid("bananas", 0, userId)).thenReturn(9000); 13372 when(mPackageManager.getPackageUid("cherries", 0, userId)).thenReturn(9001); 13373 } 13374 13375 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 13376 new NotificationListenerFilter()); 13377 13378 mBinderService.migrateNotificationFilter(null, 13379 FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13380 disallowedApps); 13381 13382 ArgumentCaptor<NotificationListenerFilter> captor = 13383 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13384 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13385 13386 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS | FLAG_FILTER_TYPE_ONGOING, 13387 captor.getValue().getTypes()); 13388 // valid values stay 13389 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("bananas", 9000))); 13390 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("cherries", 9001))); 13391 // don't store invalid values 13392 for (VersionedPackage vp : captor.getValue().getDisallowedPackages()) { 13393 assertNotEquals("apples", vp.getPackageName()); 13394 } 13395 } 13396 13397 @Test 13398 public void testMigrateNotificationFilter_noPreexistingFilter() throws Exception { 13399 int[] userIds = new int[] {mUserId}; 13400 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13401 List<String> disallowedApps = ImmutableList.of("apples"); 13402 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 13403 .thenReturn(1001); 13404 13405 when(mListeners.getNotificationListenerFilter(any())).thenReturn(null); 13406 13407 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 13408 disallowedApps); 13409 13410 ArgumentCaptor<NotificationListenerFilter> captor = 13411 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13412 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13413 13414 assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes()); 13415 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 13416 } 13417 13418 @Test 13419 public void testMigrateNotificationFilter_existingTypeFilter() throws Exception { 13420 int[] userIds = new int[] {mUserId}; 13421 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13422 List<String> disallowedApps = ImmutableList.of("apples"); 13423 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 13424 .thenReturn(1001); 13425 13426 when(mListeners.getNotificationListenerFilter(any())).thenReturn( 13427 new NotificationListenerFilter(FLAG_FILTER_TYPE_CONVERSATIONS, new ArraySet<>())); 13428 13429 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 13430 disallowedApps); 13431 13432 ArgumentCaptor<NotificationListenerFilter> captor = 13433 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13434 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13435 13436 // type isn't saved but pkg list is 13437 assertEquals(FLAG_FILTER_TYPE_CONVERSATIONS, captor.getValue().getTypes()); 13438 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 13439 } 13440 13441 @Test 13442 public void testMigrateNotificationFilter_existingPkgFilter() throws Exception { 13443 int[] userIds = new int[] {mUserId}; 13444 when(mUm.getProfileIds(anyInt(), anyBoolean())).thenReturn(userIds); 13445 List<String> disallowedApps = ImmutableList.of("apples"); 13446 when(mPackageManager.getPackageUid("apples", 0, mUserId)) 13447 .thenReturn(1001); 13448 13449 NotificationListenerFilter preexisting = new NotificationListenerFilter(); 13450 preexisting.addPackage(new VersionedPackage("test", 1002)); 13451 when(mListeners.getNotificationListenerFilter(any())).thenReturn(preexisting); 13452 13453 mBinderService.migrateNotificationFilter(null, FLAG_FILTER_TYPE_ONGOING, 13454 disallowedApps); 13455 13456 ArgumentCaptor<NotificationListenerFilter> captor = 13457 ArgumentCaptor.forClass(NotificationListenerFilter.class); 13458 verify(mListeners).setNotificationListenerFilter(any(), captor.capture()); 13459 13460 // type is saved but pkg list isn't 13461 assertEquals(FLAG_FILTER_TYPE_ONGOING, captor.getValue().getTypes()); 13462 assertTrue(captor.getValue().isPackageAllowed(new VersionedPackage("apples", 1001))); 13463 assertFalse(captor.getValue().isPackageAllowed(new VersionedPackage("test", 1002))); 13464 } 13465 13466 @Test 13467 public void getPackagesBypassingDnd_blocked() 13468 throws RemoteException, PackageManager.NameNotFoundException { 13469 13470 NotificationChannel channel1 = new NotificationChannel("id1", "name1", 13471 NotificationManager.IMPORTANCE_MAX); 13472 NotificationChannel channel2 = new NotificationChannel("id3", "name3", 13473 NotificationManager.IMPORTANCE_MAX); 13474 NotificationChannel channel3 = new NotificationChannel("id4", "name3", 13475 NotificationManager.IMPORTANCE_MAX); 13476 channel1.setBypassDnd(true); 13477 channel2.setBypassDnd(true); 13478 channel3.setBypassDnd(false); 13479 // has DND access, so can set bypassDnd attribute 13480 mService.mPreferencesHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1, true, 13481 /*has DND access*/ true, UID_N_MR1, false); 13482 mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel2, true, true, 13483 UID_P, false); 13484 mService.mPreferencesHelper.createNotificationChannel(PKG_P, UID_P, channel3, true, true, 13485 UID_P, false); 13486 13487 when(mPackageManager.getPackageUid(eq(PKG_P), anyLong(), anyInt())).thenReturn(UID_P); 13488 when(mPackageManager.getPackageUid(eq(PKG_N_MR1), anyLong(), anyInt())) 13489 .thenReturn(UID_N_MR1); 13490 when(mPermissionHelper.hasPermission(UID_N_MR1)).thenReturn(false); 13491 when(mPermissionHelper.hasPermission(UID_P)).thenReturn(true); 13492 13493 enableInteractAcrossUsers(); 13494 assertThat(mBinderService.getPackagesBypassingDnd(UserHandle.getUserId(UID_P)).getList()) 13495 .containsExactly(new ZenBypassingApp(PKG_P, false)); 13496 } 13497 13498 @Test 13499 public void testGetNotificationChannelsBypassingDnd_blocked() throws RemoteException { 13500 mService.setPreferencesHelper(mPreferencesHelper); 13501 13502 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13503 13504 assertThat(mBinderService.getNotificationChannelsBypassingDnd(mPkg, mUid).getList()) 13505 .isEmpty(); 13506 verify(mPreferencesHelper, never()).getNotificationChannelsBypassingDnd(mPkg, mUid); 13507 } 13508 13509 @Test 13510 public void testGetPackagesBypassingDnd_empty() throws RemoteException { 13511 mService.setPreferencesHelper(mPreferencesHelper); 13512 List<String> result = mBinderService.getPackagesBypassingDnd(mUserId).getList(); 13513 assertThat(result).isEmpty(); 13514 } 13515 13516 @Test 13517 public void testMatchesCallFilter_noPermissionShouldThrow() throws Exception { 13518 // set the testable NMS to not system uid/appid 13519 mService.isSystemUid = false; 13520 mService.isSystemAppId = false; 13521 13522 // make sure a caller without listener access or read_contacts permission can't call 13523 // matchesCallFilter. 13524 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 13525 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 13526 eq("android.permission.READ_CONTACTS"), anyString()); 13527 13528 try { 13529 // shouldn't matter what we're passing in, if we get past this line fail immediately 13530 ((INotificationManager) mService.mService).matchesCallFilter(null); 13531 fail("call to matchesCallFilter with no permissions should fail"); 13532 } catch (SecurityException e) { 13533 // pass 13534 } 13535 } 13536 13537 @Test 13538 public void testMatchesCallFilter_hasSystemPermission() throws Exception { 13539 // set the testable NMS to system uid 13540 mService.isSystemUid = true; 13541 13542 // make sure caller doesn't have listener access or read_contacts permission 13543 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 13544 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 13545 eq("android.permission.READ_CONTACTS"), anyString()); 13546 13547 try { 13548 ((INotificationManager) mService.mService).matchesCallFilter(null); 13549 // pass, but check that we actually checked for system permissions 13550 assertTrue(mService.countSystemChecks > 0); 13551 } catch (SecurityException e) { 13552 fail("call to matchesCallFilter with just system permissions should work"); 13553 } 13554 } 13555 13556 @Test 13557 public void testMatchesCallFilter_hasListenerPermission() throws Exception { 13558 mService.isSystemUid = false; 13559 mService.isSystemAppId = false; 13560 13561 // make sure a caller with only listener access and not read_contacts permission can call 13562 // matchesCallFilter. 13563 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(true); 13564 doThrow(new SecurityException()).when(mContext).enforceCallingPermission( 13565 eq("android.permission.READ_CONTACTS"), anyString()); 13566 13567 try { 13568 ((INotificationManager) mService.mService).matchesCallFilter(null); 13569 // pass, this is not a functionality test 13570 } catch (SecurityException e) { 13571 fail("call to matchesCallFilter with listener permissions should work"); 13572 } 13573 } 13574 13575 @Test 13576 public void testMatchesCallFilter_hasContactsPermission() throws Exception { 13577 mService.isSystemUid = false; 13578 mService.isSystemAppId = false; 13579 13580 // make sure a caller with only read_contacts permission and not listener access can call 13581 // matchesCallFilter. 13582 when(mListeners.hasAllowedListener(anyString(), anyInt())).thenReturn(false); 13583 doNothing().when(mContext).enforceCallingPermission( 13584 eq("android.permission.READ_CONTACTS"), anyString()); 13585 13586 try { 13587 ((INotificationManager) mService.mService).matchesCallFilter(null); 13588 // pass, this is not a functionality test 13589 } catch (SecurityException e) { 13590 fail("call to matchesCallFilter with listener permissions should work"); 13591 } 13592 } 13593 13594 @Test 13595 public void testMediaNotificationsBypassBlock() throws Exception { 13596 when(mAmi.getPendingIntentFlags(any(IIntentSender.class))) 13597 .thenReturn(FLAG_MUTABLE | FLAG_ONE_SHOT); 13598 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13599 13600 Notification.Builder nb = new Notification.Builder( 13601 mContext, mTestNotificationChannel.getId()) 13602 .setContentTitle("foo") 13603 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13604 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13605 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13606 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13607 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13608 13609 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13610 13611 // normal blocked notifications - blocked 13612 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13613 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13614 13615 // just using the style - blocked 13616 nb.setStyle(new Notification.MediaStyle()); 13617 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13618 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13619 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13620 13621 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13622 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13623 13624 // using the style, but incorrect type in session - blocked 13625 nb.setStyle(new Notification.MediaStyle()); 13626 Bundle extras = new Bundle(); 13627 extras.putParcelable(Notification.EXTRA_MEDIA_SESSION, new Intent()); 13628 nb.addExtras(extras); 13629 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13630 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13631 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13632 13633 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13634 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13635 13636 // style + media session - bypasses block 13637 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); 13638 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13639 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13640 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13641 13642 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13643 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13644 } 13645 13646 @Test 13647 public void testMediaNotificationsBypassBlock_atPost() throws Exception { 13648 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 13649 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13650 13651 Notification.Builder nb = new Notification.Builder( 13652 mContext, mTestNotificationChannel.getId()) 13653 .setContentTitle("foo") 13654 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13655 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13656 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13657 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13658 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13659 13660 when(mPermissionHelper.hasPermission(anyInt())).thenReturn(false); 13661 13662 mService.addEnqueuedNotification(r); 13663 NotificationManagerService.PostNotificationRunnable runnable = 13664 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 13665 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 13666 runnable.run(); 13667 waitForIdle(); 13668 13669 verify(mUsageStats).registerBlocked(any()); 13670 verify(mUsageStats, never()).registerPostedByApp(any()); 13671 13672 // just using the style - blocked 13673 mService.clearNotifications(); 13674 reset(mUsageStats); 13675 nb.setStyle(new Notification.MediaStyle()); 13676 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13677 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13678 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13679 13680 mService.addEnqueuedNotification(r); 13681 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 13682 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 13683 runnable.run(); 13684 waitForIdle(); 13685 13686 verify(mUsageStats).registerBlocked(any()); 13687 verify(mUsageStats, never()).registerPostedByApp(any()); 13688 13689 // style + media session - bypasses block 13690 mService.clearNotifications(); 13691 reset(mUsageStats); 13692 nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class))); 13693 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13694 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13695 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13696 13697 mService.addEnqueuedNotification(r); 13698 runnable = mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), 13699 r.getUid(), mPostNotificationTrackerFactory.newTracker(null)); 13700 runnable.run(); 13701 waitForIdle(); 13702 13703 verify(mUsageStats, never()).registerBlocked(any()); 13704 verify(mUsageStats).registerPostedByApp(any()); 13705 } 13706 13707 @Test 13708 public void testCallNotificationsBypassBlock() throws Exception { 13709 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13710 13711 Notification.Builder nb = new Notification.Builder( 13712 mContext, mTestNotificationChannel.getId()) 13713 .setContentTitle("foo") 13714 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13715 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13716 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13717 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13718 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13719 13720 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13721 13722 // normal blocked notifications - blocked 13723 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13724 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13725 13726 // just using the style - blocked 13727 Person person = new Person.Builder() 13728 .setName("caller") 13729 .build(); 13730 nb.setStyle(Notification.CallStyle.forOngoingCall( 13731 person, mActivityIntent)); 13732 nb.setFullScreenIntent(mActivityIntent, true); 13733 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13734 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13735 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13736 13737 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13738 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isFalse(); 13739 13740 // style + managed call - bypasses block 13741 when(mTelecomManager.isInManagedCall()).thenReturn(true); 13742 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13743 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13744 13745 // style + self managed call - bypasses block 13746 when(mTelecomManager.isInSelfManagedCall( 13747 r.getSbn().getPackageName(), UserHandle.ALL)).thenReturn(true); 13748 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13749 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 13750 13751 // set telecom manager to null - blocked 13752 mService.setTelecomManager(null); 13753 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13754 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 13755 .isFalse(); 13756 13757 // set telecom feature to false - blocked 13758 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false); 13759 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13760 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 13761 .isFalse(); 13762 13763 // telecom manager is not ready - blocked 13764 mService.setTelecomManager(mTelecomManager); 13765 when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready")); 13766 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 13767 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)) 13768 .isFalse(); 13769 } 13770 13771 @Test 13772 public void testCallNotificationsBypassBlock_atPost() throws Exception { 13773 when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false); 13774 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 13775 13776 Notification.Builder nb = 13777 new Notification.Builder(mContext, mTestNotificationChannel.getId()) 13778 .setContentTitle("foo") 13779 .setSmallIcon(android.R.drawable.sym_def_app_icon) 13780 .addAction(new Notification.Action.Builder(null, "test", null).build()); 13781 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 13782 nb.build(), UserHandle.getUserHandleForUid(mUid), null, 0); 13783 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13784 13785 when(mPermissionHelper.hasPermission(mUid)).thenReturn(false); 13786 13787 // normal blocked notifications - blocked 13788 mService.addEnqueuedNotification(r); 13789 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13790 mPostNotificationTrackerFactory.newTracker(null)).run(); 13791 waitForIdle(); 13792 13793 verify(mUsageStats).registerBlocked(any()); 13794 verify(mUsageStats, never()).registerPostedByApp(any()); 13795 13796 // just using the style - blocked 13797 mService.clearNotifications(); 13798 reset(mUsageStats); 13799 Person person = new Person.Builder().setName("caller").build(); 13800 nb.setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)); 13801 nb.setFullScreenIntent(mActivityIntent, true); 13802 sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, nb.build(), 13803 UserHandle.getUserHandleForUid(mUid), null, 0); 13804 r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 13805 13806 mService.addEnqueuedNotification(r); 13807 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13808 mPostNotificationTrackerFactory.newTracker(null)).run(); 13809 waitForIdle(); 13810 13811 verify(mUsageStats).registerBlocked(any()); 13812 verify(mUsageStats, never()).registerPostedByApp(any()); 13813 13814 // style + managed call - bypasses block 13815 mService.clearNotifications(); 13816 reset(mUsageStats); 13817 when(mTelecomManager.isInManagedCall()).thenReturn(true); 13818 13819 mService.addEnqueuedNotification(r); 13820 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13821 mPostNotificationTrackerFactory.newTracker(null)).run(); 13822 waitForIdle(); 13823 13824 verify(mUsageStats, never()).registerBlocked(any()); 13825 verify(mUsageStats).registerPostedByApp(any()); 13826 13827 // style + self managed call - bypasses block 13828 mService.clearNotifications(); 13829 reset(mUsageStats); 13830 when(mTelecomManager.isInSelfManagedCall(r.getSbn().getPackageName(), UserHandle.ALL)) 13831 .thenReturn(true); 13832 13833 mService.addEnqueuedNotification(r); 13834 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13835 mPostNotificationTrackerFactory.newTracker(null)).run(); 13836 waitForIdle(); 13837 13838 verify(mUsageStats, never()).registerBlocked(any()); 13839 verify(mUsageStats).registerPostedByApp(any()); 13840 13841 // set telecom manager to null - notifications should be blocked 13842 // but post notifications runnable should not crash 13843 mService.clearNotifications(); 13844 reset(mUsageStats); 13845 mService.setTelecomManager(null); 13846 13847 mService.addEnqueuedNotification(r); 13848 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13849 mPostNotificationTrackerFactory.newTracker(null)).run(); 13850 waitForIdle(); 13851 13852 verify(mUsageStats).registerBlocked(any()); 13853 verify(mUsageStats, never()).registerPostedByApp(any()); 13854 13855 // set FEATURE_TELECOM to false - notifications should be blocked 13856 // but post notifications runnable should not crash 13857 mService.setTelecomManager(mTelecomManager); 13858 when(mPackageManagerClient.hasSystemFeature(FEATURE_TELECOM)).thenReturn(false); 13859 reset(mUsageStats); 13860 mService.setTelecomManager(null); 13861 13862 mService.addEnqueuedNotification(r); 13863 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13864 mPostNotificationTrackerFactory.newTracker(null)).run(); 13865 waitForIdle(); 13866 13867 verify(mUsageStats).registerBlocked(any()); 13868 verify(mUsageStats, never()).registerPostedByApp(any()); 13869 13870 // telecom is not ready - notifications should be blocked but no crashes 13871 mService.setTelecomManager(mTelecomManager); 13872 when(mTelecomManager.isInCall()).thenThrow(new IllegalStateException("not ready")); 13873 reset(mUsageStats); 13874 13875 mService.addEnqueuedNotification(r); 13876 mService.new PostNotificationRunnable(r.getKey(), r.getSbn().getPackageName(), r.getUid(), 13877 mPostNotificationTrackerFactory.newTracker(null)).run(); 13878 waitForIdle(); 13879 13880 verify(mUsageStats).registerBlocked(any()); 13881 verify(mUsageStats, never()).registerPostedByApp(any()); 13882 } 13883 13884 @Test 13885 public void testGetAllUsersNotificationPermissions() { 13886 // In this case, there are multiple users each with notification permissions (and also, 13887 // for good measure, some without). 13888 // make sure the collection returned contains info for all of them 13889 final List<UserInfo> userInfos = new ArrayList<>(); 13890 userInfos.add(new UserInfo(0, "user0", 0)); 13891 userInfos.add(new UserInfo(1, "user1", 0)); 13892 userInfos.add(new UserInfo(2, "user2", 0)); 13893 when(mUm.getUsers()).thenReturn(userInfos); 13894 13895 // construct the permissions for each of them 13896 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> permissions0 = new ArrayMap<>(), 13897 permissions1 = new ArrayMap<>(); 13898 permissions0.put(new Pair<>(10, "package1"), new Pair<>(true, false)); 13899 permissions0.put(new Pair<>(20, "package2"), new Pair<>(false, true)); 13900 permissions1.put(new Pair<>(11, "package1"), new Pair<>(false, false)); 13901 permissions1.put(new Pair<>(21, "package2"), new Pair<>(true, true)); 13902 when(mPermissionHelper.getNotificationPermissionValues(0)).thenReturn(permissions0); 13903 when(mPermissionHelper.getNotificationPermissionValues(1)).thenReturn(permissions1); 13904 when(mPermissionHelper.getNotificationPermissionValues(2)).thenReturn(new ArrayMap<>()); 13905 13906 ArrayMap<Pair<Integer, String>, Pair<Boolean, Boolean>> combinedPermissions = 13907 mService.getAllUsersNotificationPermissions(); 13908 assertTrue(combinedPermissions.get(new Pair<>(10, "package1")).first); 13909 assertFalse(combinedPermissions.get(new Pair<>(10, "package1")).second); 13910 assertFalse(combinedPermissions.get(new Pair<>(20, "package2")).first); 13911 assertTrue(combinedPermissions.get(new Pair<>(20, "package2")).second); 13912 assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).first); 13913 assertFalse(combinedPermissions.get(new Pair<>(11, "package1")).second); 13914 assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).first); 13915 assertTrue(combinedPermissions.get(new Pair<>(21, "package2")).second); 13916 } 13917 13918 @Test 13919 public void testGetActiveNotification_filtersUsers() throws Exception { 13920 when(mUm.getProfileIds(mUserId, false)).thenReturn(new int[]{mUserId, 10}); 13921 13922 NotificationRecord nr0 = 13923 generateNotificationRecord(mTestNotificationChannel, mUserId); 13924 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 13925 nr0.getSbn().getId(), nr0.getSbn().getNotification(), nr0.getSbn().getUserId()); 13926 13927 NotificationRecord nr10 = 13928 generateNotificationRecord(mTestNotificationChannel, 10); 13929 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag10", 13930 nr10.getSbn().getId(), nr10.getSbn().getNotification(), nr10.getSbn().getUserId()); 13931 13932 NotificationRecord nr11 = 13933 generateNotificationRecord(mTestNotificationChannel, 11); 13934 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag11", 13935 nr11.getSbn().getId(), nr11.getSbn().getNotification(), nr11.getSbn().getUserId()); 13936 waitForIdle(); 13937 13938 StatusBarNotification[] notifs = mBinderService.getActiveNotifications(mPkg); 13939 assertEquals(2, notifs.length); 13940 for (StatusBarNotification sbn : notifs) { 13941 if (sbn.getUserId() == 11) { 13942 fail("leaked data across users"); 13943 } 13944 } 13945 } 13946 13947 @Test 13948 public void testGetActiveNotificationsFromListener_redactNotification() throws Exception { 13949 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 13950 NotificationRecord r = 13951 generateNotificationRecord(mTestNotificationChannel, 0, 0); 13952 mService.addNotification(r); 13953 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 13954 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 13955 StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1); 13956 when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted); 13957 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13958 info.userid = 0; 13959 when(info.isSameUser(anyInt())).thenReturn(true); 13960 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 13961 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 13962 List<StatusBarNotification> notifications = mBinderService 13963 .getActiveNotificationsFromListener(mock(INotificationListener.class), null, -1) 13964 .getList(); 13965 13966 boolean foundRedactedSbn = false; 13967 for (StatusBarNotification sbn: notifications) { 13968 String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString(); 13969 if (REDACTED_TEXT.equals(text)) { 13970 foundRedactedSbn = true; 13971 break; 13972 } 13973 } 13974 assertTrue("expect to find a redacted notification", foundRedactedSbn); 13975 } 13976 13977 @Test 13978 public void testGetSnoozedNotificationsFromListener_redactNotification() throws Exception { 13979 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 13980 NotificationRecord r = 13981 generateNotificationRecord(mTestNotificationChannel, 0, 0); 13982 when(mSnoozeHelper.getSnoozed()).thenReturn(List.of(r)); 13983 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 13984 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 13985 StatusBarNotification redacted = generateRedactedSbn(mTestNotificationChannel, 1, 1); 13986 when(mListeners.redactStatusBarNotification(any())).thenReturn(redacted); 13987 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 13988 info.userid = 0; 13989 when(info.isSameUser(anyInt())).thenReturn(true); 13990 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 13991 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 13992 List<StatusBarNotification> notifications = mBinderService 13993 .getSnoozedNotificationsFromListener(mock(INotificationListener.class), -1) 13994 .getList(); 13995 13996 boolean foundRedactedSbn = false; 13997 for (StatusBarNotification sbn: notifications) { 13998 String text = sbn.getNotification().extras.getCharSequence(EXTRA_TEXT).toString(); 13999 if (REDACTED_TEXT.equals(text)) { 14000 foundRedactedSbn = true; 14001 break; 14002 } 14003 } 14004 assertTrue("expect to find a redacted notification", foundRedactedSbn); 14005 } 14006 14007 @Test 14008 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14009 public void testCancelAutogroupSummary_cancelsAllChildren() throws Exception { 14010 final String originalGroupName = "originalGroup"; 14011 final String aggregateGroupName = "Aggregate_Test"; 14012 final int summaryId = Integer.MAX_VALUE; 14013 // Add 2 group notifications without a summary 14014 NotificationRecord nr0 = 14015 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 14016 NotificationRecord nr1 = 14017 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 14018 mService.addNotification(nr0); 14019 mService.addNotification(nr1); 14020 mService.mSummaryByGroupKey.remove(nr0.getGroupKey()); 14021 14022 // GroupHelper is a mock, so make the calls it would make 14023 // Add aggregate group summary 14024 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 14025 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 14026 nr0.getChannel().getId()); 14027 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 14028 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 14029 mService.addNotification(aggregateSummary); 14030 nr0.setOverrideGroupKey(aggregateGroupName); 14031 nr1.setOverrideGroupKey(aggregateGroupName); 14032 final String fullAggregateGroupKey = nr0.getGroupKey(); 14033 14034 // Check that the aggregate group summary was created 14035 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 14036 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 14037 nr0.getChannel().getId()); 14038 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 14039 14040 // Cancel aggregate group summary 14041 mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(), 14042 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId()); 14043 waitForIdle(); 14044 14045 // Check that child notifications are also removed 14046 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary)); 14047 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0)); 14048 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1)); 14049 14050 // Make sure the summary was removed and not re-posted 14051 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 14052 } 14053 14054 @Test 14055 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14056 public void testCancelAutogroupSummary_forceGrouping_cancelsAllChildren() throws Exception { 14057 final String originalGroupName = "originalGroup"; 14058 final String aggregateGroupName = "Aggregate_Test"; 14059 final int summaryId = Integer.MAX_VALUE; 14060 // Add 2 group notifications without a summary 14061 NotificationRecord nr0 = 14062 generateNotificationRecord(mTestNotificationChannel, 0, originalGroupName, false); 14063 NotificationRecord nr1 = 14064 generateNotificationRecord(mTestNotificationChannel, 1, originalGroupName, false); 14065 mService.addNotification(nr0); 14066 mService.addNotification(nr1); 14067 mService.mSummaryByGroupKey.remove(nr0.getGroupKey()); 14068 14069 // GroupHelper is a mock, so make the calls it would make 14070 // Add aggregate group summary 14071 NotificationAttributes attr = new NotificationAttributes(GroupHelper.BASE_FLAGS, 14072 mock(Icon.class), 0, VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, 14073 nr0.getChannel().getId()); 14074 NotificationRecord aggregateSummary = mService.createAutoGroupSummary(nr0.getUserId(), 14075 nr0.getSbn().getPackageName(), nr0.getKey(), aggregateGroupName, summaryId, attr); 14076 mService.addNotification(aggregateSummary); 14077 nr0.setOverrideGroupKey(aggregateGroupName); 14078 nr1.setOverrideGroupKey(aggregateGroupName); 14079 final String fullAggregateGroupKey = nr0.getGroupKey(); 14080 14081 // Check that the aggregate group summary was created 14082 assertThat(aggregateSummary.getNotification().getGroup()).isEqualTo(aggregateGroupName); 14083 assertThat(aggregateSummary.getNotification().getChannelId()).isEqualTo( 14084 nr0.getChannel().getId()); 14085 assertThat(mService.mSummaryByGroupKey.containsKey(fullAggregateGroupKey)).isTrue(); 14086 14087 // Cancel aggregate group summary 14088 mBinderService.cancelNotificationWithTag(mPkg, mPkg, aggregateSummary.getSbn().getTag(), 14089 aggregateSummary.getSbn().getId(), aggregateSummary.getSbn().getUserId()); 14090 waitForIdle(); 14091 14092 // Check that child notifications are also removed 14093 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(aggregateSummary), any(), 14094 eq(false)); 14095 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr0), any(), eq(false)); 14096 verify(mGroupHelper, times(1)).onNotificationRemoved(eq(nr1), any(), eq(false)); 14097 14098 // Make sure the summary was removed and not re-posted 14099 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 14100 } 14101 14102 @Test 14103 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14104 public void testUngroupingOngoingAutoSummary() throws Exception { 14105 NotificationRecord nr0 = 14106 generateNotificationRecord(mTestNotificationChannel, 0); 14107 NotificationRecord nr1 = 14108 generateNotificationRecord(mTestNotificationChannel, 0); 14109 nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT; 14110 14111 mService.addNotification(nr0); 14112 mService.addNotification(nr1); 14113 14114 // grouphelper is a mock here, so make the calls it would make 14115 14116 // add summary 14117 NotificationAttributes attr = new NotificationAttributes( 14118 GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0, 14119 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14120 mService.addNotification( 14121 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14122 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14123 14124 // cancel both children 14125 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(), 14126 nr0.getSbn().getId(), nr0.getSbn().getUserId()); 14127 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(), 14128 nr1.getSbn().getId(), nr1.getSbn().getUserId()); 14129 waitForIdle(); 14130 14131 // group helper would send 'remove summary' event 14132 mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(), 14133 AUTOGROUP_KEY); 14134 waitForIdle(); 14135 14136 // make sure the summary was removed and not re-posted 14137 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 14138 } 14139 14140 @Test 14141 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14142 public void testUngroupingOngoingAutoSummary_forceGrouping() throws Exception { 14143 NotificationRecord nr0 = 14144 generateNotificationRecord(mTestNotificationChannel, 0); 14145 NotificationRecord nr1 = 14146 generateNotificationRecord(mTestNotificationChannel, 0); 14147 nr1.getSbn().getNotification().flags |= FLAG_ONGOING_EVENT; 14148 14149 mService.addNotification(nr0); 14150 mService.addNotification(nr1); 14151 14152 // grouphelper is a mock here, so make the calls it would make 14153 14154 // add summary 14155 NotificationAttributes attr = new NotificationAttributes( 14156 GroupHelper.BASE_FLAGS | FLAG_ONGOING_EVENT, mock(Icon.class), 0, 14157 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14158 mService.addNotification( 14159 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14160 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14161 14162 // cancel both children 14163 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0.getSbn().getTag(), 14164 nr0.getSbn().getId(), nr0.getSbn().getUserId()); 14165 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1.getSbn().getTag(), 14166 nr1.getSbn().getId(), nr1.getSbn().getUserId()); 14167 waitForIdle(); 14168 14169 // group helper would send 'remove summary' event 14170 mService.clearAutogroupSummaryLocked(nr1.getUserId(), nr1.getSbn().getPackageName(), 14171 AUTOGROUP_KEY); 14172 waitForIdle(); 14173 14174 // make sure the summary was removed and not re-posted 14175 assertThat(mService.getNotificationRecordCount()).isEqualTo(0); 14176 } 14177 14178 @Test 14179 @DisableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14180 public void testUngroupingAutoSummary_differentUsers() throws Exception { 14181 NotificationRecord nr0 = 14182 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM); 14183 NotificationRecord nr1 = 14184 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM); 14185 14186 // add notifications + summary for USER_SYSTEM 14187 NotificationAttributes attr = new NotificationAttributes( 14188 GroupHelper.BASE_FLAGS, mock(Icon.class), 0, 14189 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14190 mService.addNotification(nr0); 14191 mService.addNotification(nr1); 14192 mService.addNotification( 14193 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14194 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14195 14196 // add notifications + summary for USER_ALL 14197 NotificationRecord nr0_all = 14198 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL); 14199 NotificationRecord nr1_all = 14200 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL); 14201 14202 mService.addNotification(nr0_all); 14203 mService.addNotification(nr1_all); 14204 mService.addNotification( 14205 mService.createAutoGroupSummary(nr0_all.getUserId(), 14206 nr0_all.getSbn().getPackageName(), 14207 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14208 14209 // cancel both children for USER_ALL 14210 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(), 14211 nr0_all.getSbn().getId(), UserHandle.USER_ALL); 14212 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(), 14213 nr1_all.getSbn().getId(), UserHandle.USER_ALL); 14214 waitForIdle(); 14215 14216 // group helper would send 'remove summary' event 14217 mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL, 14218 nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY); 14219 waitForIdle(); 14220 14221 // make sure the right summary was removed 14222 assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(), 14223 UserHandle.USER_ALL, 0, null)).isEqualTo(0); 14224 14225 // the USER_SYSTEM notifications + summary were not removed 14226 assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(), 14227 USER_SYSTEM, 0, null)).isEqualTo(3); 14228 } 14229 14230 @Test 14231 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 14232 public void testUngroupingAutoSummary_differentUsers_forceGrouping() throws Exception { 14233 NotificationRecord nr0 = 14234 generateNotificationRecord(mTestNotificationChannel, 0, USER_SYSTEM); 14235 NotificationRecord nr1 = 14236 generateNotificationRecord(mTestNotificationChannel, 1, USER_SYSTEM); 14237 14238 // add notifications + summary for USER_SYSTEM 14239 NotificationAttributes attr = new NotificationAttributes( 14240 GroupHelper.BASE_FLAGS, mock(Icon.class), 0, 14241 VISIBILITY_PRIVATE, GROUP_ALERT_CHILDREN, DEFAULT_CHANNEL_ID); 14242 mService.addNotification(nr0); 14243 mService.addNotification(nr1); 14244 mService.addNotification( 14245 mService.createAutoGroupSummary(nr1.getUserId(), nr1.getSbn().getPackageName(), 14246 nr1.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14247 14248 // add notifications + summary for USER_ALL 14249 NotificationRecord nr0_all = 14250 generateNotificationRecord(mTestNotificationChannel, 2, UserHandle.USER_ALL); 14251 NotificationRecord nr1_all = 14252 generateNotificationRecord(mTestNotificationChannel, 3, UserHandle.USER_ALL); 14253 14254 mService.addNotification(nr0_all); 14255 mService.addNotification(nr1_all); 14256 mService.addNotification( 14257 mService.createAutoGroupSummary(nr0_all.getUserId(), 14258 nr0_all.getSbn().getPackageName(), 14259 nr0_all.getKey(), AUTOGROUP_KEY, Integer.MAX_VALUE, attr)); 14260 14261 // cancel both children for USER_ALL 14262 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr0_all.getSbn().getTag(), 14263 nr0_all.getSbn().getId(), UserHandle.USER_ALL); 14264 mBinderService.cancelNotificationWithTag(mPkg, mPkg, nr1_all.getSbn().getTag(), 14265 nr1_all.getSbn().getId(), UserHandle.USER_ALL); 14266 waitForIdle(); 14267 14268 // group helper would send 'remove summary' event 14269 mService.clearAutogroupSummaryLocked(UserHandle.USER_ALL, 14270 nr0_all.getSbn().getPackageName(), AUTOGROUP_KEY); 14271 waitForIdle(); 14272 14273 // make sure the right summary was removed 14274 assertThat(mService.getNotificationCount(nr0_all.getSbn().getPackageName(), 14275 UserHandle.USER_ALL, 0, null)).isEqualTo(0); 14276 14277 // the USER_SYSTEM notifications + summary were not removed 14278 assertThat(mService.getNotificationCount(nr0.getSbn().getPackageName(), 14279 USER_SYSTEM, 0, null)).isEqualTo(3); 14280 } 14281 14282 @Test 14283 public void testStrongAuthTracker_isInLockDownMode() { 14284 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 14285 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 14286 mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); 14287 assertTrue(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); 14288 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(mContext.getUserId()); 14289 mStrongAuthTracker.onStrongAuthRequiredChanged(mContext.getUserId()); 14290 assertFalse(mStrongAuthTracker.isInLockDownMode(mContext.getUserId())); 14291 } 14292 14293 @Test 14294 public void testCancelAndPostNotificationsWhenEnterAndExitLockDownMode() { 14295 // post 2 notifications from 2 packages 14296 NotificationRecord pkgA = new NotificationRecord(mContext, 14297 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14298 mService.addNotification(pkgA); 14299 NotificationRecord pkgB = new NotificationRecord(mContext, 14300 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 14301 mService.addNotification(pkgB); 14302 14303 // when entering the lockdown mode, cancel the 2 notifications. 14304 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 14305 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 14306 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14307 assertTrue(mStrongAuthTracker.isInLockDownMode(0)); 14308 14309 // the notifyRemovedLocked function is called twice due to REASON_LOCKDOWN. 14310 ArgumentCaptor<Integer> captor = ArgumentCaptor.forClass(Integer.class); 14311 verify(mListeners, times(2)).notifyRemovedLocked(any(), captor.capture(), any()); 14312 assertEquals(REASON_LOCKDOWN, captor.getValue().intValue()); 14313 14314 // exit lockdown mode. 14315 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); 14316 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14317 assertFalse(mStrongAuthTracker.isInLockDownMode(0)); 14318 14319 // the notifyPostedLocked function is called twice. 14320 verify(mWorkerHandler, times(2)).postDelayed(any(Runnable.class), anyLong()); 14321 } 14322 14323 @Test 14324 public void testMakeRankingUpdateLockedInLockDownMode() { 14325 // post 2 notifications from a same package 14326 NotificationRecord pkgA = new NotificationRecord(mContext, 14327 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14328 mService.addNotification(pkgA); 14329 NotificationRecord pkgB = new NotificationRecord(mContext, 14330 generateSbn("a", 1000, 9, 1), mTestNotificationChannel); 14331 mService.addNotification(pkgB); 14332 14333 mService.setIsVisibleToListenerReturnValue(true); 14334 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 14335 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 14336 assertEquals(2, nru.getRankingMap().getOrderedKeys().length); 14337 14338 // when only user 0 entering the lockdown mode, its notification will be suppressed. 14339 mStrongAuthTracker.setGetStrongAuthForUserReturnValue( 14340 STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN); 14341 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14342 assertTrue(mStrongAuthTracker.isInLockDownMode(0)); 14343 assertFalse(mStrongAuthTracker.isInLockDownMode(1)); 14344 14345 nru = mService.makeRankingUpdateLocked(info); 14346 assertEquals(1, nru.getRankingMap().getOrderedKeys().length); 14347 14348 // User 0 exits lockdown mode. Its notification will be resumed. 14349 mStrongAuthTracker.setGetStrongAuthForUserReturnValue(0); 14350 mStrongAuthTracker.onStrongAuthRequiredChanged(0); 14351 assertFalse(mStrongAuthTracker.isInLockDownMode(0)); 14352 assertFalse(mStrongAuthTracker.isInLockDownMode(1)); 14353 14354 nru = mService.makeRankingUpdateLocked(info); 14355 assertEquals(2, nru.getRankingMap().getOrderedKeys().length); 14356 } 14357 14358 @Test 14359 public void testMakeRankingUpdate_redactsIfRecordSensitiveAndServiceUntrusted() { 14360 mSetFlagsRule.enableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 14361 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 14362 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 14363 NotificationRecord pkgA = new NotificationRecord(mContext, 14364 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14365 addSmartActionsAndReplies(pkgA); 14366 mService.addNotification(pkgA); 14367 NotificationRecord pkgB = new NotificationRecord(mContext, 14368 generateSbn("b", 1001, 9, 0), mTestNotificationChannel); 14369 addSmartActionsAndReplies(pkgB); 14370 mService.addNotification(pkgB); 14371 14372 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 14373 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 14374 when(info.isSameUser(anyInt())).thenReturn(true); 14375 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 14376 NotificationListenerService.Ranking ranking = 14377 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14378 assertEquals(0, ranking.getSmartActions().size()); 14379 assertEquals(0, ranking.getSmartReplies().size()); 14380 NotificationListenerService.Ranking ranking2 = 14381 nru.getRankingMap().getRawRankingObject(pkgB.getSbn().getKey()); 14382 assertEquals(0, ranking2.getSmartActions().size()); 14383 assertEquals(0, ranking2.getSmartReplies().size()); 14384 } 14385 14386 private NotificationRecord getSensitiveNotificationRecord() { 14387 NotificationRecord record = new NotificationRecord(mContext, 14388 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14389 Bundle signals = new Bundle(); 14390 signals.putBoolean(Adjustment.KEY_SENSITIVE_CONTENT, true); 14391 Adjustment adjustment = new Adjustment("a", record.getKey(), signals, "", 0); 14392 record.addAdjustment(adjustment); 14393 record.applyAdjustments(); 14394 return record; 14395 } 14396 14397 @Test 14398 public void testMakeRankingUpdate_doestntRedactIfFlagDisabled() { 14399 mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 14400 when(mListeners.isUidTrusted(anyInt())).thenReturn(false); 14401 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 14402 NotificationRecord pkgA = getSensitiveNotificationRecord(); 14403 addSmartActionsAndReplies(pkgA); 14404 14405 mService.addNotification(pkgA); 14406 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 14407 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 14408 when(info.isSameUser(anyInt())).thenReturn(true); 14409 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 14410 NotificationListenerService.Ranking ranking = 14411 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14412 assertEquals(1, ranking.getSmartActions().size()); 14413 assertEquals(1, ranking.getSmartReplies().size()); 14414 } 14415 14416 @Test 14417 public void testMakeRankingUpdate_doesntRedactIfNotSensitiveOrServiceTrusted() { 14418 mSetFlagsRule.disableFlags(FLAG_REDACT_SENSITIVE_NOTIFICATIONS_FROM_UNTRUSTED_LISTENERS); 14419 NotificationRecord pkgA = new NotificationRecord(mContext, 14420 generateSbn("a", 1000, 9, 0), mTestNotificationChannel); 14421 addSmartActionsAndReplies(pkgA); 14422 14423 mService.addNotification(pkgA); 14424 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 14425 when(info.enabledAndUserMatches(anyInt())).thenReturn(true); 14426 when(info.isSameUser(anyInt())).thenReturn(true); 14427 14428 // No sensitive content, no redaction 14429 when(mListeners.isUidTrusted(eq(1000))).thenReturn(false); 14430 when(mListeners.hasSensitiveContent(any())).thenReturn(false); 14431 NotificationRankingUpdate nru = mService.makeRankingUpdateLocked(info); 14432 NotificationListenerService.Ranking ranking = 14433 nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14434 assertEquals(1, ranking.getSmartActions().size()); 14435 assertEquals(1, ranking.getSmartReplies().size()); 14436 14437 // trusted listener, no redaction 14438 when(mListeners.isUidTrusted(eq(1000))).thenReturn(true); 14439 when(mListeners.hasSensitiveContent(any())).thenReturn(true); 14440 nru = mService.makeRankingUpdateLocked(info); 14441 ranking = nru.getRankingMap().getRawRankingObject(pkgA.getSbn().getKey()); 14442 assertEquals(1, ranking.getSmartActions().size()); 14443 assertEquals(1, ranking.getSmartReplies().size()); 14444 } 14445 14446 private void addSmartActionsAndReplies(NotificationRecord record) { 14447 Bundle b = new Bundle(); 14448 ArrayList<Notification.Action> actions = new ArrayList<>(); 14449 actions.add(new Notification.Action(0, "", null)); 14450 b.putParcelableArrayList(KEY_CONTEXTUAL_ACTIONS, actions); 14451 ArrayList<CharSequence> replies = new ArrayList<>(List.of("test")); 14452 b.putCharSequenceArrayList(KEY_TEXT_REPLIES, replies); 14453 Adjustment a = new Adjustment(record.getSbn().getPackageName(), record.getSbn().getKey(), 14454 b, "", record.getUserId()); 14455 record.addAdjustment(a); 14456 record.applyAdjustments(); 14457 } 14458 14459 @Test 14460 public void testMaybeShowReviewPermissionsNotification_flagOff() { 14461 mService.setShowReviewPermissionsNotification(false); 14462 reset(mMockNm); 14463 14464 // If state is SHOULD_SHOW, it would show, but not if the flag is off! 14465 Settings.Global.putInt(mContext.getContentResolver(), 14466 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14467 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 14468 mService.maybeShowInitialReviewPermissionsNotification(); 14469 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14470 } 14471 14472 @Test 14473 public void testMaybeShowReviewPermissionsNotification_unknown() { 14474 mService.setShowReviewPermissionsNotification(true); 14475 reset(mMockNm); 14476 14477 // Set up various possible states of the settings int and confirm whether or not the 14478 // notification is shown as expected 14479 14480 // Initial state: default/unknown setting, make sure nothing happens 14481 Settings.Global.putInt(mContext.getContentResolver(), 14482 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14483 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN); 14484 mService.maybeShowInitialReviewPermissionsNotification(); 14485 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14486 } 14487 14488 @Test 14489 public void testMaybeShowReviewPermissionsNotification_shouldShow() { 14490 mService.setShowReviewPermissionsNotification(true); 14491 reset(mMockNm); 14492 14493 // If state is SHOULD_SHOW, it ... should show 14494 Settings.Global.putInt(mContext.getContentResolver(), 14495 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14496 NotificationManagerService.REVIEW_NOTIF_STATE_SHOULD_SHOW); 14497 mService.maybeShowInitialReviewPermissionsNotification(); 14498 verify(mMockNm, times(1)).notify(eq(TAG), 14499 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 14500 any(Notification.class)); 14501 } 14502 14503 @Test 14504 public void testMaybeShowReviewPermissionsNotification_alreadyShown() { 14505 mService.setShowReviewPermissionsNotification(true); 14506 reset(mMockNm); 14507 14508 // If state is either USER_INTERACTED or DISMISSED, we should not show this on boot 14509 Settings.Global.putInt(mContext.getContentResolver(), 14510 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14511 NotificationManagerService.REVIEW_NOTIF_STATE_USER_INTERACTED); 14512 mService.maybeShowInitialReviewPermissionsNotification(); 14513 14514 Settings.Global.putInt(mContext.getContentResolver(), 14515 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14516 NotificationManagerService.REVIEW_NOTIF_STATE_DISMISSED); 14517 mService.maybeShowInitialReviewPermissionsNotification(); 14518 14519 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14520 } 14521 14522 @Test 14523 public void testMaybeShowReviewPermissionsNotification_reshown() { 14524 mService.setShowReviewPermissionsNotification(true); 14525 reset(mMockNm); 14526 14527 // If we have re-shown the notification and the user did not subsequently interacted with 14528 // it, then make sure we show when trying on boot 14529 Settings.Global.putInt(mContext.getContentResolver(), 14530 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14531 NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN); 14532 mService.maybeShowInitialReviewPermissionsNotification(); 14533 verify(mMockNm, times(1)).notify(eq(TAG), 14534 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 14535 any(Notification.class)); 14536 } 14537 14538 @Test 14539 public void testRescheduledReviewPermissionsNotification() { 14540 mService.setShowReviewPermissionsNotification(true); 14541 reset(mMockNm); 14542 14543 // when rescheduled, the notification goes through the NotificationManagerInternal service 14544 // this call doesn't need to know anything about previously scheduled state -- if called, 14545 // it should send the notification & write the appropriate int to Settings 14546 mInternalService.sendReviewPermissionsNotification(); 14547 14548 // Notification should be sent 14549 verify(mMockNm, times(1)).notify(eq(TAG), 14550 eq(SystemMessageProto.SystemMessage.NOTE_REVIEW_NOTIFICATION_PERMISSIONS), 14551 any(Notification.class)); 14552 14553 // write STATE_RESHOWN to settings 14554 assertEquals(NotificationManagerService.REVIEW_NOTIF_STATE_RESHOWN, 14555 Settings.Global.getInt(mContext.getContentResolver(), 14556 Settings.Global.REVIEW_PERMISSIONS_NOTIFICATION_STATE, 14557 NotificationManagerService.REVIEW_NOTIF_STATE_UNKNOWN)); 14558 } 14559 14560 @Test 14561 public void testRescheduledReviewPermissionsNotification_flagOff() { 14562 mService.setShowReviewPermissionsNotification(false); 14563 reset(mMockNm); 14564 14565 // no notification should be sent if the flag is off 14566 mInternalService.sendReviewPermissionsNotification(); 14567 verify(mMockNm, never()).notify(anyString(), anyInt(), any(Notification.class)); 14568 } 14569 14570 private void verifyStickyHun(int permissionState, boolean appRequested, 14571 boolean isSticky) throws Exception { 14572 14573 when(mPermissionHelper.hasRequestedPermission(Manifest.permission.USE_FULL_SCREEN_INTENT, 14574 mPkg, mUserId)).thenReturn(appRequested); 14575 14576 when(mPermissionManager.checkPermissionForDataDelivery( 14577 eq(Manifest.permission.USE_FULL_SCREEN_INTENT), any(), any())) 14578 .thenReturn(permissionState); 14579 14580 Notification n = new Notification.Builder(mContext, "test") 14581 .setFullScreenIntent(mActivityIntent, true) 14582 .build(); 14583 14584 mService.fixNotification(n, mPkg, "tag", 9, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 14585 14586 final int stickyFlag = n.flags & Notification.FLAG_FSI_REQUESTED_BUT_DENIED; 14587 14588 if (isSticky) { 14589 assertNotSame(0, stickyFlag); 14590 } else { 14591 assertSame(0, stickyFlag); 14592 } 14593 } 14594 14595 @Test 14596 public void testFixNotification_flagEnableStickyHun_fsiPermissionHardDenied_showStickyHun() 14597 throws Exception { 14598 14599 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_HARD_DENIED, true, 14600 /* isSticky= */ true); 14601 } 14602 14603 @Test 14604 public void testFixNotification_flagEnableStickyHun_fsiPermissionSoftDenied_showStickyHun() 14605 throws Exception { 14606 14607 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, true, 14608 /* isSticky= */ true); 14609 } 14610 14611 @Test 14612 public void testFixNotification_fsiPermissionSoftDenied_appNotRequest_noShowStickyHun() 14613 throws Exception { 14614 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_SOFT_DENIED, false, 14615 /* isSticky= */ false); 14616 } 14617 14618 14619 @Test 14620 public void testFixNotification_flagEnableStickyHun_fsiPermissionGranted_showFsi() 14621 throws Exception { 14622 14623 verifyStickyHun(/* permissionState= */ PermissionManager.PERMISSION_GRANTED, true, 14624 /* isSticky= */ false); 14625 } 14626 14627 @Test 14628 public void fixNotification_withFgsFlag_butIsNotFgs() throws Exception { 14629 final ApplicationInfo applicationInfo = new ApplicationInfo(); 14630 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14631 .thenReturn(applicationInfo); 14632 14633 Notification n = new Notification.Builder(mContext, "test") 14634 .setFlag(FLAG_FOREGROUND_SERVICE, true) 14635 .setFlag(FLAG_CAN_COLORIZE, true) 14636 .build(); 14637 14638 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14639 14640 assertFalse(n.isForegroundService()); 14641 assertFalse(n.hasColorizedPermission()); 14642 } 14643 14644 @Test 14645 public void checkCallStyleNotification_withoutAnyValidUseCase_throws() throws Exception { 14646 Person person = new Person.Builder().setName("caller").build(); 14647 Notification n = new Notification.Builder(mContext, "test") 14648 .setStyle(Notification.CallStyle.forOngoingCall( 14649 person, mActivityIntent)) 14650 .build(); 14651 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14652 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14653 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14654 14655 try { 14656 mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14657 r.getSbn().getId(), r.getSbn().getTag(), r, false, false); 14658 assertFalse("CallStyle should not be allowed without a valid use case", true); 14659 } catch (IllegalArgumentException error) { 14660 assertThat(error.getMessage()).contains("CallStyle"); 14661 } 14662 } 14663 14664 @Test 14665 public void checkCallStyleNotification_allowedForFgs() throws Exception { 14666 Person person = new Person.Builder().setName("caller").build(); 14667 Notification n = new Notification.Builder(mContext, "test") 14668 .setFlag(FLAG_FOREGROUND_SERVICE, true) 14669 .setStyle(Notification.CallStyle.forOngoingCall( 14670 person, mActivityIntent)) 14671 .build(); 14672 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14673 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14674 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14675 14676 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14677 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14678 } 14679 14680 private Notification createBigPictureNotification(boolean isBigPictureStyle, boolean hasImage, 14681 boolean isImageBitmap) { 14682 Notification.Builder builder = new Notification.Builder(mContext) 14683 .setSmallIcon(android.R.drawable.sym_def_app_icon); 14684 Notification.BigPictureStyle style = new Notification.BigPictureStyle(); 14685 14686 if (isBigPictureStyle && hasImage) { 14687 if (isImageBitmap) { 14688 style = style.bigPicture(Bitmap.createBitmap(400, 400, Bitmap.Config.ARGB_8888)); 14689 } else { 14690 style = style.bigPicture(Icon.createWithResource(mContext, R.drawable.btn_plus)); 14691 } 14692 } 14693 if (isBigPictureStyle) { 14694 builder.setStyle(style); 14695 } 14696 14697 Notification notification = builder.setChannelId(TEST_CHANNEL_ID).build(); 14698 14699 return notification; 14700 } 14701 14702 private NotificationRecord createBigPictureRecord(boolean isBigPictureStyle, boolean hasImage, 14703 boolean isImageBitmap, boolean isExpired) { 14704 long timePostedMs = System.currentTimeMillis(); 14705 if (isExpired) { 14706 timePostedMs -= BITMAP_DURATION.toMillis(); 14707 } 14708 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14709 createBigPictureNotification(isBigPictureStyle, hasImage, isImageBitmap), 14710 UserHandle.getUserHandleForUid(mUid), null, timePostedMs); 14711 14712 return new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14713 } 14714 14715 private void addRecordAndRemoveBitmaps(NotificationRecord record) { 14716 mService.addNotification(record); 14717 mInternalService.removeBitmaps(); 14718 waitForIdle(); 14719 } 14720 14721 @Test 14722 public void testRemoveBitmaps_canRemoveRevokedDelegate() throws Exception { 14723 Notification n = createBigPictureNotification(true, true, true); 14724 long timePostedMs = System.currentTimeMillis(); 14725 timePostedMs -= BITMAP_DURATION.toMillis(); 14726 14727 when(mPermissionHelper.hasPermission(UID_O)).thenReturn(true); 14728 when(mPackageManagerInternal.isSameApp(PKG_O, UID_O, UserHandle.getUserId(UID_O))) 14729 .thenReturn(true); 14730 mService.mPreferencesHelper.createNotificationChannel(PKG_O, UID_O, 14731 mTestNotificationChannel, true /* fromTargetApp */, false, UID_O, 14732 false); 14733 mBinderService.createNotificationChannels(PKG_O, new ParceledListSlice( 14734 Arrays.asList(mTestNotificationChannel, mSilentChannel, mMinChannel))); 14735 14736 StatusBarNotification sbn = new StatusBarNotification(PKG_O, "old.delegate", 8, "tag", 14737 UID_O, 0, n, UserHandle.getUserHandleForUid(UID_O), null, timePostedMs); 14738 14739 mService.addNotification(new NotificationRecord(mContext, sbn, mTestNotificationChannel)); 14740 mInternalService.removeBitmaps(); 14741 14742 waitForIdle(); 14743 14744 verify(mWorkerHandler, times(1)) 14745 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14746 } 14747 14748 @Test 14749 public void testRemoveBitmaps_notBigPicture_noRepost() { 14750 addRecordAndRemoveBitmaps( 14751 createBigPictureRecord( 14752 /* isBigPictureStyle= */ false, 14753 /* hasImage= */ false, 14754 /* isImageBitmap= */ false, 14755 /* isExpired= */ false)); 14756 verify(mWorkerHandler, never()) 14757 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14758 } 14759 14760 @Test 14761 public void testRemoveBitmaps_bigPictureNoImage_noRepost() { 14762 addRecordAndRemoveBitmaps( 14763 createBigPictureRecord( 14764 /* isBigPictureStyle= */ true, 14765 /* hasImage= */ false, 14766 /* isImageBitmap= */ false, 14767 /* isExpired= */ false)); 14768 verify(mWorkerHandler, never()) 14769 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14770 } 14771 14772 @Test 14773 public void testRemoveBitmaps_notExpired_noRepost() { 14774 addRecordAndRemoveBitmaps( 14775 createBigPictureRecord( 14776 /* isBigPictureStyle= */ true, 14777 /* hasImage= */ true, 14778 /* isImageBitmap= */ true, 14779 /* isExpired= */ false)); 14780 verify(mWorkerHandler, never()) 14781 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14782 } 14783 14784 @Test 14785 public void testRemoveBitmaps_bitmapExpired_repost() { 14786 addRecordAndRemoveBitmaps( 14787 createBigPictureRecord( 14788 /* isBigPictureStyle= */ true, 14789 /* hasImage= */ true, 14790 /* isImageBitmap= */ true, 14791 /* isExpired= */ true)); 14792 verify(mWorkerHandler, times(1)) 14793 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14794 } 14795 14796 @Test 14797 public void testRemoveBitmaps_bitmapExpired_bitmapGone() { 14798 NotificationRecord record = createBigPictureRecord( 14799 /* isBigPictureStyle= */ true, 14800 /* hasImage= */ true, 14801 /* isImageBitmap= */ true, 14802 /* isExpired= */ true); 14803 addRecordAndRemoveBitmaps(record); 14804 assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE)).isTrue(); 14805 final Parcelable picture = record.getNotification().extras.getParcelable(EXTRA_PICTURE); 14806 assertThat(picture).isNull(); 14807 } 14808 14809 @Test 14810 public void testRemoveBitmaps_bitmapExpired_silent() { 14811 NotificationRecord record = createBigPictureRecord( 14812 /* isBigPictureStyle= */ true, 14813 /* hasImage= */ true, 14814 /* isImageBitmap= */ true, 14815 /* isExpired= */ true); 14816 addRecordAndRemoveBitmaps(record); 14817 assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0); 14818 } 14819 14820 @Test 14821 public void testRemoveBitmaps_iconExpired_repost() { 14822 addRecordAndRemoveBitmaps( 14823 createBigPictureRecord( 14824 /* isBigPictureStyle= */ true, 14825 /* hasImage= */ true, 14826 /* isImageBitmap= */ false, 14827 /* isExpired= */ true)); 14828 verify(mWorkerHandler, times(1)) 14829 .post(any(NotificationManagerService.EnqueueNotificationRunnable.class)); 14830 } 14831 14832 @Test 14833 public void testRemoveBitmaps_iconExpired_iconGone() { 14834 NotificationRecord record = createBigPictureRecord( 14835 /* isBigPictureStyle= */ true, 14836 /* hasImage= */ true, 14837 /* isImageBitmap= */ false, 14838 /* isExpired= */ true); 14839 addRecordAndRemoveBitmaps(record); 14840 assertThat(record.getNotification().extras.containsKey(EXTRA_PICTURE_ICON)).isTrue(); 14841 final Parcelable pictureIcon = 14842 record.getNotification().extras.getParcelable(EXTRA_PICTURE_ICON); 14843 assertThat(pictureIcon).isNull(); 14844 } 14845 14846 @Test 14847 public void testRemoveBitmaps_iconExpired_silent() { 14848 NotificationRecord record = createBigPictureRecord( 14849 /* isBigPictureStyle= */ true, 14850 /* hasImage= */ true, 14851 /* isImageBitmap= */ false, 14852 /* isExpired= */ true); 14853 addRecordAndRemoveBitmaps(record); 14854 assertThat(record.getNotification().flags & FLAG_ONLY_ALERT_ONCE).isNotEqualTo(0); 14855 } 14856 14857 @Test 14858 public void checkCallStyleNotification_allowedForByForegroundService() throws Exception { 14859 Person person = new Person.Builder().setName("caller").build(); 14860 Notification n = new Notification.Builder(mContext, "test") 14861 // Without FLAG_FOREGROUND_SERVICE. 14862 //.setFlag(FLAG_FOREGROUND_SERVICE, true) 14863 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14864 .build(); 14865 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14866 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14867 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14868 14869 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14870 r.getSbn().getId(), r.getSbn().getTag(), r, false, 14871 true /* byForegroundService */)).isTrue(); 14872 } 14873 14874 @Test 14875 public void checkCallStyleNotification_allowedForUij() throws Exception { 14876 Person person = new Person.Builder().setName("caller").build(); 14877 Notification n = new Notification.Builder(mContext, "test") 14878 .setFlag(FLAG_USER_INITIATED_JOB, true) 14879 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14880 .build(); 14881 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14882 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14883 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14884 14885 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14886 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14887 } 14888 14889 @Test 14890 public void checkCallStyleNotification_allowedForFsiAllowed() throws Exception { 14891 Person person = new Person.Builder().setName("caller").build(); 14892 Notification n = new Notification.Builder(mContext, "test") 14893 .setFullScreenIntent(mActivityIntent, true) 14894 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14895 .build(); 14896 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14897 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14898 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14899 14900 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14901 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14902 } 14903 14904 @Test 14905 public void checkCallStyleNotification_allowedForFsiDenied() throws Exception { 14906 Person person = new Person.Builder().setName("caller").build(); 14907 Notification n = new Notification.Builder(mContext, "test") 14908 .setFlag(Notification.FLAG_FSI_REQUESTED_BUT_DENIED, true) 14909 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 14910 .build(); 14911 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, "tag", mUid, 0, 14912 n, UserHandle.getUserHandleForUid(mUid), null, 0); 14913 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 14914 14915 assertThat(mService.checkDisqualifyingFeatures(r.getUserId(), r.getUid(), 14916 r.getSbn().getId(), r.getSbn().getTag(), r, false, false)).isTrue(); 14917 } 14918 14919 @Test 14920 public void fixSystemNotification_withOnGoingFlag_shouldBeDismissible() 14921 throws Exception { 14922 final ApplicationInfo ai = new ApplicationInfo(); 14923 ai.packageName = "pkg"; 14924 ai.uid = mUid; 14925 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 14926 14927 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14928 .thenReturn(ai); 14929 when(mAppOpsManager.checkOpNoThrow( 14930 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 14931 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 14932 // Given: a notification from an app on the system partition has the flag 14933 // FLAG_ONGOING_EVENT set 14934 Notification n = new Notification.Builder(mContext, "test") 14935 .setOngoing(true) 14936 .build(); 14937 14938 // When: fix the notification with NotificationManagerService 14939 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14940 14941 // Then: the notification's flag FLAG_NO_DISMISS should not be set 14942 assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14943 } 14944 14945 @Test 14946 public void fixMediaNotification_withOnGoingFlag_shouldBeNonDismissible() 14947 throws Exception { 14948 // Given: a media notification has the flag FLAG_ONGOING_EVENT set 14949 Notification n = new Notification.Builder(mContext, "test") 14950 .setOngoing(true) 14951 .setStyle(new Notification.MediaStyle() 14952 .setMediaSession(mock(MediaSession.Token.class))) 14953 .build(); 14954 14955 // When: fix the notification with NotificationManagerService 14956 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14957 14958 // Then: the notification's flag FLAG_NO_DISMISS should be set 14959 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14960 } 14961 14962 @Test 14963 public void fixSystemNotification_defaultSearchSelectior_withOnGoingFlag_nondismissible() 14964 throws Exception { 14965 final ApplicationInfo ai = new ApplicationInfo(); 14966 ai.packageName = SEARCH_SELECTOR_PKG; 14967 ai.uid = mUid; 14968 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 14969 14970 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14971 .thenReturn(ai); 14972 when(mAppOpsManager.checkOpNoThrow( 14973 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 14974 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 14975 // Given: a notification from an app on the system partition has the flag 14976 // FLAG_ONGOING_EVENT set 14977 Notification n = new Notification.Builder(mContext, "test") 14978 .setOngoing(true) 14979 .build(); 14980 14981 // When: fix the notification with NotificationManagerService 14982 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 14983 14984 // Then: the notification's flag FLAG_NO_DISMISS should be set 14985 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 14986 } 14987 14988 @Test 14989 public void fixSystemNotification_defaultAdservices_withOnGoingFlag_nondismissible() 14990 throws Exception { 14991 final ApplicationInfo ai = new ApplicationInfo(); 14992 ai.packageName = ADSERVICES_APK_PKG; 14993 ai.uid = mUid; 14994 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 14995 14996 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 14997 .thenReturn(ai); 14998 when(mAppOpsManager.checkOpNoThrow( 14999 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, ai.uid, 15000 ai.packageName)).thenReturn(AppOpsManager.MODE_IGNORED); 15001 // Given: a notification from an app on the system partition has the flag 15002 // FLAG_ONGOING_EVENT set 15003 Notification n = new Notification.Builder(mContext, "test") 15004 .setOngoing(true) 15005 .build(); 15006 15007 // When: fix the notification with NotificationManagerService 15008 mService.fixNotification(n, ADSERVICES_APK_PKG, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, 15009 true); 15010 15011 // Then: the notification's flag FLAG_NO_DISMISS should be set 15012 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15013 } 15014 15015 @Test 15016 public void fixCallNotification_withOnGoingFlag_shouldNotBeNonDismissible() 15017 throws Exception { 15018 // Given: a call notification has the flag FLAG_ONGOING_EVENT set 15019 Person person = new Person.Builder() 15020 .setName("caller") 15021 .build(); 15022 Notification n = new Notification.Builder(mContext, "test") 15023 .setOngoing(true) 15024 .setStyle(Notification.CallStyle.forOngoingCall(person, mActivityIntent)) 15025 .build(); 15026 15027 // When: fix the notification with NotificationManagerService 15028 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15029 15030 // Then: the notification's flag FLAG_NO_DISMISS should be set 15031 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15032 } 15033 15034 15035 @Test 15036 public void fixNonExemptNotification_withOnGoingFlag_shouldBeDismissible() throws Exception { 15037 // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set 15038 Notification n = new Notification.Builder(mContext, "test") 15039 .setOngoing(true) 15040 .build(); 15041 15042 // When: fix the notification with NotificationManagerService 15043 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15044 15045 // Then: the notification's flag FLAG_NO_DISMISS should not be set 15046 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 15047 } 15048 15049 @Test 15050 public void fixNonExemptNotification_withNoDismissFlag_shouldBeDismissible() 15051 throws Exception { 15052 // Given: a non-exempt notification has the flag FLAG_NO_DISMISS set (even though this is 15053 // not allowed) 15054 Notification n = new Notification.Builder(mContext, "test") 15055 .build(); 15056 n.flags |= Notification.FLAG_NO_DISMISS; 15057 15058 // When: fix the notification with NotificationManagerService 15059 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15060 15061 // Then: the notification's flag FLAG_NO_DISMISS should be cleared 15062 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 15063 } 15064 15065 @Test 15066 public void fixMediaNotification_withoutOnGoingFlag_shouldBeDismissible() throws Exception { 15067 // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set 15068 Notification n = new Notification.Builder(mContext, "test") 15069 .setOngoing(false) 15070 .setStyle(new Notification.MediaStyle() 15071 .setMediaSession(mock(MediaSession.Token.class))) 15072 .build(); 15073 15074 // When: fix the notification with NotificationManagerService 15075 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15076 15077 // Then: the notification's flag FLAG_NO_DISMISS should not be set 15078 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 15079 } 15080 15081 @Test 15082 public void fixMediaNotification_withoutOnGoingFlag_withNoDismissFlag_shouldBeDismissible() 15083 throws Exception { 15084 // Given: a media notification doesn't have the flag FLAG_ONGOING_EVENT set, 15085 // but has the flag FLAG_NO_DISMISS set 15086 Notification n = new Notification.Builder(mContext, "test") 15087 .setOngoing(false) 15088 .setStyle(new Notification.MediaStyle() 15089 .setMediaSession(mock(MediaSession.Token.class))) 15090 .build(); 15091 n.flags |= Notification.FLAG_NO_DISMISS; 15092 15093 // When: fix the notification with NotificationManagerService 15094 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15095 15096 // Then: the notification's flag FLAG_NO_DISMISS should be cleared 15097 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 15098 } 15099 15100 @Test 15101 public void fixNonExempt_Notification_withoutOnGoingFlag_shouldBeDismissible() 15102 throws Exception { 15103 // Given: a non-exempt notification has the flag FLAG_ONGOING_EVENT set 15104 Notification n = new Notification.Builder(mContext, "test") 15105 .setOngoing(false) 15106 .build(); 15107 15108 // When: fix the notification with NotificationManagerService 15109 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15110 15111 // Then: the notification's flag FLAG_NO_DISMISS should not be set 15112 assertEquals(0, n.flags & Notification.FLAG_NO_DISMISS); 15113 } 15114 15115 @Test 15116 public void fixOrganizationAdminNotification_withOnGoingFlag_shouldBeNonDismissible() 15117 throws Exception { 15118 when(mDevicePolicyManager.isActiveDeviceOwner(mUid)).thenReturn(true); 15119 // Given: a notification has the flag FLAG_ONGOING_EVENT set 15120 Notification n = new Notification.Builder(mContext, "test") 15121 .setOngoing(true) 15122 .build(); 15123 15124 // When: fix the notification with NotificationManagerService 15125 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15126 15127 // Then: the notification's flag FLAG_NO_DISMISS should be set 15128 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15129 } 15130 15131 @Test 15132 public void fixExemptAppOpNotification_withFlag_shouldBeNonDismissible() 15133 throws Exception { 15134 final ApplicationInfo ai = new ApplicationInfo(); 15135 ai.packageName = mPkg; 15136 ai.uid = mUid; 15137 ai.flags |= ApplicationInfo.FLAG_SYSTEM; 15138 15139 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 15140 .thenReturn(ai); 15141 when(mAppOpsManager.checkOpNoThrow( 15142 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 15143 mPkg)).thenReturn(AppOpsManager.MODE_ALLOWED); 15144 // Given: a notification has the flag FLAG_ONGOING_EVENT set 15145 Notification n = new Notification.Builder(mContext, "test") 15146 .setOngoing(true) 15147 .build(); 15148 15149 // When: fix the notification with NotificationManagerService 15150 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15151 15152 // Then: the notification's flag FLAG_NO_DISMISS should be set 15153 assertNotSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15154 } 15155 15156 @Test 15157 public void fixExemptAppOpNotification_withoutAppOpsFlag_shouldBeDismissible() 15158 throws Exception { 15159 when(mAppOpsManager.checkOpNoThrow( 15160 AppOpsManager.OP_SYSTEM_EXEMPT_FROM_DISMISSIBLE_NOTIFICATIONS, mUid, 15161 mPkg)).thenReturn(AppOpsManager.MODE_IGNORED); 15162 // Given: a notification has the flag FLAG_ONGOING_EVENT set 15163 Notification n = new Notification.Builder(mContext, "test") 15164 .setOngoing(true) 15165 .build(); 15166 15167 // When: fix the notification with NotificationManagerService 15168 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15169 15170 // Then: the notification's flag FLAG_NO_DISMISS should not be set 15171 assertSame(0, n.flags & Notification.FLAG_NO_DISMISS); 15172 } 15173 15174 @Test 15175 public void testCancelAllNotifications_IgnoreUserInitiatedJob() throws Exception { 15176 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15177 .thenReturn(true); 15178 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15179 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15180 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15181 "testCancelAllNotifications_IgnoreUserInitiatedJob", 15182 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15183 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 15184 waitForIdle(); 15185 StatusBarNotification[] notifs = 15186 mBinderService.getActiveNotifications(sbn.getPackageName()); 15187 assertEquals(1, notifs.length); 15188 assertEquals(1, mService.getNotificationRecordCount()); 15189 } 15190 15191 @Test 15192 public void testCancelAllNotifications_UijFlag_NoUij_Allowed() throws Exception { 15193 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15194 .thenReturn(false); 15195 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15196 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15197 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15198 "testCancelAllNotifications_UijFlag_NoUij_Allowed", 15199 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15200 mBinderService.cancelAllNotifications(mPkg, sbn.getUserId()); 15201 waitForIdle(); 15202 StatusBarNotification[] notifs = 15203 mBinderService.getActiveNotifications(sbn.getPackageName()); 15204 assertEquals(0, notifs.length); 15205 } 15206 15207 @Test 15208 public void testCancelAllNotificationsOtherPackage_IgnoresUijNotification() throws Exception { 15209 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15210 .thenReturn(true); 15211 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15212 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15213 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15214 "testCancelAllNotifications_IgnoreOtherPackages", 15215 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15216 mBinderService.cancelAllNotifications("other_pkg_name", sbn.getUserId()); 15217 waitForIdle(); 15218 StatusBarNotification[] notifs = 15219 mBinderService.getActiveNotifications(sbn.getPackageName()); 15220 assertEquals(1, notifs.length); 15221 assertEquals(1, mService.getNotificationRecordCount()); 15222 } 15223 15224 @Test 15225 public void testRemoveUserInitiatedJobFlag_ImmediatelyAfterEnqueue() throws Exception { 15226 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15227 .thenReturn(true); 15228 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 15229 .setSmallIcon(android.R.drawable.sym_def_app_icon) 15230 .build(); 15231 StatusBarNotification sbn = new StatusBarNotification("a", "a", 0, null, mUid, 0, 15232 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15233 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15234 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, null, 15235 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15236 mInternalService.removeUserInitiatedJobFlagFromNotification(mPkg, sbn.getId(), 15237 sbn.getUserId()); 15238 waitForIdle(); 15239 StatusBarNotification[] notifs = 15240 mBinderService.getActiveNotifications(sbn.getPackageName()); 15241 assertFalse(notifs[0].getNotification().isUserInitiatedJob()); 15242 } 15243 15244 @Test 15245 public void testCancelAfterSecondEnqueueDoesNotSpecifyUserInitiatedJobFlag() throws Exception { 15246 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15247 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT | FLAG_USER_INITIATED_JOB; 15248 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 15249 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15250 sbn.getNotification().flags = Notification.FLAG_ONGOING_EVENT; 15251 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 15252 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15253 mBinderService.cancelNotificationWithTag(mPkg, mPkg, sbn.getTag(), sbn.getId(), 15254 sbn.getUserId()); 15255 waitForIdle(); 15256 assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length); 15257 assertEquals(0, mService.getNotificationRecordCount()); 15258 } 15259 15260 @Test 15261 public void testCancelNotificationWithTag_fromApp_cannotCancelUijChild() throws Exception { 15262 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15263 .thenReturn(true); 15264 mService.isSystemUid = false; 15265 mService.isSystemAppId = false; 15266 final NotificationRecord parent = generateNotificationRecord( 15267 mTestNotificationChannel, 1, "group", true); 15268 final NotificationRecord child = generateNotificationRecord( 15269 mTestNotificationChannel, 2, "group", false); 15270 final NotificationRecord child2 = generateNotificationRecord( 15271 mTestNotificationChannel, 3, "group", false); 15272 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15273 mService.addNotification(parent); 15274 mService.addNotification(child); 15275 mService.addNotification(child2); 15276 mService.getBinderService().cancelNotificationWithTag( 15277 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 15278 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 15279 waitForIdle(); 15280 StatusBarNotification[] notifs = 15281 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15282 assertEquals(1, notifs.length); 15283 } 15284 15285 @Test 15286 public void testCancelNotificationWithTag_fromApp_cannotCancelUijParent() throws Exception { 15287 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15288 .thenReturn(true); 15289 mService.isSystemUid = false; 15290 mService.isSystemAppId = false; 15291 final NotificationRecord parent = generateNotificationRecord( 15292 mTestNotificationChannel, 1, "group", true); 15293 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15294 final NotificationRecord child = generateNotificationRecord( 15295 mTestNotificationChannel, 2, "group", false); 15296 final NotificationRecord child2 = generateNotificationRecord( 15297 mTestNotificationChannel, 3, "group", false); 15298 mService.addNotification(parent); 15299 mService.addNotification(child); 15300 mService.addNotification(child2); 15301 mService.getBinderService().cancelNotificationWithTag( 15302 parent.getSbn().getPackageName(), parent.getSbn().getPackageName(), 15303 parent.getSbn().getTag(), parent.getSbn().getId(), parent.getSbn().getUserId()); 15304 waitForIdle(); 15305 StatusBarNotification[] notifs = 15306 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15307 assertEquals(3, notifs.length); 15308 } 15309 15310 @Test 15311 public void testCancelAllNotificationsFromApp_cannotCancelUijChild() throws Exception { 15312 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15313 .thenReturn(true); 15314 mService.isSystemUid = false; 15315 mService.isSystemAppId = false; 15316 final NotificationRecord parent = generateNotificationRecord( 15317 mTestNotificationChannel, 1, "group", true); 15318 final NotificationRecord child = generateNotificationRecord( 15319 mTestNotificationChannel, 2, "group", false); 15320 final NotificationRecord child2 = generateNotificationRecord( 15321 mTestNotificationChannel, 3, "group", false); 15322 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15323 final NotificationRecord newGroup = generateNotificationRecord( 15324 mTestNotificationChannel, 4, "group2", false); 15325 mService.addNotification(parent); 15326 mService.addNotification(child); 15327 mService.addNotification(child2); 15328 mService.addNotification(newGroup); 15329 mService.getBinderService().cancelAllNotifications( 15330 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 15331 waitForIdle(); 15332 StatusBarNotification[] notifs = 15333 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15334 assertEquals(1, notifs.length); 15335 } 15336 15337 @Test 15338 public void testCancelAllNotifications_fromApp_cannotCancelUijParent() throws Exception { 15339 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15340 .thenReturn(true); 15341 mService.isSystemUid = false; 15342 mService.isSystemAppId = false; 15343 final NotificationRecord parent = generateNotificationRecord( 15344 mTestNotificationChannel, 1, "group", true); 15345 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15346 final NotificationRecord child = generateNotificationRecord( 15347 mTestNotificationChannel, 2, "group", false); 15348 final NotificationRecord child2 = generateNotificationRecord( 15349 mTestNotificationChannel, 3, "group", false); 15350 final NotificationRecord newGroup = generateNotificationRecord( 15351 mTestNotificationChannel, 4, "group2", false); 15352 mService.addNotification(parent); 15353 mService.addNotification(child); 15354 mService.addNotification(child2); 15355 mService.addNotification(newGroup); 15356 mService.getBinderService().cancelAllNotifications( 15357 parent.getSbn().getPackageName(), parent.getSbn().getUserId()); 15358 waitForIdle(); 15359 StatusBarNotification[] notifs = 15360 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15361 assertEquals(1, notifs.length); 15362 } 15363 15364 @Test 15365 public void testCancelNotificationsFromListener_clearAll_GroupWithUijParent() throws Exception { 15366 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15367 .thenReturn(true); 15368 final NotificationRecord parent = generateNotificationRecord( 15369 mTestNotificationChannel, 1, "group", true); 15370 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15371 final NotificationRecord child = generateNotificationRecord( 15372 mTestNotificationChannel, 2, "group", false); 15373 final NotificationRecord child2 = generateNotificationRecord( 15374 mTestNotificationChannel, 3, "group", false); 15375 final NotificationRecord newGroup = generateNotificationRecord( 15376 mTestNotificationChannel, 4, "group2", false); 15377 mService.addNotification(parent); 15378 mService.addNotification(child); 15379 mService.addNotification(child2); 15380 mService.addNotification(newGroup); 15381 mService.getBinderService().cancelNotificationsFromListener(null, null); 15382 waitForIdle(); 15383 StatusBarNotification[] notifs = 15384 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15385 assertEquals(0, notifs.length); 15386 } 15387 15388 @Test 15389 public void testCancelNotificationsFromListener_clearAll_GroupWithUijChild() throws Exception { 15390 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15391 .thenReturn(true); 15392 final NotificationRecord parent = generateNotificationRecord( 15393 mTestNotificationChannel, 1, "group", true); 15394 final NotificationRecord child = generateNotificationRecord( 15395 mTestNotificationChannel, 2, "group", false); 15396 final NotificationRecord child2 = generateNotificationRecord( 15397 mTestNotificationChannel, 3, "group", false); 15398 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15399 final NotificationRecord newGroup = generateNotificationRecord( 15400 mTestNotificationChannel, 4, "group2", false); 15401 mService.addNotification(parent); 15402 mService.addNotification(child); 15403 mService.addNotification(child2); 15404 mService.addNotification(newGroup); 15405 mService.getBinderService().cancelNotificationsFromListener(null, null); 15406 waitForIdle(); 15407 StatusBarNotification[] notifs = 15408 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15409 assertEquals(0, notifs.length); 15410 } 15411 15412 @Test 15413 public void testCancelNotificationsFromListener_clearAll_Uij() throws Exception { 15414 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15415 .thenReturn(true); 15416 final NotificationRecord child2 = generateNotificationRecord( 15417 mTestNotificationChannel, 3, null, false); 15418 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15419 mService.addNotification(child2); 15420 mService.getBinderService().cancelNotificationsFromListener(null, null); 15421 waitForIdle(); 15422 StatusBarNotification[] notifs = 15423 mBinderService.getActiveNotifications(child2.getSbn().getPackageName()); 15424 assertEquals(0, notifs.length); 15425 } 15426 15427 @Test 15428 public void testCancelNotificationsFromListener_byKey_GroupWithUijParent() throws Exception { 15429 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15430 .thenReturn(true); 15431 final NotificationRecord parent = generateNotificationRecord( 15432 mTestNotificationChannel, 1, "group", true); 15433 parent.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15434 final NotificationRecord child = generateNotificationRecord( 15435 mTestNotificationChannel, 2, "group", false); 15436 final NotificationRecord child2 = generateNotificationRecord( 15437 mTestNotificationChannel, 3, "group", false); 15438 final NotificationRecord newGroup = generateNotificationRecord( 15439 mTestNotificationChannel, 4, "group2", false); 15440 mService.addNotification(parent); 15441 mService.addNotification(child); 15442 mService.addNotification(child2); 15443 mService.addNotification(newGroup); 15444 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 15445 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 15446 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15447 waitForIdle(); 15448 StatusBarNotification[] notifs = 15449 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15450 assertEquals(0, notifs.length); 15451 } 15452 15453 @Test 15454 public void testCancelNotificationsFromListener_byKey_GroupWithUijChild() throws Exception { 15455 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15456 .thenReturn(true); 15457 final NotificationRecord parent = generateNotificationRecord( 15458 mTestNotificationChannel, 1, "group", true); 15459 final NotificationRecord child = generateNotificationRecord( 15460 mTestNotificationChannel, 2, "group", false); 15461 final NotificationRecord child2 = generateNotificationRecord( 15462 mTestNotificationChannel, 3, "group", false); 15463 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15464 final NotificationRecord newGroup = generateNotificationRecord( 15465 mTestNotificationChannel, 4, "group2", false); 15466 mService.addNotification(parent); 15467 mService.addNotification(child); 15468 mService.addNotification(child2); 15469 mService.addNotification(newGroup); 15470 String[] keys = {parent.getSbn().getKey(), child.getSbn().getKey(), 15471 child2.getSbn().getKey(), newGroup.getSbn().getKey()}; 15472 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15473 waitForIdle(); 15474 StatusBarNotification[] notifs = 15475 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15476 assertEquals(0, notifs.length); 15477 } 15478 15479 @Test 15480 public void testCancelNotificationsFromListener_byKey_Uij() throws Exception { 15481 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15482 .thenReturn(true); 15483 final NotificationRecord child = generateNotificationRecord( 15484 mTestNotificationChannel, 3, null, false); 15485 child.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15486 mService.addNotification(child); 15487 String[] keys = {child.getSbn().getKey()}; 15488 mService.getBinderService().cancelNotificationsFromListener(null, keys); 15489 waitForIdle(); 15490 StatusBarNotification[] notifs = 15491 mBinderService.getActiveNotifications(child.getSbn().getPackageName()); 15492 assertEquals(0, notifs.length); 15493 } 15494 15495 @Test 15496 public void testUserInitiatedCancelAllWithGroup_UserInitiatedFlag() throws Exception { 15497 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15498 .thenReturn(true); 15499 final NotificationRecord parent = generateNotificationRecord( 15500 mTestNotificationChannel, 1, "group", true); 15501 final NotificationRecord child = generateNotificationRecord( 15502 mTestNotificationChannel, 2, "group", false); 15503 final NotificationRecord child2 = generateNotificationRecord( 15504 mTestNotificationChannel, 3, "group", false); 15505 child2.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15506 final NotificationRecord newGroup = generateNotificationRecord( 15507 mTestNotificationChannel, 4, "group2", false); 15508 mService.addNotification(parent); 15509 mService.addNotification(child); 15510 mService.addNotification(child2); 15511 mService.addNotification(newGroup); 15512 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), parent.getUserId()); 15513 waitForIdle(); 15514 StatusBarNotification[] notifs = 15515 mBinderService.getActiveNotifications(parent.getSbn().getPackageName()); 15516 assertEquals(0, notifs.length); 15517 } 15518 15519 @Test 15520 public void testDeleteChannelGroupChecksForUijs() throws Exception { 15521 when(mCompanionMgr.getAssociations(mPkg, UserHandle.getUserId(mUid))) 15522 .thenReturn(singletonList(mock(AssociationInfo.class))); 15523 CountDownLatch latch = new CountDownLatch(2); 15524 mService.createNotificationChannelGroup(mPkg, mUid, 15525 new NotificationChannelGroup("group", "group"), true, false); 15526 new Thread(() -> { 15527 NotificationChannel notificationChannel = new NotificationChannel("id", "id", 15528 NotificationManager.IMPORTANCE_HIGH); 15529 notificationChannel.setGroup("group"); 15530 ParceledListSlice<NotificationChannel> pls = 15531 new ParceledListSlice(ImmutableList.of(notificationChannel)); 15532 try { 15533 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 15534 } catch (RemoteException e) { 15535 throw new RuntimeException(e); 15536 } 15537 latch.countDown(); 15538 }).start(); 15539 new Thread(() -> { 15540 try { 15541 synchronized (this) { 15542 wait(5000); 15543 } 15544 mService.createNotificationChannelGroup(mPkg, mUid, 15545 new NotificationChannelGroup("new", "new group"), true, false); 15546 NotificationChannel notificationChannel = 15547 new NotificationChannel("id", "id", NotificationManager.IMPORTANCE_HIGH); 15548 notificationChannel.setGroup("new"); 15549 ParceledListSlice<NotificationChannel> pls = 15550 new ParceledListSlice(ImmutableList.of(notificationChannel)); 15551 try { 15552 mBinderService.createNotificationChannelsForPackage(mPkg, mUid, pls); 15553 mBinderService.deleteNotificationChannelGroup(mPkg, "group"); 15554 } catch (RemoteException e) { 15555 throw new RuntimeException(e); 15556 } 15557 } catch (Exception e) { 15558 e.printStackTrace(); 15559 } 15560 latch.countDown(); 15561 }).start(); 15562 15563 latch.await(); 15564 verify(mJsi).isNotificationChannelAssociatedWithAnyUserInitiatedJobs( 15565 anyString(), anyInt(), anyString()); 15566 } 15567 15568 @Test 15569 public void testRemoveUserInitiatedJobFlagFromNotification_enqueued() { 15570 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15571 .thenReturn(true); 15572 Notification n = new Notification.Builder(mContext, "").build(); 15573 n.flags |= FLAG_USER_INITIATED_JOB; 15574 15575 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 15576 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15577 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15578 15579 mService.addEnqueuedNotification(r); 15580 15581 mInternalService.removeUserInitiatedJobFlagFromNotification( 15582 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15583 15584 waitForIdle(); 15585 15586 verify(mListeners, timeout(200).times(0)).notifyPostedLocked(any(), any()); 15587 } 15588 15589 @Test 15590 public void testRemoveUserInitiatedJobFlagFromNotification_posted() { 15591 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15592 .thenReturn(true); 15593 Notification n = new Notification.Builder(mContext, "").build(); 15594 n.flags |= FLAG_USER_INITIATED_JOB; 15595 15596 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 15597 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15598 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15599 15600 mService.addNotification(r); 15601 15602 mInternalService.removeUserInitiatedJobFlagFromNotification( 15603 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15604 15605 waitForIdle(); 15606 15607 ArgumentCaptor<NotificationRecord> captor = 15608 ArgumentCaptor.forClass(NotificationRecord.class); 15609 verify(mListeners, times(1)).notifyPostedLocked(captor.capture(), any()); 15610 15611 assertEquals(0, captor.getValue().getNotification().flags); 15612 } 15613 15614 @Test 15615 public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_enqueued() { 15616 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15617 Notification n = new Notification.Builder(mContext, "").build(); 15618 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 15619 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15620 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15621 mService.addEnqueuedNotification(r); 15622 } 15623 Notification n = new Notification.Builder(mContext, "").build(); 15624 n.flags |= FLAG_USER_INITIATED_JOB; 15625 15626 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 15627 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 15628 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15629 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15630 15631 mService.addEnqueuedNotification(r); 15632 15633 mInternalService.removeUserInitiatedJobFlagFromNotification( 15634 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15635 15636 waitForIdle(); 15637 15638 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 15639 mService.getNotificationRecordCount()); 15640 } 15641 15642 @Test 15643 public void testCannotRemoveUserInitiatedJobFlagWhenOverLimit_posted() { 15644 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15645 .thenReturn(true); 15646 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15647 Notification n = new Notification.Builder(mContext, "").build(); 15648 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, i, null, mUid, 0, 15649 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15650 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15651 mService.addNotification(r); 15652 } 15653 Notification n = new Notification.Builder(mContext, "").build(); 15654 n.flags |= FLAG_USER_INITIATED_JOB; 15655 15656 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 15657 NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, null, mUid, 0, 15658 n, UserHandle.getUserHandleForUid(mUid), null, 0); 15659 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 15660 15661 mService.addNotification(r); 15662 15663 mInternalService.removeUserInitiatedJobFlagFromNotification( 15664 mPkg, r.getSbn().getId(), r.getSbn().getUserId()); 15665 15666 waitForIdle(); 15667 15668 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS, 15669 mService.getNotificationRecordCount()); 15670 } 15671 15672 @Test 15673 public void testCanPostUijWhenOverLimit() throws RemoteException { 15674 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15675 .thenReturn(true); 15676 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15677 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 15678 i, null, false).getSbn(); 15679 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "testCanPostUijWhenOverLimit", 15680 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15681 } 15682 15683 final StatusBarNotification sbn = generateNotificationRecord(null).getSbn(); 15684 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15685 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15686 "testCanPostUijWhenOverLimit - uij over limit!", 15687 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15688 15689 waitForIdle(); 15690 15691 StatusBarNotification[] notifs = 15692 mBinderService.getActiveNotifications(sbn.getPackageName()); 15693 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 15694 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 15695 mService.getNotificationRecordCount()); 15696 } 15697 15698 @Test 15699 public void testCannotPostNonUijWhenOverLimit() throws RemoteException { 15700 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15701 .thenReturn(true); 15702 for (int i = 0; i < NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS; i++) { 15703 StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 15704 i, null, false).getSbn(); 15705 mBinderService.enqueueNotificationWithTag( 15706 mPkg, 15707 mPkg, 15708 "testCannotPostNonUijWhenOverLimit", 15709 sbn.getId(), 15710 sbn.getNotification(), 15711 sbn.getUserId()); 15712 waitForIdle(); 15713 } 15714 15715 final StatusBarNotification sbn = generateNotificationRecord(mTestNotificationChannel, 15716 100, null, false).getSbn(); 15717 sbn.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15718 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15719 "testCannotPostNonUijWhenOverLimit - uij over limit!", 15720 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 15721 15722 final StatusBarNotification sbn2 = generateNotificationRecord(mTestNotificationChannel, 15723 101, null, false).getSbn(); 15724 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15725 "testCannotPostNonUijWhenOverLimit - non uij over limit!", 15726 sbn2.getId(), sbn2.getNotification(), sbn2.getUserId()); 15727 15728 when(mJsi.isNotificationAssociatedWithAnyUserInitiatedJobs(anyInt(), anyInt(), anyString())) 15729 .thenReturn(false); 15730 final StatusBarNotification sbn3 = generateNotificationRecord(mTestNotificationChannel, 15731 101, null, false).getSbn(); 15732 sbn3.getNotification().flags |= FLAG_USER_INITIATED_JOB; 15733 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, 15734 "testCannotPostNonUijWhenOverLimit - fake uij over limit!", 15735 sbn3.getId(), sbn3.getNotification(), sbn3.getUserId()); 15736 15737 waitForIdle(); 15738 15739 StatusBarNotification[] notifs = 15740 mBinderService.getActiveNotifications(sbn.getPackageName()); 15741 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, notifs.length); 15742 assertEquals(NotificationManagerService.MAX_PACKAGE_NOTIFICATIONS + 1, 15743 mService.getNotificationRecordCount()); 15744 } 15745 15746 @Test 15747 public void fixNotification_withUijFlag_butIsNotUij() throws Exception { 15748 final ApplicationInfo applicationInfo = new ApplicationInfo(); 15749 when(mPackageManagerClient.getApplicationInfoAsUser(anyString(), anyInt(), anyInt())) 15750 .thenReturn(applicationInfo); 15751 15752 Notification n = new Notification.Builder(mContext, "test") 15753 .setFlag(FLAG_USER_INITIATED_JOB, true) 15754 .build(); 15755 15756 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 15757 assertFalse(n.isUserInitiatedJob()); 15758 } 15759 15760 @Test 15761 public void enqueue_updatesEnqueueRate() throws Exception { 15762 Notification n = generateNotificationRecord(null).getNotification(); 15763 15764 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 15765 // Don't waitForIdle() here. We want to verify the "intermediate" state. 15766 15767 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15768 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15769 verify(mUsageStats, never()).registerPostedByApp(any()); 15770 15771 waitForIdle(); 15772 } 15773 15774 @Test 15775 public void enqueue_withPost_updatesEnqueueRateAndPost() throws Exception { 15776 Notification n = generateNotificationRecord(null).getNotification(); 15777 15778 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 15779 waitForIdle(); 15780 15781 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15782 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15783 verify(mUsageStats).registerPostedByApp(any()); 15784 } 15785 15786 @Test 15787 public void enqueueNew_whenOverEnqueueRate_accepts() throws Exception { 15788 Notification n = generateNotificationRecord(null).getNotification(); 15789 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 15790 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f); 15791 15792 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, n, mUserId); 15793 waitForIdle(); 15794 15795 assertThat(mService.mNotificationsByKey).hasSize(1); 15796 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15797 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15798 verify(mUsageStats).registerPostedByApp(any()); 15799 } 15800 15801 @Test 15802 public void enqueueUpdate_whenBelowMaxEnqueueRate_accepts() throws Exception { 15803 // Post the first version. 15804 Notification original = generateNotificationRecord(null).getNotification(); 15805 original.when = System.currentTimeMillis(); 15806 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); 15807 waitForIdle(); 15808 assertThat(mService.mNotificationList).hasSize(1); 15809 assertThat(mService.mNotificationList.get(0).getNotification().when) 15810 .isEqualTo(original.when); 15811 15812 reset(mUsageStats); 15813 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 15814 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE - 1f); 15815 15816 // Post the update. 15817 Notification update = generateNotificationRecord(null).getNotification(); 15818 update.when = System.currentTimeMillis() + 111; 15819 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); 15820 waitForIdle(); 15821 15822 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15823 verify(mUsageStats).registerEnqueuedByAppAndAccepted(eq(mPkg)); 15824 verify(mUsageStats, never()).registerPostedByApp(any()); 15825 verify(mUsageStats).registerUpdatedByApp(any(), any()); 15826 assertThat(mService.mNotificationList).hasSize(1); 15827 assertThat(mService.mNotificationList.get(0).getNotification().when).isEqualTo(update.when); 15828 } 15829 15830 @Test 15831 public void enqueueUpdate_whenAboveMaxEnqueueRate_rejects() throws Exception { 15832 // Post the first version. 15833 Notification original = generateNotificationRecord(null).getNotification(); 15834 original.when = System.currentTimeMillis(); 15835 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, original, mUserId); 15836 waitForIdle(); 15837 assertThat(mService.mNotificationList).hasSize(1); 15838 assertThat(mService.mNotificationList.get(0).getNotification().when) 15839 .isEqualTo(original.when); 15840 15841 reset(mUsageStats); 15842 when(mUsageStats.getAppEnqueueRate(eq(mPkg))) 15843 .thenReturn(DEFAULT_MAX_NOTIFICATION_ENQUEUE_RATE + 1f); 15844 15845 // Post the update. 15846 Notification update = generateNotificationRecord(null).getNotification(); 15847 update.when = System.currentTimeMillis() + 111; 15848 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 0, update, mUserId); 15849 waitForIdle(); 15850 15851 verify(mUsageStats).registerEnqueuedByApp(eq(mPkg)); 15852 verify(mUsageStats, never()).registerEnqueuedByAppAndAccepted(any()); 15853 verify(mUsageStats, never()).registerPostedByApp(any()); 15854 verify(mUsageStats, never()).registerUpdatedByApp(any(), any()); 15855 assertThat(mService.mNotificationList).hasSize(1); 15856 assertThat(mService.mNotificationList.get(0).getNotification().when) 15857 .isEqualTo(original.when); // old 15858 } 15859 15860 @Test 15861 public void enqueueNotification_acceptsCorrectToken() throws RemoteException { 15862 Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15863 .setContentIntent(createPendingIntent("content")) 15864 .build(); 15865 Notification received = parcelAndUnparcel(sent, Notification.CREATOR); 15866 assertThat(received.getAllowlistToken()).isEqualTo( 15867 NotificationManagerService.ALLOWLIST_TOKEN); 15868 15869 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 15870 parcelAndUnparcel(received, Notification.CREATOR), mUserId); 15871 waitForIdle(); 15872 15873 assertThat(mService.mNotificationList).hasSize(1); 15874 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 15875 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 15876 } 15877 15878 @Test 15879 public void enqueueNotification_acceptsNullToken_andPopulatesIt() throws RemoteException { 15880 Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15881 .setContentIntent(createPendingIntent("content")) 15882 .build(); 15883 assertThat(receivedWithoutParceling.getAllowlistToken()).isNull(); 15884 15885 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 15886 parcelAndUnparcel(receivedWithoutParceling, Notification.CREATOR), mUserId); 15887 waitForIdle(); 15888 15889 assertThat(mService.mNotificationList).hasSize(1); 15890 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 15891 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 15892 } 15893 15894 @Test 15895 public void enqueueNotification_directlyThroughRunnable_populatesAllowlistToken() { 15896 Notification receivedWithoutParceling = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15897 .setContentIntent(createPendingIntent("content")) 15898 .build(); 15899 NotificationRecord record = new NotificationRecord( 15900 mContext, 15901 new StatusBarNotification(mPkg, mPkg, 1, "tag", mUid, 44, receivedWithoutParceling, 15902 mUser, "groupKey", 0), 15903 mTestNotificationChannel); 15904 assertThat(record.getNotification().getAllowlistToken()).isNull(); 15905 15906 mWorkerHandler.post( 15907 mService.new EnqueueNotificationRunnable(mUserId, record, false, false, 15908 mPostNotificationTrackerFactory.newTracker(null))); 15909 waitForIdle(); 15910 15911 assertThat(mService.mNotificationList).hasSize(1); 15912 assertThat(mService.mNotificationList.get(0).getNotification().getAllowlistToken()) 15913 .isEqualTo(NotificationManagerService.ALLOWLIST_TOKEN); 15914 } 15915 15916 @Test 15917 public void enqueueNotification_rejectsOtherToken() throws RemoteException { 15918 Notification sent = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15919 .setContentIntent(createPendingIntent("content")) 15920 .build(); 15921 sent.overrideAllowlistToken(new Binder()); 15922 Notification received = parcelAndUnparcel(sent, Notification.CREATOR); 15923 assertThat(received.getAllowlistToken()).isEqualTo(sent.getAllowlistToken()); 15924 15925 assertThrows(SecurityException.class, () -> 15926 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 15927 parcelAndUnparcel(received, Notification.CREATOR), mUserId)); 15928 waitForIdle(); 15929 15930 assertThat(mService.mNotificationList).isEmpty(); 15931 } 15932 15933 @Test 15934 public void enqueueNotification_customParcelingWithFakeInnerToken_hasCorrectTokenInIntents() 15935 throws RemoteException { 15936 Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) 15937 .setContentIntent(createPendingIntent("content")) 15938 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) 15939 .setContentIntent(createPendingIntent("public")) 15940 .build()) 15941 .build(); 15942 sentFromApp.publicVersion.overrideAllowlistToken(new Binder()); 15943 15944 // Instead of using the normal parceling, assume the caller parcels it by hand, including a 15945 // null token in the outer notification (as would be expected, and as is verified by 15946 // enqueue) but trying to sneak in a different one in the inner notification, hoping it gets 15947 // propagated to the PendingIntents. 15948 Parcel parcelSentFromApp = Parcel.obtain(); 15949 writeNotificationToParcelCustom(parcelSentFromApp, sentFromApp, new ArraySet<>( 15950 Lists.newArrayList(sentFromApp.contentIntent, 15951 sentFromApp.publicVersion.contentIntent))); 15952 15953 // Use the unparceling as received in enqueueNotificationWithTag() 15954 parcelSentFromApp.setDataPosition(0); 15955 Notification receivedByNms = new Notification(parcelSentFromApp); 15956 15957 // Verify that all the pendingIntents have the correct token. 15958 assertThat(receivedByNms.contentIntent.getWhitelistToken()).isEqualTo( 15959 NotificationManagerService.ALLOWLIST_TOKEN); 15960 assertThat(receivedByNms.publicVersion.contentIntent.getWhitelistToken()).isEqualTo( 15961 NotificationManagerService.ALLOWLIST_TOKEN); 15962 } 15963 15964 /** 15965 * Replicates the behavior of {@link Notification#writeToParcel} but excluding the 15966 * "always use the same allowlist token as the root notification" parts. 15967 */ 15968 private static void writeNotificationToParcelCustom(Parcel parcel, Notification notif, 15969 ArraySet<PendingIntent> allPendingIntents) { 15970 int flags = 0; 15971 parcel.writeInt(1); // version? 15972 15973 parcel.writeStrongBinder(notif.getAllowlistToken()); 15974 parcel.writeLong(notif.when); 15975 parcel.writeLong(notif.creationTime); 15976 if (notif.getSmallIcon() != null) { 15977 parcel.writeInt(1); 15978 notif.getSmallIcon().writeToParcel(parcel, 0); 15979 } else { 15980 parcel.writeInt(0); 15981 } 15982 parcel.writeInt(notif.number); 15983 if (notif.contentIntent != null) { 15984 parcel.writeInt(1); 15985 notif.contentIntent.writeToParcel(parcel, 0); 15986 } else { 15987 parcel.writeInt(0); 15988 } 15989 if (notif.deleteIntent != null) { 15990 parcel.writeInt(1); 15991 notif.deleteIntent.writeToParcel(parcel, 0); 15992 } else { 15993 parcel.writeInt(0); 15994 } 15995 if (notif.tickerText != null) { 15996 parcel.writeInt(1); 15997 TextUtils.writeToParcel(notif.tickerText, parcel, flags); 15998 } else { 15999 parcel.writeInt(0); 16000 } 16001 if (notif.tickerView != null) { 16002 parcel.writeInt(1); 16003 notif.tickerView.writeToParcel(parcel, 0); 16004 } else { 16005 parcel.writeInt(0); 16006 } 16007 if (notif.contentView != null) { 16008 parcel.writeInt(1); 16009 notif.contentView.writeToParcel(parcel, 0); 16010 } else { 16011 parcel.writeInt(0); 16012 } 16013 if (notif.getLargeIcon() != null) { 16014 parcel.writeInt(1); 16015 notif.getLargeIcon().writeToParcel(parcel, 0); 16016 } else { 16017 parcel.writeInt(0); 16018 } 16019 16020 parcel.writeInt(notif.defaults); 16021 parcel.writeInt(notif.flags); 16022 16023 if (notif.sound != null) { 16024 parcel.writeInt(1); 16025 notif.sound.writeToParcel(parcel, 0); 16026 } else { 16027 parcel.writeInt(0); 16028 } 16029 parcel.writeInt(notif.audioStreamType); 16030 16031 if (notif.audioAttributes != null) { 16032 parcel.writeInt(1); 16033 notif.audioAttributes.writeToParcel(parcel, 0); 16034 } else { 16035 parcel.writeInt(0); 16036 } 16037 16038 parcel.writeLongArray(notif.vibrate); 16039 parcel.writeInt(notif.ledARGB); 16040 parcel.writeInt(notif.ledOnMS); 16041 parcel.writeInt(notif.ledOffMS); 16042 parcel.writeInt(notif.iconLevel); 16043 16044 if (notif.fullScreenIntent != null) { 16045 parcel.writeInt(1); 16046 notif.fullScreenIntent.writeToParcel(parcel, 0); 16047 } else { 16048 parcel.writeInt(0); 16049 } 16050 16051 parcel.writeInt(notif.priority); 16052 16053 parcel.writeString8(notif.category); 16054 16055 parcel.writeString8(notif.getGroup()); 16056 16057 parcel.writeString8(notif.getSortKey()); 16058 16059 parcel.writeBundle(notif.extras); // null ok 16060 16061 parcel.writeTypedArray(notif.actions, 0); // null ok 16062 16063 if (notif.bigContentView != null) { 16064 parcel.writeInt(1); 16065 notif.bigContentView.writeToParcel(parcel, 0); 16066 } else { 16067 parcel.writeInt(0); 16068 } 16069 16070 if (notif.headsUpContentView != null) { 16071 parcel.writeInt(1); 16072 notif.headsUpContentView.writeToParcel(parcel, 0); 16073 } else { 16074 parcel.writeInt(0); 16075 } 16076 16077 parcel.writeInt(notif.visibility); 16078 16079 if (notif.publicVersion != null) { 16080 parcel.writeInt(1); 16081 writeNotificationToParcelCustom(parcel, notif.publicVersion, new ArraySet<>()); 16082 } else { 16083 parcel.writeInt(0); 16084 } 16085 16086 parcel.writeInt(notif.color); 16087 16088 if (notif.getChannelId() != null) { 16089 parcel.writeInt(1); 16090 parcel.writeString8(notif.getChannelId()); 16091 } else { 16092 parcel.writeInt(0); 16093 } 16094 parcel.writeLong(notif.getTimeoutAfter()); 16095 16096 if (notif.getShortcutId() != null) { 16097 parcel.writeInt(1); 16098 parcel.writeString8(notif.getShortcutId()); 16099 } else { 16100 parcel.writeInt(0); 16101 } 16102 16103 if (notif.getLocusId() != null) { 16104 parcel.writeInt(1); 16105 notif.getLocusId().writeToParcel(parcel, 0); 16106 } else { 16107 parcel.writeInt(0); 16108 } 16109 16110 parcel.writeInt(notif.getBadgeIconType()); 16111 16112 if (notif.getSettingsText() != null) { 16113 parcel.writeInt(1); 16114 TextUtils.writeToParcel(notif.getSettingsText(), parcel, flags); 16115 } else { 16116 parcel.writeInt(0); 16117 } 16118 16119 parcel.writeInt(notif.getGroupAlertBehavior()); 16120 16121 if (notif.getBubbleMetadata() != null) { 16122 parcel.writeInt(1); 16123 notif.getBubbleMetadata().writeToParcel(parcel, 0); 16124 } else { 16125 parcel.writeInt(0); 16126 } 16127 16128 parcel.writeBoolean(notif.getAllowSystemGeneratedContextualActions()); 16129 16130 parcel.writeInt(Notification.FOREGROUND_SERVICE_DEFAULT); // no getter for mFgsDeferBehavior 16131 16132 // mUsesStandardHeader is not written because it should be recomputed in listeners 16133 16134 parcel.writeArraySet(allPendingIntents); 16135 } 16136 16137 @Test 16138 @SuppressWarnings("unchecked") 16139 public void getActiveNotifications_doesNotLeakAllowlistToken() throws RemoteException { 16140 Notification sentFromApp = new Notification.Builder(mContext, TEST_CHANNEL_ID) 16141 .setContentIntent(createPendingIntent("content")) 16142 .setPublicVersion(new Notification.Builder(mContext, TEST_CHANNEL_ID) 16143 .setContentIntent(createPendingIntent("public")) 16144 .build()) 16145 .extend(new Notification.WearableExtender() 16146 .addPage(new Notification.Builder(mContext, TEST_CHANNEL_ID) 16147 .setContentIntent(createPendingIntent("wearPage")) 16148 .build())) 16149 .build(); 16150 // Binder transition: app -> NMS 16151 Notification receivedByNms = parcelAndUnparcel(sentFromApp, Notification.CREATOR); 16152 assertThat(receivedByNms.getAllowlistToken()).isEqualTo( 16153 NotificationManagerService.ALLOWLIST_TOKEN); 16154 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 16155 parcelAndUnparcel(receivedByNms, Notification.CREATOR), mUserId); 16156 waitForIdle(); 16157 assertThat(mService.mNotificationList).hasSize(1); 16158 Notification posted = mService.mNotificationList.get(0).getNotification(); 16159 assertThat(posted.getAllowlistToken()).isEqualTo( 16160 NotificationManagerService.ALLOWLIST_TOKEN); 16161 assertThat(posted.contentIntent.getWhitelistToken()).isEqualTo( 16162 NotificationManagerService.ALLOWLIST_TOKEN); 16163 16164 ParceledListSlice<StatusBarNotification> listSentFromNms = 16165 mBinderService.getAppActiveNotifications(mPkg, mUserId); 16166 // Binder transition: NMS -> app. App doesn't have the allowlist token so clear it 16167 // (having a different one would produce the same effect; the relevant thing is to not let 16168 // out ALLOWLIST_TOKEN). 16169 // Note: for other tests, this is restored by constructing TestableNMS in setup(). 16170 Notification.processAllowlistToken = null; 16171 ParceledListSlice<StatusBarNotification> listReceivedByApp = parcelAndUnparcel( 16172 listSentFromNms, ParceledListSlice.CREATOR); 16173 Notification gottenBackByApp = listReceivedByApp.getList().get(0).getNotification(); 16174 16175 assertThat(gottenBackByApp.getAllowlistToken()).isNull(); 16176 assertThat(gottenBackByApp.contentIntent.getWhitelistToken()).isNull(); 16177 assertThat(gottenBackByApp.publicVersion.getAllowlistToken()).isNull(); 16178 assertThat(gottenBackByApp.publicVersion.contentIntent.getWhitelistToken()).isNull(); 16179 assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() 16180 .get(0).getAllowlistToken()).isNull(); 16181 assertThat(new Notification.WearableExtender(gottenBackByApp).getPages() 16182 .get(0).contentIntent.getWhitelistToken()).isNull(); 16183 } 16184 16185 @Test 16186 public void enqueueNotification_allowlistsPendingIntents() throws RemoteException { 16187 PendingIntent contentIntent = createPendingIntent("content"); 16188 PendingIntent actionIntent1 = createPendingIntent("action1"); 16189 PendingIntent actionIntent2 = createPendingIntent("action2"); 16190 Notification n = new Notification.Builder(mContext, TEST_CHANNEL_ID) 16191 .setContentIntent(contentIntent) 16192 .addAction(new Notification.Action.Builder(null, "action1", actionIntent1).build()) 16193 .addAction(new Notification.Action.Builder(null, "action2", actionIntent2).build()) 16194 .build(); 16195 16196 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 16197 parcelAndUnparcel(n, Notification.CREATOR), mUserId); 16198 16199 verify(mAmi, times(3)).setPendingIntentAllowlistDuration( 16200 any(), any(), anyLong(), 16201 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED), 16202 eq(REASON_NOTIFICATION_SERVICE), any()); 16203 verify(mAmi, times(3)).setPendingIntentAllowBgActivityStarts(any(), 16204 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER)); 16205 contentIntent.cancel(); 16206 actionIntent2.cancel(); 16207 actionIntent1.cancel(); 16208 } 16209 16210 @Test 16211 public void enqueueNotification_allowlistsPendingIntents_includingFromPublicVersion() 16212 throws RemoteException { 16213 PendingIntent contentIntent = createPendingIntent("content"); 16214 PendingIntent actionIntent = createPendingIntent("action"); 16215 PendingIntent publicContentIntent = createPendingIntent("publicContent"); 16216 PendingIntent publicActionIntent = createPendingIntent("publicAction"); 16217 Notification source = new Notification.Builder(mContext, TEST_CHANNEL_ID) 16218 .setContentIntent(contentIntent) 16219 .addAction(new Notification.Action.Builder(null, "action", actionIntent).build()) 16220 .setPublicVersion(new Notification.Builder(mContext, "channel") 16221 .setContentIntent(publicContentIntent) 16222 .addAction(new Notification.Action.Builder( 16223 null, "publicAction", publicActionIntent).build()) 16224 .build()) 16225 .build(); 16226 16227 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 1, 16228 parcelAndUnparcel(source, Notification.CREATOR), mUserId); 16229 16230 verify(mAmi, times(4)).setPendingIntentAllowlistDuration( 16231 any(), any(), anyLong(), 16232 eq(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED), 16233 eq(REASON_NOTIFICATION_SERVICE), any()); 16234 verify(mAmi, times(4)).setPendingIntentAllowBgActivityStarts(any(), 16235 any(), eq(FLAG_ACTIVITY_SENDER | FLAG_BROADCAST_SENDER | FLAG_SERVICE_SENDER)); 16236 contentIntent.cancel(); 16237 publicContentIntent.cancel(); 16238 actionIntent.cancel(); 16239 publicActionIntent.cancel(); 16240 } 16241 16242 @Test 16243 @EnableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL) 16244 public void onUserSwitched_updatesZenModeAndChannelsBypassingDnd() { 16245 mService.mZenModeHelper = mock(ZenModeHelper.class); 16246 mService.setPreferencesHelper(mPreferencesHelper); 16247 16248 UserInfo prevUser = new UserInfo(); 16249 prevUser.id = 10; 16250 UserInfo newUser = new UserInfo(); 16251 newUser.id = 20; 16252 16253 mService.onUserSwitching(new TargetUser(prevUser), new TargetUser(newUser)); 16254 16255 InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper); 16256 inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20)); 16257 inOrder.verify(mPreferencesHelper).syncHasPriorityChannels(); 16258 inOrder.verifyNoMoreInteractions(); 16259 } 16260 16261 @Test 16262 @DisableFlags(Flags.FLAG_USE_SSM_USER_SWITCH_SIGNAL) 16263 public void onUserSwitched_broadcast_updatesZenModeAndChannelsBypassingDnd() { 16264 Intent intent = new Intent(Intent.ACTION_USER_SWITCHED); 16265 intent.putExtra(Intent.EXTRA_USER_HANDLE, 20); 16266 mService.mZenModeHelper = mock(ZenModeHelper.class); 16267 mService.setPreferencesHelper(mPreferencesHelper); 16268 16269 mUserIntentReceiver.onReceive(mContext, intent); 16270 16271 InOrder inOrder = inOrder(mPreferencesHelper, mService.mZenModeHelper); 16272 inOrder.verify(mService.mZenModeHelper).onUserSwitched(eq(20)); 16273 inOrder.verify(mPreferencesHelper).syncHasPriorityChannels(); 16274 inOrder.verifyNoMoreInteractions(); 16275 } 16276 16277 @Test 16278 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16279 public void onUserStopped_callBackToListeners() { 16280 Intent intent = new Intent(Intent.ACTION_USER_STOPPED); 16281 intent.putExtra(Intent.EXTRA_USER_HANDLE, 20); 16282 16283 mUserIntentReceiver.onReceive(mContext, intent); 16284 16285 verify(mConditionProviders).onUserStopped(eq(20)); 16286 verify(mListeners).onUserStopped(eq(20)); 16287 verify(mAssistants).onUserStopped(eq(20)); 16288 } 16289 16290 @Test 16291 @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16292 public void isNotificationPolicyAccessGranted_invalidPackage() throws Exception { 16293 final String notReal = "NOT REAL"; 16294 final var checker = mService.permissionChecker; 16295 16296 when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( 16297 PackageManager.NameNotFoundException.class); 16298 16299 assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse(); 16300 verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt()); 16301 verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean()); 16302 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt()); 16303 verify(mListeners, never()).isComponentEnabledForPackage(any()); 16304 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16305 } 16306 16307 @Test 16308 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16309 public void isNotificationPolicyAccessGranted_invalidPackage_concurrent_multiUser() 16310 throws Exception { 16311 final String notReal = "NOT REAL"; 16312 final var checker = mService.permissionChecker; 16313 16314 when(mPackageManagerClient.getPackageUidAsUser(eq(notReal), anyInt())).thenThrow( 16315 PackageManager.NameNotFoundException.class); 16316 16317 assertThat(mBinderService.isNotificationPolicyAccessGranted(notReal)).isFalse(); 16318 verify(mPackageManagerClient).getPackageUidAsUser(eq(notReal), anyInt()); 16319 verify(checker, never()).check(any(), anyInt(), anyInt(), anyBoolean()); 16320 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(notReal), anyInt()); 16321 verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt()); 16322 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16323 } 16324 16325 @Test 16326 @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16327 public void isNotificationPolicyAccessGranted_hasPermission() throws Exception { 16328 final String packageName = "target"; 16329 final int uid = 123; 16330 final var checker = mService.permissionChecker; 16331 16332 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16333 when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true)) 16334 .thenReturn(PackageManager.PERMISSION_GRANTED); 16335 16336 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16337 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16338 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16339 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16340 verify(mListeners, never()).isComponentEnabledForPackage(any()); 16341 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16342 } 16343 16344 @Test 16345 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16346 public void isNotificationPolicyAccessGranted_hasPermission_concurrent_multiUser() 16347 throws Exception { 16348 final String packageName = "target"; 16349 final int uid = 123; 16350 final var checker = mService.permissionChecker; 16351 16352 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16353 when(checker.check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true)) 16354 .thenReturn(PackageManager.PERMISSION_GRANTED); 16355 16356 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16357 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16358 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16359 verify(mConditionProviders, never()).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16360 verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt()); 16361 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16362 } 16363 16364 @Test 16365 @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16366 public void isNotificationPolicyAccessGranted_isPackageAllowed() throws Exception { 16367 final String packageName = "target"; 16368 final int uid = 123; 16369 final var checker = mService.permissionChecker; 16370 16371 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16372 when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt())) 16373 .thenReturn(true); 16374 16375 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16376 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16377 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16378 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16379 verify(mListeners, never()).isComponentEnabledForPackage(any()); 16380 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16381 } 16382 16383 @Test 16384 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16385 public void isNotificationPolicyAccessGranted_isPackageAllowed_concurrent_multiUser() 16386 throws Exception { 16387 final String packageName = "target"; 16388 final int uid = 123; 16389 final var checker = mService.permissionChecker; 16390 16391 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16392 when(mConditionProviders.isPackageOrComponentAllowed(eq(packageName), anyInt())) 16393 .thenReturn(true); 16394 16395 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16396 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16397 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16398 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16399 verify(mListeners, never()).isComponentEnabledForPackage(any(), anyInt()); 16400 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16401 } 16402 16403 @Test 16404 @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16405 public void isNotificationPolicyAccessGranted_isComponentEnabled() throws Exception { 16406 final String packageName = "target"; 16407 final int uid = 123; 16408 final var checker = mService.permissionChecker; 16409 16410 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16411 when(mListeners.isComponentEnabledForPackage(packageName)).thenReturn(true); 16412 16413 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16414 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16415 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16416 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16417 verify(mListeners).isComponentEnabledForPackage(packageName); 16418 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16419 } 16420 16421 @Test 16422 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16423 public void isNotificationPolicyAccessGranted_isComponentEnabled_concurrent_multiUser() 16424 throws Exception { 16425 final String packageName = "target"; 16426 final int uid = 123; 16427 final var checker = mService.permissionChecker; 16428 16429 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16430 when(mListeners.isComponentEnabledForPackage(packageName, mUserId)).thenReturn(true); 16431 16432 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16433 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16434 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16435 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16436 verify(mListeners).isComponentEnabledForPackage(packageName, mUserId); 16437 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(anyInt()); 16438 } 16439 16440 @Test 16441 @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16442 public void isNotificationPolicyAccessGranted_isDeviceOwner() throws Exception { 16443 final String packageName = "target"; 16444 final int uid = 123; 16445 final var checker = mService.permissionChecker; 16446 16447 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16448 when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true); 16449 16450 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16451 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16452 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16453 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16454 verify(mListeners).isComponentEnabledForPackage(packageName); 16455 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16456 } 16457 16458 @Test 16459 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16460 public void isNotificationPolicyAccessGranted_isDeviceOwner_concurrent_multiUser() 16461 throws Exception { 16462 final String packageName = "target"; 16463 final int uid = 123; 16464 final var checker = mService.permissionChecker; 16465 16466 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16467 when(mDevicePolicyManager.isActiveDeviceOwner(uid)).thenReturn(true); 16468 16469 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isTrue(); 16470 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16471 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16472 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16473 verify(mListeners).isComponentEnabledForPackage(packageName, mUserId); 16474 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16475 } 16476 16477 /** 16478 * b/292163859 16479 */ 16480 @Test 16481 @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16482 public void isNotificationPolicyAccessGranted_callerIsDeviceOwner() throws Exception { 16483 final String packageName = "target"; 16484 final int uid = 123; 16485 final int callingUid = Binder.getCallingUid(); 16486 final var checker = mService.permissionChecker; 16487 16488 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16489 when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true); 16490 16491 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 16492 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16493 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16494 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16495 verify(mListeners).isComponentEnabledForPackage(packageName); 16496 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16497 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid); 16498 } 16499 16500 /** 16501 * b/292163859 16502 */ 16503 @Test 16504 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16505 public void isNotificationPolicyAccessGranted_callerIsDeviceOwner_concurrent_multiUser() 16506 throws Exception { 16507 final String packageName = "target"; 16508 final int uid = 123; 16509 final int callingUid = Binder.getCallingUid(); 16510 final var checker = mService.permissionChecker; 16511 16512 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16513 when(mDevicePolicyManager.isActiveDeviceOwner(callingUid)).thenReturn(true); 16514 16515 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 16516 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16517 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16518 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16519 verify(mListeners).isComponentEnabledForPackage(packageName, mUserId); 16520 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16521 verify(mDevicePolicyManager, never()).isActiveDeviceOwner(callingUid); 16522 } 16523 16524 @Test 16525 @DisableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16526 public void isNotificationPolicyAccessGranted_notGranted() throws Exception { 16527 final String packageName = "target"; 16528 final int uid = 123; 16529 final var checker = mService.permissionChecker; 16530 16531 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16532 16533 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 16534 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16535 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16536 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16537 verify(mListeners).isComponentEnabledForPackage(packageName); 16538 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16539 } 16540 16541 @Test 16542 @EnableFlags(FLAG_MANAGED_SERVICES_CONCURRENT_MULTIUSER) 16543 public void isNotificationPolicyAccessGranted_notGranted_concurrent_multiUser() 16544 throws Exception { 16545 final String packageName = "target"; 16546 final int uid = 123; 16547 final var checker = mService.permissionChecker; 16548 16549 when(mPackageManagerClient.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid); 16550 16551 assertThat(mBinderService.isNotificationPolicyAccessGranted(packageName)).isFalse(); 16552 verify(mPackageManagerClient).getPackageUidAsUser(eq(packageName), anyInt()); 16553 verify(checker).check(android.Manifest.permission.MANAGE_NOTIFICATIONS, uid, -1, true); 16554 verify(mConditionProviders).isPackageOrComponentAllowed(eq(packageName), anyInt()); 16555 verify(mListeners).isComponentEnabledForPackage(packageName, mUserId); 16556 verify(mDevicePolicyManager).isActiveDeviceOwner(uid); 16557 } 16558 16559 @Test 16560 public void testResetDefaultDnd() { 16561 TestableNotificationManagerService service = spy(mService); 16562 UserInfo user = new UserInfo(0, "owner", 0); 16563 when(mUm.getAliveUsers()).thenReturn(List.of(user)); 16564 doReturn(false).when(service).isDNDMigrationDone(anyInt()); 16565 16566 service.resetDefaultDndIfNecessary(); 16567 16568 verify(mConditionProviders, times(1)).removeDefaultFromConfig(user.id); 16569 verify(mConditionProviders, times(1)).resetDefaultFromConfig(); 16570 verify(service, times(1)).allowDndPackages(user.id); 16571 verify(service, times(1)).setDNDMigrationDone(user.id); 16572 } 16573 16574 @Test 16575 public void testProfileUnavailableIntent() throws RemoteException { 16576 mSetFlagsRule.enableFlags(FLAG_ALLOW_PRIVATE_PROFILE, 16577 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 16578 simulateProfileAvailabilityActions(Intent.ACTION_PROFILE_UNAVAILABLE); 16579 verify(mWorkerHandler).post(any(Runnable.class)); 16580 verify(mSnoozeHelper).clearData(anyInt()); 16581 } 16582 16583 16584 @Test 16585 public void testManagedProfileUnavailableIntent() throws RemoteException { 16586 mSetFlagsRule.disableFlags(FLAG_ALLOW_PRIVATE_PROFILE, 16587 android.multiuser.Flags.FLAG_ENABLE_PRIVATE_SPACE_FEATURES); 16588 simulateProfileAvailabilityActions(Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE); 16589 verify(mWorkerHandler).post(any(Runnable.class)); 16590 verify(mSnoozeHelper).clearData(anyInt()); 16591 } 16592 16593 @Test 16594 public void setDeviceEffectsApplier_succeeds() throws Exception { 16595 initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY); 16596 16597 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)); 16598 16599 mService.onBootPhase(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START, mMainLooper); 16600 // No exception! 16601 } 16602 16603 @Test 16604 public void setDeviceEffectsApplier_tooLate_throws() throws Exception { 16605 initNMS(SystemService.PHASE_THIRD_PARTY_APPS_CAN_START); 16606 16607 assertThrows(IllegalStateException.class, () -> 16608 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class))); 16609 } 16610 16611 @Test 16612 public void setDeviceEffectsApplier_calledTwice_throws() throws Exception { 16613 initNMS(SystemService.PHASE_SYSTEM_SERVICES_READY); 16614 16615 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class)); 16616 assertThrows(IllegalStateException.class, () -> 16617 mInternalService.setDeviceEffectsApplier(mock(DeviceEffectsApplier.class))); 16618 } 16619 16620 @Test 16621 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16622 public void setNotificationPolicy_mappedToImplicitRule() throws RemoteException { 16623 mService.setCallerIsNormalPackage(); 16624 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 16625 mService.mZenModeHelper = zenHelper; 16626 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16627 .thenReturn(true); 16628 16629 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16630 mBinderService.setNotificationPolicy("package", policy, false); 16631 16632 verify(zenHelper).applyGlobalPolicyAsImplicitZenRule(any(), eq("package"), anyInt(), 16633 eq(policy)); 16634 } 16635 16636 @Test 16637 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16638 public void setNotificationPolicy_systemCaller_setsGlobalPolicy() throws RemoteException { 16639 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16640 mService.mZenModeHelper = zenModeHelper; 16641 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16642 .thenReturn(true); 16643 mService.isSystemUid = true; 16644 16645 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16646 mBinderService.setNotificationPolicy("package", policy, false); 16647 16648 verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt()); 16649 } 16650 16651 @Test 16652 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16653 public void setNotificationPolicy_watchCompanionApp_setsGlobalPolicy() 16654 throws RemoteException { 16655 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16656 AssociationRequest.DEVICE_PROFILE_WATCH, true); 16657 } 16658 16659 @Test 16660 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16661 public void setNotificationPolicy_autoCompanionApp_setsGlobalPolicy() 16662 throws RemoteException { 16663 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16664 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true); 16665 } 16666 16667 @Test 16668 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16669 public void setNotificationPolicy_otherCompanionApp_doesNotSetGlobalPolicy() 16670 throws RemoteException { 16671 setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16672 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false); 16673 } 16674 16675 private void setNotificationPolicy_dependingOnCompanionAppDevice_maySetGlobalPolicy( 16676 @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy) 16677 throws RemoteException { 16678 mService.setCallerIsNormalPackage(); 16679 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16680 mService.mZenModeHelper = zenModeHelper; 16681 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16682 .thenReturn(true); 16683 when(mCompanionMgr.getAssociations(anyString(), anyInt())) 16684 .thenReturn(ImmutableList.of( 16685 new AssociationInfo.Builder(1, mUserId, "package") 16686 .setDisplayName("My connected device") 16687 .setDeviceProfile(deviceProfile) 16688 .build())); 16689 16690 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16691 mBinderService.setNotificationPolicy("package", policy, false); 16692 16693 if (canSetGlobalPolicy) { 16694 verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt()); 16695 } else { 16696 verify(zenModeHelper).applyGlobalPolicyAsImplicitZenRule(any(), anyString(), anyInt(), 16697 eq(policy)); 16698 } 16699 } 16700 16701 @Test 16702 @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16703 public void setNotificationPolicy_withoutCompat_setsGlobalPolicy() throws RemoteException { 16704 mService.setCallerIsNormalPackage(); 16705 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16706 mService.mZenModeHelper = zenModeHelper; 16707 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16708 .thenReturn(true); 16709 16710 NotificationManager.Policy policy = new NotificationManager.Policy(0, 0, 0); 16711 mBinderService.setNotificationPolicy("package", policy, false); 16712 16713 verify(zenModeHelper).setNotificationPolicy(any(), eq(policy), anyInt(), anyInt()); 16714 } 16715 16716 @Test 16717 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16718 public void getNotificationPolicy_mappedFromImplicitRule() throws RemoteException { 16719 mService.setCallerIsNormalPackage(); 16720 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 16721 mService.mZenModeHelper = zenHelper; 16722 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16723 .thenReturn(true); 16724 16725 mBinderService.getNotificationPolicy("package"); 16726 16727 verify(zenHelper).getNotificationPolicyFromImplicitZenRule(any(), eq("package")); 16728 } 16729 16730 @Test 16731 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16732 public void setInterruptionFilter_mappedToImplicitRule() throws RemoteException { 16733 mService.setCallerIsNormalPackage(); 16734 ZenModeHelper zenHelper = mock(ZenModeHelper.class); 16735 mService.mZenModeHelper = zenHelper; 16736 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16737 .thenReturn(true); 16738 16739 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 16740 16741 verify(zenHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("package"), anyInt(), 16742 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 16743 } 16744 16745 @Test 16746 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16747 public void setInterruptionFilter_systemCaller_setsGlobalPolicy() throws RemoteException { 16748 mService.setCallerIsNormalPackage(); 16749 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16750 mService.mZenModeHelper = zenModeHelper; 16751 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16752 .thenReturn(true); 16753 mService.isSystemUid = true; 16754 16755 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 16756 16757 verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), 16758 eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM), anyString(), eq("package"), anyInt()); 16759 } 16760 16761 @Test 16762 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16763 public void setInterruptionFilter_watchCompanionApp_setsGlobalZen() throws RemoteException { 16764 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16765 AssociationRequest.DEVICE_PROFILE_WATCH, true); 16766 } 16767 16768 @Test 16769 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16770 public void setInterruptionFilter_autoCompanionApp_setsGlobalZen() throws RemoteException { 16771 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16772 AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION, true); 16773 } 16774 16775 @Test 16776 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16777 public void setInterruptionFilter_otherCompanionApp_doesNotSetGlobalZen() 16778 throws RemoteException { 16779 setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16780 AssociationRequest.DEVICE_PROFILE_NEARBY_DEVICE_STREAMING, false); 16781 } 16782 16783 private void setInterruptionFilter_dependingOnCompanionAppDevice_maySetGlobalZen( 16784 @AssociationRequest.DeviceProfile String deviceProfile, boolean canSetGlobalPolicy) 16785 throws RemoteException { 16786 ZenModeHelper zenModeHelper = mock(ZenModeHelper.class); 16787 mService.mZenModeHelper = zenModeHelper; 16788 mService.setCallerIsNormalPackage(); 16789 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16790 .thenReturn(true); 16791 when(mCompanionMgr.getAssociations(anyString(), anyInt())) 16792 .thenReturn(ImmutableList.of( 16793 new AssociationInfo.Builder(1, mUserId, "package") 16794 .setDisplayName("My connected device") 16795 .setDeviceProfile(deviceProfile) 16796 .build())); 16797 16798 mBinderService.setInterruptionFilter("package", INTERRUPTION_FILTER_PRIORITY, false); 16799 16800 if (canSetGlobalPolicy) { 16801 verify(zenModeHelper).setManualZenMode(any(), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), 16802 eq(null), eq(ZenModeConfig.ORIGIN_APP), anyString(), eq("package"), anyInt()); 16803 } else { 16804 verify(zenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), anyString(), anyInt(), 16805 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 16806 } 16807 } 16808 16809 @Test 16810 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16811 public void requestInterruptionFilterFromListener_fromApp_doesNotSetGlobalZen() 16812 throws Exception { 16813 mService.setCallerIsNormalPackage(); 16814 mService.mZenModeHelper = mock(ZenModeHelper.class); 16815 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 16816 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 16817 info.component = new ComponentName("pkg", "cls"); 16818 16819 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 16820 INTERRUPTION_FILTER_PRIORITY); 16821 16822 verify(mService.mZenModeHelper).applyGlobalZenModeAsImplicitZenRule(any(), eq("pkg"), 16823 eq(mUid), eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS)); 16824 } 16825 16826 @Test 16827 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16828 public void requestInterruptionFilterFromListener_fromSystem_setsGlobalZen() 16829 throws Exception { 16830 mService.isSystemUid = true; 16831 mService.mZenModeHelper = mock(ZenModeHelper.class); 16832 ManagedServices.ManagedServiceInfo info = mock(ManagedServices.ManagedServiceInfo.class); 16833 when(mListeners.checkServiceTokenLocked(any())).thenReturn(info); 16834 info.component = new ComponentName("pkg", "cls"); 16835 16836 mBinderService.requestInterruptionFilterFromListener(mock(INotificationListener.class), 16837 INTERRUPTION_FILTER_PRIORITY); 16838 16839 verify(mService.mZenModeHelper).setManualZenMode(any(), 16840 eq(ZEN_MODE_IMPORTANT_INTERRUPTIONS), eq(null), eq(ZenModeConfig.ORIGIN_SYSTEM), 16841 anyString(), eq("pkg"), eq(mUid)); 16842 } 16843 16844 @Test 16845 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16846 public void updateAutomaticZenRule_implicitRuleWithoutCPS_disallowedFromApp() throws Exception { 16847 setUpRealZenTest(); 16848 mService.setCallerIsNormalPackage(); 16849 assertThat(mBinderService.getAutomaticZenRules().getList()).isEmpty(); 16850 16851 // Create an implicit zen rule by calling setNotificationPolicy from an app. 16852 mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false); 16853 assertThat(mBinderService.getAutomaticZenRules().getList()).hasSize(1); 16854 AutomaticZenRule.AzrWithId rule = getOnlyElement( 16855 (List<AutomaticZenRule.AzrWithId>) mBinderService.getAutomaticZenRules().getList()); 16856 assertThat(rule.mRule.getOwner()).isNull(); 16857 assertThat(rule.mRule.getConfigurationActivity()).isNull(); 16858 16859 // Now try to update said rule (e.g. disable it). Should fail. 16860 // We also validate the exception message because NPE could be thrown by all sorts of test 16861 // issues (e.g. misconfigured mocks). 16862 rule.mRule.setEnabled(false); 16863 NullPointerException e = assertThrows(NullPointerException.class, 16864 () -> mBinderService.updateAutomaticZenRule(rule.mId, rule.mRule, false)); 16865 assertThat(e.getMessage()).isEqualTo( 16866 "Rule must have a ConditionProviderService and/or configuration activity"); 16867 } 16868 16869 @Test 16870 @EnableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16871 public void updateAutomaticZenRule_implicitRuleWithoutCPS_allowedFromSystem() throws Exception { 16872 setUpRealZenTest(); 16873 mService.setCallerIsNormalPackage(); 16874 assertThat(mBinderService.getAutomaticZenRules().getList()).isEmpty(); 16875 16876 // Create an implicit zen rule by calling setNotificationPolicy from an app. 16877 mBinderService.setNotificationPolicy(mPkg, new NotificationManager.Policy(0, 0, 0), false); 16878 assertThat(mBinderService.getAutomaticZenRules().getList()).hasSize(1); 16879 AutomaticZenRule.AzrWithId rule = getOnlyElement( 16880 (List<AutomaticZenRule.AzrWithId>) mBinderService.getAutomaticZenRules().getList()); 16881 assertThat(rule.mRule.getOwner()).isNull(); 16882 assertThat(rule.mRule.getConfigurationActivity()).isNull(); 16883 16884 // Now update said rule from Settings (e.g. disable it). Should work! 16885 mService.isSystemUid = true; 16886 rule.mRule.setEnabled(false); 16887 mBinderService.updateAutomaticZenRule(rule.mId, rule.mRule, false); 16888 16889 AutomaticZenRule.AzrWithId updatedRule = getOnlyElement( 16890 (List<AutomaticZenRule.AzrWithId>) mBinderService.getAutomaticZenRules().getList()); 16891 assertThat(updatedRule.mRule.isEnabled()).isFalse(); 16892 } 16893 16894 @Test 16895 @EnableFlags(android.app.Flags.FLAG_MODES_UI) 16896 public void setNotificationPolicy_fromSystemApp_appliesPriorityChannelsAllowed() 16897 throws Exception { 16898 setUpRealZenTest(); 16899 // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default"). 16900 mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, 16901 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0), 16902 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID); 16903 16904 // The caller will supply states with "wrong" hasPriorityChannels. 16905 int stateBlockingPriorityChannels = Policy.policyState(false, false); 16906 mBinderService.setNotificationPolicy(mPkg, 16907 new Policy(1, 0, 0, 0, stateBlockingPriorityChannels, 0), false); 16908 16909 // hasPriorityChannels is untouched and allowPriorityChannels was updated. 16910 assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1); 16911 assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo( 16912 Policy.policyState(true, false)); 16913 16914 // Same but setting allowPriorityChannels to true. 16915 int stateAllowingPriorityChannels = Policy.policyState(false, true); 16916 mBinderService.setNotificationPolicy(mPkg, 16917 new Policy(2, 0, 0, 0, stateAllowingPriorityChannels, 0), false); 16918 16919 assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(2); 16920 assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo( 16921 Policy.policyState(true, true)); 16922 } 16923 16924 @Test 16925 @EnableFlags(android.app.Flags.FLAG_MODES_UI) 16926 @DisableCompatChanges(NotificationManagerService.MANAGE_GLOBAL_ZEN_VIA_IMPLICIT_RULES) 16927 public void setNotificationPolicy_fromRegularAppThatCanModifyPolicy_ignoresState() 16928 throws Exception { 16929 setUpRealZenTest(); 16930 // Start with hasPriorityChannels=true, allowPriorityChannels=true ("default"). 16931 mService.mZenModeHelper.setNotificationPolicy(UserHandle.CURRENT, 16932 new Policy(0, 0, 0, 0, Policy.policyState(true, true), 0), 16933 ZenModeConfig.ORIGIN_SYSTEM, Process.SYSTEM_UID); 16934 mService.setCallerIsNormalPackage(); 16935 16936 mBinderService.setNotificationPolicy(mPkg, 16937 new Policy(1, 0, 0, 0, Policy.policyState(false, false), 0), false); 16938 16939 // Policy was updated but the attempt to change state was ignored (it's a @hide API). 16940 assertThat(mBinderService.getNotificationPolicy(mPkg).priorityCategories).isEqualTo(1); 16941 assertThat(mBinderService.getNotificationPolicy(mPkg).state).isEqualTo( 16942 Policy.policyState(true, true)); 16943 } 16944 16945 /** Prepares for a zen-related test that uses the real {@link ZenModeHelper}. */ 16946 private void setUpRealZenTest() throws Exception { 16947 when(mConditionProviders.isPackageOrComponentAllowed(anyString(), anyInt())) 16948 .thenReturn(true); 16949 16950 int iconResId = 79; 16951 String iconResName = "icon_79"; 16952 String pkg = mContext.getPackageName(); 16953 ApplicationInfo appInfoSpy = spy(new ApplicationInfo()); 16954 appInfoSpy.icon = iconResId; 16955 when(appInfoSpy.loadLabel(any())).thenReturn("Test App"); 16956 when(mPackageManagerClient.getApplicationInfo(eq(pkg), anyInt())).thenReturn(appInfoSpy); 16957 16958 when(mResources.getResourceName(eq(iconResId))).thenReturn(iconResName); 16959 when(mResources.getIdentifier(eq(iconResName), any(), any())).thenReturn(iconResId); 16960 when(mPackageManagerClient.getResourcesForApplication(eq(pkg))).thenReturn(mResources); 16961 16962 // Ensure that there is a zen configuration for the user running the test (won't be 16963 // USER_SYSTEM if running on HSUM). 16964 mService.mZenModeHelper.onUserSwitched(mUserId); 16965 } 16966 16967 @Test 16968 @EnableFlags(android.app.Flags.FLAG_LIFETIME_EXTENSION_REFACTOR) 16969 public void testFixNotification_clearsLifetimeExtendedFlag() throws Exception { 16970 Notification n = new Notification.Builder(mContext, "test") 16971 .setFlag(FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY, true) 16972 .build(); 16973 16974 assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isGreaterThan(0); 16975 16976 mService.fixNotification(n, mPkg, "tag", 9, 0, mUid, NOT_FOREGROUND_SERVICE, true); 16977 16978 assertThat(n.flags & FLAG_LIFETIME_EXTENDED_BY_DIRECT_REPLY).isEqualTo(0); 16979 } 16980 16981 @Test 16982 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne() 16983 throws RemoteException { 16984 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 16985 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 16986 16987 // Create recent notification. 16988 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 16989 System.currentTimeMillis()); 16990 mService.addNotification(nr1); 16991 16992 // Create old notification. 16993 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 16994 System.currentTimeMillis() - 60000); 16995 mService.addNotification(nr2); 16996 16997 // Cancel specific notifications via listener. 16998 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 16999 mService.getBinderService().cancelNotificationsFromListener(null, keys); 17000 waitForIdle(); 17001 17002 // Notifications should not be active anymore. 17003 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 17004 assertThat(notifications).isEmpty(); 17005 assertEquals(0, mService.getNotificationRecordCount()); 17006 // Ensure cancel event is logged. 17007 verify(mAppOpsManager).noteOpNoThrow( 17008 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null); 17009 } 17010 17011 @Test 17012 public void cancelNotificationsFromListener_rapidClear_old_cancelOne() throws RemoteException { 17013 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 17014 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 17015 17016 // Create old notifications. 17017 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 17018 System.currentTimeMillis() - 60000); 17019 mService.addNotification(nr1); 17020 17021 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 17022 System.currentTimeMillis() - 60000); 17023 mService.addNotification(nr2); 17024 17025 // Cancel specific notifications via listener. 17026 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 17027 mService.getBinderService().cancelNotificationsFromListener(null, keys); 17028 waitForIdle(); 17029 17030 // Notifications should not be active anymore. 17031 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 17032 assertThat(notifications).isEmpty(); 17033 assertEquals(0, mService.getNotificationRecordCount()); 17034 // Ensure cancel event is not logged. 17035 verify(mAppOpsManager, never()).noteOpNoThrow( 17036 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 17037 any(), any()); 17038 } 17039 17040 @Test 17041 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelOne_flagDisabled() 17042 throws RemoteException { 17043 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 17044 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 17045 17046 // Create recent notification. 17047 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 17048 System.currentTimeMillis()); 17049 mService.addNotification(nr1); 17050 17051 // Create old notification. 17052 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 17053 System.currentTimeMillis() - 60000); 17054 mService.addNotification(nr2); 17055 17056 // Cancel specific notifications via listener. 17057 String[] keys = {nr1.getSbn().getKey(), nr2.getSbn().getKey()}; 17058 mService.getBinderService().cancelNotificationsFromListener(null, keys); 17059 waitForIdle(); 17060 17061 // Notifications should not be active anymore. 17062 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 17063 assertThat(notifications).isEmpty(); 17064 assertEquals(0, mService.getNotificationRecordCount()); 17065 // Ensure cancel event is not logged due to flag being disabled. 17066 verify(mAppOpsManager, never()).noteOpNoThrow( 17067 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 17068 any(), any()); 17069 } 17070 17071 @Test 17072 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll() 17073 throws RemoteException { 17074 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 17075 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 17076 17077 // Create recent notification. 17078 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 17079 System.currentTimeMillis()); 17080 mService.addNotification(nr1); 17081 17082 // Create old notification. 17083 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 17084 System.currentTimeMillis() - 60000); 17085 mService.addNotification(nr2); 17086 17087 // Cancel all notifications via listener. 17088 mService.getBinderService().cancelNotificationsFromListener(null, null); 17089 waitForIdle(); 17090 17091 // Notifications should not be active anymore. 17092 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 17093 assertThat(notifications).isEmpty(); 17094 assertEquals(0, mService.getNotificationRecordCount()); 17095 // Ensure cancel event is logged. 17096 verify(mAppOpsManager).noteOpNoThrow( 17097 AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER, mUid, mPkg, null, null); 17098 } 17099 17100 @Test 17101 public void cancelNotificationsFromListener_rapidClear_old_cancelAll() throws RemoteException { 17102 mSetFlagsRule.enableFlags(android.view.contentprotection.flags.Flags 17103 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 17104 17105 // Create old notifications. 17106 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 17107 System.currentTimeMillis() - 60000); 17108 mService.addNotification(nr1); 17109 17110 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 17111 System.currentTimeMillis() - 60000); 17112 mService.addNotification(nr2); 17113 17114 // Cancel all notifications via listener. 17115 mService.getBinderService().cancelNotificationsFromListener(null, null); 17116 waitForIdle(); 17117 17118 // Notifications should not be active anymore. 17119 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 17120 assertThat(notifications).isEmpty(); 17121 assertEquals(0, mService.getNotificationRecordCount()); 17122 // Ensure cancel event is not logged. 17123 verify(mAppOpsManager, never()).noteOpNoThrow( 17124 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 17125 any(), any()); 17126 } 17127 17128 @Test 17129 public void cancelNotificationsFromListener_rapidClear_oldNew_cancelAll_flagDisabled() 17130 throws RemoteException { 17131 mSetFlagsRule.disableFlags(android.view.contentprotection.flags.Flags 17132 .FLAG_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER_APP_OP_ENABLED); 17133 17134 // Create recent notification. 17135 final NotificationRecord nr1 = generateNotificationRecord(mTestNotificationChannel, 17136 System.currentTimeMillis()); 17137 mService.addNotification(nr1); 17138 17139 // Create old notification. 17140 final NotificationRecord nr2 = generateNotificationRecord(mTestNotificationChannel, 17141 System.currentTimeMillis() - 60000); 17142 mService.addNotification(nr2); 17143 17144 // Cancel all notifications via listener. 17145 mService.getBinderService().cancelNotificationsFromListener(null, null); 17146 waitForIdle(); 17147 17148 // Notifications should not be active anymore. 17149 StatusBarNotification[] notifications = mBinderService.getActiveNotifications(mPkg); 17150 assertThat(notifications).isEmpty(); 17151 assertEquals(0, mService.getNotificationRecordCount()); 17152 // Ensure cancel event is not logged due to flag being disabled. 17153 verify(mAppOpsManager, never()).noteOpNoThrow( 17154 eq(AppOpsManager.OP_RAPID_CLEAR_NOTIFICATIONS_BY_LISTENER), anyInt(), anyString(), 17155 any(), any()); 17156 } 17157 17158 @Test 17159 @EnableFlags(FLAG_KEYGUARD_PRIVATE_NOTIFICATIONS) 17160 public void testSetPrivateNotificationsAllowed() throws Exception { 17161 when(mContext.checkCallingPermission(CONTROL_KEYGUARD_SECURE_NOTIFICATIONS)) 17162 .thenReturn(PERMISSION_GRANTED); 17163 mBinderService.setPrivateNotificationsAllowed(false); 17164 Intent expected = new Intent(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED) 17165 .putExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, false); 17166 ArgumentCaptor<Intent> actual = ArgumentCaptor.forClass(Intent.class); 17167 verify(mContext).sendBroadcast(actual.capture(), eq(STATUS_BAR_SERVICE)); 17168 17169 assertEquals(ACTION_KEYGUARD_PRIVATE_NOTIFICATIONS_CHANGED, actual.getValue().getAction()); 17170 assertFalse(actual.getValue().getBooleanExtra(EXTRA_KM_PRIVATE_NOTIFS_ALLOWED, true)); 17171 assertFalse(mBinderService.getPrivateNotificationsAllowed()); 17172 } 17173 17174 @Test 17175 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 17176 public void testCallNotificationListener_NotifiedOnPostCallStyle() throws Exception { 17177 ICallNotificationEventCallback listener = mock( 17178 ICallNotificationEventCallback.class); 17179 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 17180 mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.CURRENT, listener); 17181 waitForIdle(); 17182 17183 final UserHandle userHandle = UserHandle.getUserHandleForUid(mUid); 17184 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, userHandle, 17185 "testCallNotificationListener_NotifiedOnPostCallStyle"); 17186 17187 verify(listener, times(1)).onCallNotificationPosted(mPkg, userHandle); 17188 17189 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 17190 r.getSbn().getUserId()); 17191 waitForIdle(); 17192 17193 verify(listener, times(1)).onCallNotificationRemoved(mPkg, userHandle); 17194 } 17195 17196 @Test 17197 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 17198 public void testCallNotificationListener_NotNotifiedOnPostNonCallStyle() throws Exception { 17199 ICallNotificationEventCallback listener = mock( 17200 ICallNotificationEventCallback.class); 17201 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 17202 mBinderService.registerCallNotificationEventListener(mPkg, 17203 UserHandle.getUserHandleForUid(mUid), listener); 17204 waitForIdle(); 17205 17206 Notification.Builder nb = new Notification.Builder(mContext, 17207 mTestNotificationChannel.getId()).setSmallIcon(android.R.drawable.sym_def_app_icon); 17208 final NotificationRecord r = createAndPostNotification(nb, 17209 "testCallNotificationListener_NotNotifiedOnPostNonCallStyle"); 17210 17211 verify(listener, never()).onCallNotificationPosted(anyString(), any()); 17212 17213 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 17214 r.getSbn().getUserId()); 17215 waitForIdle(); 17216 17217 verify(listener, never()).onCallNotificationRemoved(anyString(), any()); 17218 } 17219 17220 @Test 17221 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 17222 public void testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId() 17223 throws Exception { 17224 ICallNotificationEventCallback listener = mock( 17225 ICallNotificationEventCallback.class); 17226 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 17227 mBinderService.registerCallNotificationEventListener(mPkg, UserHandle.ALL, listener); 17228 waitForIdle(); 17229 17230 final UserHandle otherUser = UserHandle.of(2); 17231 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, 17232 otherUser, "testCallNotificationListener_registerForUserAll_notifiedOnAnyUserId"); 17233 17234 verify(listener, times(1)).onCallNotificationPosted(mPkg, otherUser); 17235 17236 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 17237 r.getSbn().getUserId()); 17238 waitForIdle(); 17239 17240 verify(listener, times(1)).onCallNotificationRemoved(mPkg, otherUser); 17241 } 17242 17243 @Test 17244 @EnableFlags(android.service.notification.Flags.FLAG_CALLSTYLE_CALLBACK_API) 17245 public void testCallNotificationListener_differentPackage_notNotified() throws Exception { 17246 final String packageName = "package"; 17247 ICallNotificationEventCallback listener = mock( 17248 ICallNotificationEventCallback.class); 17249 when(listener.asBinder()).thenReturn(mock(IBinder.class)); 17250 mBinderService.registerCallNotificationEventListener(packageName, UserHandle.ALL, listener); 17251 waitForIdle(); 17252 17253 final NotificationRecord r = createAndPostCallStyleNotification(mPkg, 17254 UserHandle.of(mUserId), 17255 "testCallNotificationListener_differentPackage_notNotified"); 17256 17257 verify(listener, never()).onCallNotificationPosted(anyString(), any()); 17258 17259 mBinderService.cancelNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), r.getSbn().getId(), 17260 r.getSbn().getUserId()); 17261 waitForIdle(); 17262 17263 verify(listener, never()).onCallNotificationRemoved(anyString(), any()); 17264 } 17265 17266 @Test 17267 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17268 public void rankingTime_newNotification_noisy_matchesSbn() throws Exception { 17269 NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel, mUserId); 17270 17271 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17272 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17273 waitForIdle(); 17274 17275 NotificationRecord posted = mService.mNotificationList.get(0); 17276 long originalPostTime = posted.getSbn().getPostTime(); 17277 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17278 } 17279 17280 @Test 17281 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17282 public void rankingTime_newNotification_silent_matchesSbn() throws Exception { 17283 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17284 NotificationRecord nr = generateNotificationRecord(low, mUserId); 17285 17286 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17287 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17288 waitForIdle(); 17289 17290 NotificationRecord posted = mService.mNotificationList.get(0); 17291 long originalPostTime = posted.getSbn().getPostTime(); 17292 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17293 } 17294 17295 @Test 17296 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17297 public void rankingTime_updatedNotification_silentSameText_originalPostTime() throws Exception { 17298 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17299 NotificationRecord nr = generateNotificationRecord(low, mUserId); 17300 17301 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17302 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17303 waitForIdle(); 17304 NotificationRecord posted = mService.mNotificationList.get(0); 17305 long originalPostTime = posted.getSbn().getPostTime(); 17306 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17307 17308 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17309 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17310 waitForIdle(); 17311 assertThat(mService.mNotificationList.get(0).getRankingTimeMs()) 17312 .isEqualTo(originalPostTime); 17313 } 17314 17315 @Test 17316 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17317 public void rankingTime_updatedNotification_silentNewText_newPostTime() throws Exception { 17318 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17319 NotificationRecord nr = generateNotificationRecord(low, 0, mUserId); 17320 17321 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17322 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17323 waitForIdle(); 17324 NotificationRecord posted = mService.mNotificationList.get(0); 17325 long originalPostTime = posted.getSbn().getPostTime(); 17326 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17327 17328 NotificationRecord nrUpdate = generateNotificationRecord(low, 0, mUserId, "bar"); 17329 // no attention helper mocked behavior needed because this does not make noise 17330 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17331 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(), 17332 nrUpdate.getSbn().getUserId()); 17333 waitForIdle(); 17334 17335 posted = mService.mNotificationList.get(0); 17336 assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime); 17337 assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime()); 17338 } 17339 17340 @Test 17341 @EnableFlags(FLAG_SORT_SECTION_BY_TIME) 17342 public void rankingTime_updatedNotification_noisySameText_newPostTime() throws Exception { 17343 NotificationChannel low = new NotificationChannel("low", "low", IMPORTANCE_LOW); 17344 NotificationRecord nr = generateNotificationRecord(low, mUserId); 17345 17346 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17347 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 17348 waitForIdle(); 17349 NotificationRecord posted = mService.mNotificationList.get(0); 17350 long originalPostTime = posted.getSbn().getPostTime(); 17351 assertThat(posted.getRankingTimeMs()).isEqualTo(originalPostTime); 17352 17353 NotificationRecord nrUpdate = generateNotificationRecord(mTestNotificationChannel, mUserId); 17354 when(mAttentionHelper.buzzBeepBlinkLocked(any(), any())).thenAnswer(new Answer<Object>() { 17355 public Object answer(InvocationOnMock invocation) { 17356 Object[] args = invocation.getArguments(); 17357 ((NotificationRecord) args[0]).resetRankingTime(); 17358 return 2; // beep 17359 } 17360 }); 17361 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag0", 17362 nrUpdate.getSbn().getId(), nrUpdate.getSbn().getNotification(), 17363 nrUpdate.getSbn().getUserId()); 17364 waitForIdle(); 17365 posted = mService.mNotificationList.get(0); 17366 assertThat(posted.getRankingTimeMs()).isGreaterThan(originalPostTime); 17367 assertThat(posted.getRankingTimeMs()).isEqualTo(posted.getSbn().getPostTime()); 17368 } 17369 17370 @Test 17371 @EnableFlags(android.app.Flags.FLAG_RESTRICT_AUDIO_ATTRIBUTES_MEDIA) 17372 public void testRestrictAudioAttributes_listenersGetCorrectAttributes() throws Exception { 17373 NotificationChannel sound = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT); 17374 sound.setSound(Uri.EMPTY, new AudioAttributes.Builder().setUsage(USAGE_MEDIA).build()); 17375 mBinderService.createNotificationChannels(mPkg, new ParceledListSlice( 17376 Arrays.asList(sound))); 17377 17378 Notification n = new Notification.Builder(mContext, "a") 17379 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17380 .build(); 17381 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17382 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17383 17384 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 17385 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 17386 waitForIdle(); 17387 17388 ArgumentCaptor<NotificationRecord> captor = 17389 ArgumentCaptor.forClass(NotificationRecord.class); 17390 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17391 captor.capture(), any(), anyBoolean()); 17392 17393 assertThat(captor.getValue().getChannel().getAudioAttributes().getUsage()) 17394 .isEqualTo(USAGE_NOTIFICATION); 17395 } 17396 17397 @Test 17398 @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL) 17399 public void testFixNotification_missingTtl() throws Exception { 17400 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17401 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17402 .build(); 17403 17404 mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 17405 17406 assertThat(n.getTimeoutAfter()).isEqualTo(NOTIFICATION_TTL); 17407 } 17408 17409 @Test 17410 @EnableFlags(FLAG_ALL_NOTIFS_NEED_TTL) 17411 public void testFixNotification_doesNotOverwriteTtl() throws Exception { 17412 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17413 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17414 .setTimeoutAfter(20) 17415 .build(); 17416 17417 mService.fixNotification(n, mPkg, "tag", 0, mUserId, mUid, NOT_FOREGROUND_SERVICE, true); 17418 17419 assertThat(n.getTimeoutAfter()).isEqualTo(20); 17420 } 17421 17422 @Test 17423 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 17424 public void testRejectOldNotification_oldWhen() throws Exception { 17425 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17426 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17427 .setWhen(System.currentTimeMillis() - Duration.ofDays(15).toMillis()) 17428 .build(); 17429 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17430 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17431 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17432 17433 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 17434 .isFalse(); 17435 } 17436 17437 @Test 17438 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 17439 public void testRejectOldNotification_mediumOldWhen() throws Exception { 17440 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17441 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17442 .setWhen(System.currentTimeMillis() - Duration.ofDays(13).toMillis()) 17443 .build(); 17444 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17445 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17446 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17447 17448 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 17449 .isTrue(); 17450 } 17451 17452 @Test 17453 @EnableFlags(FLAG_REJECT_OLD_NOTIFICATIONS) 17454 public void testRejectOldNotification_zeroWhen() throws Exception { 17455 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17456 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17457 .setWhen(0) 17458 .build(); 17459 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17460 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17461 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17462 17463 assertThat(mService.checkDisqualifyingFeatures(mUserId, mUid, 0, null, r, false, false)) 17464 .isTrue(); 17465 } 17466 17467 @Test 17468 public void testClearUIJFromUninstallingPackage() throws Exception { 17469 NotificationRecord r = 17470 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar"); 17471 mService.addNotification(r); 17472 17473 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())) 17474 .thenThrow(PackageManager.NameNotFoundException.class); 17475 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17476 17477 mInternalService.cancelNotification(mPkg, mPkg, mUid, 0, r.getSbn().getTag(), 17478 r.getSbn().getId(), mUserId); 17479 17480 // no exception 17481 } 17482 17483 @Test 17484 public void testPostFromMissingPackage_throws() throws Exception { 17485 NotificationRecord r = 17486 generateNotificationRecord(mTestNotificationChannel, 0, mUserId, "bar"); 17487 17488 when(mPackageManagerClient.getPackageUidAsUser(anyString(), anyInt())) 17489 .thenThrow(PackageManager.NameNotFoundException.class); 17490 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17491 17492 try { 17493 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, r.getSbn().getTag(), 17494 r.getSbn().getId(), r.getSbn().getNotification(), 17495 r.getSbn().getUserId()); 17496 fail("Allowed to post a notification for an absent package"); 17497 } catch (SecurityException e) { 17498 // yay 17499 } 17500 } 17501 17502 @Test 17503 public void testGetEffectsSuppressor_noSuppressor() throws Exception { 17504 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17505 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17506 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true); 17507 assertThat(mBinderService.getEffectsSuppressor()).isNull(); 17508 } 17509 17510 @Test 17511 public void testGetEffectsSuppressor_suppressorSameApp() throws Exception { 17512 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17513 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17514 mService.isSystemUid = false; 17515 mService.isSystemAppId = false; 17516 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 17517 HINT_HOST_DISABLE_EFFECTS); 17518 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(true); 17519 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); 17520 } 17521 17522 @Test 17523 public void testGetEffectsSuppressor_suppressorDiffApp() throws Exception { 17524 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17525 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17526 mService.isSystemUid = false; 17527 mService.isSystemAppId = false; 17528 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 17529 HINT_HOST_DISABLE_EFFECTS); 17530 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17531 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(null); 17532 } 17533 17534 @Test 17535 public void testGetEffectsSuppressor_suppressorDiffAppSystemCaller() throws Exception { 17536 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17537 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17538 mService.isSystemUid = true; 17539 mBinderService.requestHintsFromListener(mock(INotificationListener.class), 17540 HINT_HOST_DISABLE_EFFECTS); 17541 when(mPackageManagerInternal.isSameApp(anyString(), anyInt(), anyInt())).thenReturn(false); 17542 assertThat(mBinderService.getEffectsSuppressor()).isEqualTo(mListener.component); 17543 } 17544 17545 @Test 17546 @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST, 17547 Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS}) 17548 public void requestHintsFromListener_changingEffectsButNotSuppressor_noBroadcast() 17549 throws Exception { 17550 // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each 17551 // path will do slightly different calls so we force one of them to simplify the test. 17552 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17553 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17554 INotificationListener token = mock(INotificationListener.class); 17555 mService.isSystemUid = true; 17556 17557 mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); 17558 mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY 17559 waitForIdle(); 17560 17561 verify(mContext, times(1)).sendBroadcastMultiplePermissions( 17562 isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); 17563 17564 // Same suppressor suppresses something else. 17565 mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 17566 mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY 17567 waitForIdle(); 17568 17569 // Still 1 total calls (the previous one). 17570 verify(mContext, times(1)).sendBroadcastMultiplePermissions( 17571 isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); 17572 } 17573 17574 @Test 17575 @EnableFlags({Flags.FLAG_NM_BINDER_PERF_THROTTLE_EFFECTS_SUPPRESSOR_BROADCAST, 17576 Flags.FLAG_NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS}) 17577 public void requestHintsFromListener_changingSuppressor_throttlesBroadcast() throws Exception { 17578 // Note that NM_BINDER_PERF_REDUCE_ZEN_BROADCASTS is not strictly necessary; however each 17579 // path will do slightly different calls so we force one of them to simplify the test. 17580 when(mUmInternal.getProfileIds(anyInt(), anyBoolean())).thenReturn(new int[]{mUserId}); 17581 when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener); 17582 INotificationListener token = mock(INotificationListener.class); 17583 mService.isSystemUid = true; 17584 17585 // Several updates in quick succession. 17586 mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); 17587 mBinderService.clearRequestedListenerHints(token); 17588 mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 17589 mBinderService.clearRequestedListenerHints(token); 17590 mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_CALL_EFFECTS); 17591 mBinderService.clearRequestedListenerHints(token); 17592 mBinderService.requestHintsFromListener(token, HINT_HOST_DISABLE_NOTIFICATION_EFFECTS); 17593 17594 // No broadcasts yet! 17595 verify(mContext, never()).sendBroadcastMultiplePermissions(any(), any(), any(), any()); 17596 17597 mTestableLooper.moveTimeForward(500); // more than ZEN_BROADCAST_DELAY 17598 waitForIdle(); 17599 17600 // Only one broadcast after idle time. 17601 verify(mContext, times(1)).sendBroadcastMultiplePermissions( 17602 isIntentWithAction(ACTION_EFFECTS_SUPPRESSOR_CHANGED), any(), any(), any()); 17603 } 17604 17605 @Test 17606 @EnableFlags(android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION) 17607 public void testApplyAdjustment_keyType_validType() throws Exception { 17608 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 17609 mService.addNotification(r); 17610 NotificationManagerService.WorkerHandler handler = mock( 17611 NotificationManagerService.WorkerHandler.class); 17612 mService.setHandler(handler); 17613 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 17614 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 17615 17616 Bundle signals = new Bundle(); 17617 signals.putInt(KEY_TYPE, TYPE_NEWS); 17618 Adjustment adjustment = new Adjustment( 17619 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 17620 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 17621 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17622 17623 waitForIdle(); 17624 17625 r.applyAdjustments(); 17626 17627 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 17628 17629 signals.putInt(KEY_TYPE, TYPE_PROMOTION); 17630 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17631 waitForIdle(); 17632 r.applyAdjustments(); 17633 assertThat(r.getChannel().getId()).isEqualTo(PROMOTIONS_ID); 17634 17635 signals.putInt(KEY_TYPE, TYPE_SOCIAL_MEDIA); 17636 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17637 waitForIdle(); 17638 r.applyAdjustments(); 17639 assertThat(r.getChannel().getId()).isEqualTo(SOCIAL_MEDIA_ID); 17640 17641 signals.putInt(KEY_TYPE, TYPE_CONTENT_RECOMMENDATION); 17642 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17643 waitForIdle(); 17644 r.applyAdjustments(); 17645 assertThat(r.getChannel().getId()).isEqualTo(RECS_ID); 17646 } 17647 17648 @Test 17649 @EnableFlags({android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION, 17650 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 17651 public void testApplyAdjustment_keyTypeForDisallowedPackage_DoesNotApply() throws Exception { 17652 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 17653 mService.addNotification(r); 17654 NotificationManagerService.WorkerHandler handler = mock( 17655 NotificationManagerService.WorkerHandler.class); 17656 mService.setHandler(handler); 17657 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 17658 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 17659 17660 Bundle signals = new Bundle(); 17661 signals.putInt(KEY_TYPE, TYPE_NEWS); 17662 Adjustment adjustment = new Adjustment( 17663 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 17664 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 17665 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17666 17667 waitForIdle(); 17668 17669 r.applyAdjustments(); 17670 17671 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 17672 17673 // When we block adjustments for this package 17674 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(false); 17675 17676 signals.putInt(KEY_TYPE, TYPE_PROMOTION); 17677 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 17678 waitForIdle(); 17679 r.applyAdjustments(); 17680 // Then the adjustment is not applied. 17681 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 17682 } 17683 17684 @Test 17685 @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING, 17686 android.service.notification.Flags.FLAG_NOTIFICATION_CLASSIFICATION, 17687 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 17688 public void testApplyAdjustment_promotedOngoingNotification_doesNotApply() throws Exception { 17689 // promoted ongoing notification which should not have the adjustment applied 17690 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17691 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17692 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17693 .setColor(Color.WHITE) 17694 .setColorized(true) 17695 .setOngoing(true) 17696 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post 17697 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17698 .build(); 17699 17700 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17701 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17702 final NotificationRecord r = new NotificationRecord(mContext, sbn, 17703 mTestNotificationChannel); 17704 17705 // regular notification record for contrast 17706 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel); 17707 17708 mService.addNotification(r); 17709 mService.addNotification(r2); 17710 NotificationManagerService.WorkerHandler handler = mock( 17711 NotificationManagerService.WorkerHandler.class); 17712 mService.setHandler(handler); 17713 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 17714 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 17715 17716 Bundle signals = new Bundle(); 17717 signals.putInt(KEY_TYPE, TYPE_NEWS); 17718 Bundle signals2 = new Bundle(signals); // copy for the second adjustment 17719 Adjustment adjustment = new Adjustment( 17720 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 17721 Adjustment a2 = new Adjustment(r2.getSbn().getPackageName(), r2.getKey(), signals2, "", 17722 r2.getUser().getIdentifier()); 17723 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 17724 mBinderService.applyAdjustmentsFromAssistant(null, List.of(adjustment, a2)); 17725 17726 waitForIdle(); 17727 17728 r.applyAdjustments(); 17729 r2.applyAdjustments(); 17730 17731 // promoted ongoing notification does not get bundled; regular one does 17732 assertThat(r.getChannel().getId()).isEqualTo(mTestNotificationChannel.getId()); 17733 assertThat(r2.getChannel().getId()).isEqualTo(NEWS_ID); 17734 } 17735 17736 @Test 17737 @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING}) 17738 public void testSetCanBePromoted_granted_noui() throws Exception { 17739 testSetCanBePromoted_granted(); 17740 } 17741 17742 @Test 17743 @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING, 17744 android.app.Flags.FLAG_UI_RICH_ONGOING }) 17745 public void testSetCanBePromoted_granted_ui() throws Exception { 17746 testSetCanBePromoted_granted(); 17747 } 17748 17749 private void testSetCanBePromoted_granted() throws Exception { 17750 // qualifying posted notification 17751 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17752 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17753 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17754 .setColor(Color.WHITE) 17755 .setColorized(true) 17756 .setOngoing(true) 17757 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17758 .build(); 17759 17760 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17761 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17762 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17763 17764 // qualifying enqueued notification 17765 Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17766 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17767 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17768 .setColor(Color.WHITE) 17769 .setColorized(true) 17770 .setOngoing(true) 17771 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17772 .build(); 17773 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0, 17774 n1, UserHandle.getUserHandleForUid(mUid), null, 0); 17775 NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel); 17776 17777 // another package but otherwise would qualify 17778 Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17779 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17780 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17781 .setColor(Color.WHITE) 17782 .setColorized(true) 17783 .setOngoing(true) 17784 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17785 .build(); 17786 StatusBarNotification sbn2 = new StatusBarNotification(PKG_O, PKG_O, 7, null, UID_O, 0, 17787 n2, UserHandle.getUserHandleForUid(UID_O), null, 0); 17788 NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel); 17789 17790 // not-qualifying posted notification 17791 Notification n3 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17792 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17793 .build(); 17794 17795 StatusBarNotification sbn3 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17796 n3, UserHandle.getUserHandleForUid(mUid), null, 0); 17797 NotificationRecord r3 = new NotificationRecord(mContext, sbn3, mTestNotificationChannel); 17798 17799 mService.addNotification(r3); 17800 mService.addNotification(r2); 17801 mService.addNotification(r); 17802 mService.addEnqueuedNotification(r1); 17803 17804 // GIVEN - make sure the promoted value does not depend on the default value. 17805 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17806 waitForIdle(); 17807 clearInvocations(mListeners); 17808 17809 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17810 17811 waitForIdle(); 17812 17813 ArgumentCaptor<NotificationRecord> captor = 17814 ArgumentCaptor.forClass(NotificationRecord.class); 17815 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17816 captor.capture(), any(), anyBoolean()); 17817 17818 // the posted one 17819 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17820 FLAG_PROMOTED_ONGOING)).isTrue(); 17821 // the enqueued one 17822 assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isTrue(); 17823 // the other app 17824 assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17825 // same app, not qualifying 17826 assertThat(mService.hasFlag(r3.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17827 } 17828 17829 @Test 17830 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17831 public void testSetCanBePromoted_granted_onlyNotifiesOnce_noui() throws Exception { 17832 testSetCanBePromoted_granted_onlyNotifiesOnce(); 17833 } 17834 17835 @Test 17836 @EnableFlags({android.app.Flags.FLAG_API_RICH_ONGOING, 17837 android.app.Flags.FLAG_UI_RICH_ONGOING}) 17838 public void testSetCanBePromoted_granted_onlyNotifiesOnce_ui() throws Exception { 17839 testSetCanBePromoted_granted_onlyNotifiesOnce(); 17840 } 17841 17842 private void testSetCanBePromoted_granted_onlyNotifiesOnce() throws Exception { 17843 // qualifying posted notification 17844 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17845 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17846 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17847 .setColor(Color.WHITE) 17848 .setColorized(true) 17849 .setOngoing(true) 17850 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17851 .build(); 17852 17853 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17854 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17855 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17856 17857 mService.addNotification(r); 17858 // GIVEN - make sure the promoted value does not depend on the default value. 17859 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17860 waitForIdle(); 17861 clearInvocations(mListeners); 17862 17863 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17864 waitForIdle(); 17865 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17866 waitForIdle(); 17867 17868 ArgumentCaptor<NotificationRecord> captor = 17869 ArgumentCaptor.forClass(NotificationRecord.class); 17870 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17871 captor.capture(), any(), anyBoolean()); 17872 } 17873 17874 @Test 17875 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17876 public void testSetCanBePromoted_revoked() throws Exception { 17877 // start from true state 17878 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17879 17880 // qualifying posted notification 17881 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17882 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17883 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17884 .setColor(Color.WHITE) 17885 .setColorized(true) 17886 .setOngoing(true) 17887 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post 17888 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17889 .build(); 17890 17891 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17892 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17893 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17894 17895 // qualifying enqueued notification 17896 Notification n1 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17897 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17898 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17899 .setColor(Color.WHITE) 17900 .setColorized(true) 17901 .setOngoing(true) 17902 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post 17903 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17904 .build(); 17905 StatusBarNotification sbn1 = new StatusBarNotification(mPkg, mPkg, 7, null, mUid, 0, 17906 n1, UserHandle.getUserHandleForUid(mUid), null, 0); 17907 NotificationRecord r1 = new NotificationRecord(mContext, sbn1, mTestNotificationChannel); 17908 17909 // doesn't qualify, same package 17910 Notification n2 = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17911 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17912 .build(); 17913 StatusBarNotification sbn2 = new StatusBarNotification(mPkg, mPkg, 8, null, mUid, 0, 17914 n2, UserHandle.getUserHandleForUid(UID_O), null, 0); 17915 NotificationRecord r2 = new NotificationRecord(mContext, sbn2, mTestNotificationChannel); 17916 17917 mService.addNotification(r2); 17918 mService.addNotification(r); 17919 mService.addEnqueuedNotification(r1); 17920 17921 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17922 17923 waitForIdle(); 17924 17925 ArgumentCaptor<NotificationRecord> captor = 17926 ArgumentCaptor.forClass(NotificationRecord.class); 17927 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17928 captor.capture(), any(), anyBoolean()); 17929 17930 // the posted one 17931 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17932 FLAG_PROMOTED_ONGOING)).isFalse(); 17933 // the enqueued one 17934 assertThat(mService.hasFlag(r1.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17935 // the not qualifying one 17936 assertThat(mService.hasFlag(r2.getNotification().flags, FLAG_PROMOTED_ONGOING)).isFalse(); 17937 } 17938 17939 @Test 17940 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17941 public void testSetCanBePromoted_revoked_onlyNotifiesOnce() throws Exception { 17942 // start from true state 17943 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17944 17945 // qualifying posted notification 17946 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17947 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17948 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17949 .setColor(Color.WHITE) 17950 .setColorized(true) 17951 .setOngoing(true) 17952 .setFlag(FLAG_PROMOTED_ONGOING, true) // add manually since we're skipping post 17953 .setFlag(FLAG_CAN_COLORIZE, true) // add manually since we're skipping post 17954 .build(); 17955 17956 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17957 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17958 NotificationRecord r = new NotificationRecord(mContext, sbn, mTestNotificationChannel); 17959 17960 mService.addNotification(r); 17961 17962 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17963 waitForIdle(); 17964 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 17965 waitForIdle(); 17966 17967 ArgumentCaptor<NotificationRecord> captor = 17968 ArgumentCaptor.forClass(NotificationRecord.class); 17969 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17970 captor.capture(), any(), anyBoolean()); 17971 } 17972 17973 @Test 17974 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 17975 public void testPostPromotableNotification() throws Exception { 17976 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 17977 assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isTrue(); 17978 17979 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 17980 .setSmallIcon(android.R.drawable.sym_def_app_icon) 17981 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 17982 .setColor(Color.WHITE) 17983 .setColorized(true) 17984 .setOngoing(true) 17985 .build(); 17986 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 17987 n, UserHandle.getUserHandleForUid(mUid), null, 0); 17988 17989 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 17990 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 17991 waitForIdle(); 17992 17993 ArgumentCaptor<NotificationRecord> captor = 17994 ArgumentCaptor.forClass(NotificationRecord.class); 17995 verify(mListeners, times(1)).prepareNotifyPostedLocked( 17996 captor.capture(), any(), anyBoolean()); 17997 17998 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 17999 FLAG_PROMOTED_ONGOING)).isTrue(); 18000 } 18001 18002 @Test 18003 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 18004 public void testPostPromotableNotification_noPermission() throws Exception { 18005 mBinderService.setCanBePromoted(mPkg, mUid, false, true); 18006 assertThat(mBinderService.appCanBePromoted(mPkg, mUid)).isFalse(); 18007 18008 Notification n = new Notification.Builder(mContext, mTestNotificationChannel.getId()) 18009 .setSmallIcon(android.R.drawable.sym_def_app_icon) 18010 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 18011 .setColor(Color.WHITE) 18012 .setColorized(true) 18013 .setOngoing(true) 18014 .build(); 18015 18016 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 18017 n, UserHandle.getUserHandleForUid(mUid), null, 0); 18018 18019 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 18020 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 18021 waitForIdle(); 18022 18023 ArgumentCaptor<NotificationRecord> captor = 18024 ArgumentCaptor.forClass(NotificationRecord.class); 18025 verify(mListeners, times(1)).prepareNotifyPostedLocked( 18026 captor.capture(), any(), anyBoolean()); 18027 18028 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 18029 FLAG_PROMOTED_ONGOING)).isFalse(); 18030 } 18031 18032 @Test 18033 @EnableFlags(android.app.Flags.FLAG_API_RICH_ONGOING) 18034 public void testPostPromotableNotification_unimportantNotification() throws Exception { 18035 mBinderService.setCanBePromoted(mPkg, mUid, true, true); 18036 Notification n = new Notification.Builder(mContext, mMinChannel.getId()) 18037 .setSmallIcon(android.R.drawable.sym_def_app_icon) 18038 .setStyle(new Notification.BigTextStyle().setBigContentTitle("BIG")) 18039 .setColor(Color.WHITE) 18040 .setColorized(true) 18041 .setOngoing(true) 18042 .build(); 18043 18044 StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, 9, null, mUid, 0, 18045 n, UserHandle.getUserHandleForUid(mUid), null, 0); 18046 18047 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, sbn.getTag(), 18048 sbn.getId(), sbn.getNotification(), sbn.getUserId()); 18049 waitForIdle(); 18050 18051 ArgumentCaptor<NotificationRecord> captor = 18052 ArgumentCaptor.forClass(NotificationRecord.class); 18053 verify(mListeners, times(1)).prepareNotifyPostedLocked( 18054 captor.capture(), any(), anyBoolean()); 18055 18056 assertThat(mService.hasFlag(captor.getValue().getNotification().flags, 18057 FLAG_PROMOTED_ONGOING)).isFalse(); 18058 } 18059 18060 @Test 18061 @EnableFlags(FLAG_NOTIFICATION_CLASSIFICATION) 18062 public void testAppCannotUseReservedBundleChannels() throws Exception { 18063 mService.mPreferencesHelper.createReservedChannel(mPkg, mUid, TYPE_NEWS); 18064 NotificationChannel news = mBinderService.getNotificationChannel( 18065 mPkg, mContext.getUserId(), mPkg, NEWS_ID); 18066 assertThat(news).isNotNull(); 18067 18068 NotificationRecord nr = generateNotificationRecord(news); 18069 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, nr.getSbn().getTag(), 18070 nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); 18071 waitForIdle(); 18072 18073 assertThat(mService.mNotificationList).isEmpty(); 18074 } 18075 18076 @Test 18077 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18078 FLAG_NOTIFICATION_FORCE_GROUPING, 18079 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18080 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18081 public void testUnclassifyNotification_ungrouped_restoresOriginalChannel() throws Exception { 18082 NotificationManagerService.WorkerHandler handler = mock( 18083 NotificationManagerService.WorkerHandler.class); 18084 mService.setHandler(handler); 18085 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18086 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18087 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18088 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18089 18090 // Post a single notification 18091 final boolean hasOriginalSummary = false; 18092 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 18093 final String keyToUnbundle = r.getKey(); 18094 mService.addNotification(r); 18095 18096 // Classify notification into the NEWS bundle 18097 Bundle signals = new Bundle(); 18098 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 18099 Adjustment adjustment = new Adjustment( 18100 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 18101 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18102 waitForIdle(); 18103 r.applyAdjustments(); 18104 // Check that the NotificationRecord channel is updated 18105 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 18106 // Check that the Notification mChannelId is not updated 18107 assertThat(r.getNotification().getChannelId()).isEqualTo(TEST_CHANNEL_ID); 18108 // Check that the bundleType is updated 18109 assertThat(r.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); 18110 18111 // Unclassify the notification 18112 mService.unclassifyNotification(keyToUnbundle); 18113 18114 // Check that the original channel was restored 18115 assertThat(r.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18116 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r), eq(hasOriginalSummary)); 18117 } 18118 18119 @Test 18120 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18121 FLAG_NOTIFICATION_FORCE_GROUPING, 18122 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18123 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18124 public void testUnclassifyNotification_grouped_restoresOriginalChannel() throws Exception { 18125 NotificationManagerService.WorkerHandler handler = mock( 18126 NotificationManagerService.WorkerHandler.class); 18127 mService.setHandler(handler); 18128 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18129 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18130 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18131 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18132 18133 // Post grouped notifications 18134 final String originalGroupName = "originalGroup"; 18135 final int summaryId = 0; 18136 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 18137 summaryId + 1, originalGroupName, false); 18138 mService.addNotification(r1); 18139 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 18140 summaryId + 2, originalGroupName, false); 18141 mService.addNotification(r2); 18142 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 18143 summaryId, originalGroupName, true); 18144 mService.addNotification(summary); 18145 final String originalGroupKey = summary.getGroupKey(); 18146 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 18147 18148 // Classify a child notification into the NEWS bundle 18149 final String keyToUnbundle = r1.getKey(); 18150 final boolean hasOriginalSummary = true; 18151 Bundle signals = new Bundle(); 18152 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 18153 Adjustment adjustment = new Adjustment(r1.getSbn().getPackageName(), r1.getKey(), signals, 18154 "", r1.getUser().getIdentifier()); 18155 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18156 waitForIdle(); 18157 r1.applyAdjustments(); 18158 assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID); 18159 assertThat(r1.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); 18160 18161 // Unclassify the notification 18162 mService.unclassifyNotification(keyToUnbundle); 18163 18164 // Check that the original channel was restored 18165 assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18166 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r1), eq(hasOriginalSummary)); 18167 } 18168 18169 @Test 18170 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18171 FLAG_NOTIFICATION_FORCE_GROUPING, 18172 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18173 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18174 public void testUnclassifyNotification_groupedSummaryCanceled_restoresOriginalChannel() 18175 throws Exception { 18176 NotificationManagerService.WorkerHandler handler = mock( 18177 NotificationManagerService.WorkerHandler.class); 18178 mService.setHandler(handler); 18179 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18180 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18181 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18182 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18183 18184 // Post grouped notifications 18185 final String originalGroupName = "originalGroup"; 18186 final int summaryId = 0; 18187 final NotificationRecord r1 = generateNotificationRecord(mTestNotificationChannel, 18188 summaryId + 1, originalGroupName, false); 18189 mService.addNotification(r1); 18190 final NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 18191 summaryId + 2, originalGroupName, false); 18192 mService.addNotification(r2); 18193 final NotificationRecord summary = generateNotificationRecord(mTestNotificationChannel, 18194 summaryId, originalGroupName, true); 18195 mService.addNotification(summary); 18196 final String originalGroupKey = summary.getGroupKey(); 18197 assertThat(mService.mSummaryByGroupKey).containsEntry(originalGroupKey, summary); 18198 18199 // Classify a child notification into the NEWS bundle 18200 final String keyToUnbundle = r1.getKey(); 18201 Bundle signals = new Bundle(); 18202 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 18203 Adjustment adjustment = new Adjustment(r1.getSbn().getPackageName(), r1.getKey(), signals, 18204 "", r1.getUser().getIdentifier()); 18205 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18206 waitForIdle(); 18207 r1.applyAdjustments(); 18208 assertThat(r1.getChannel().getId()).isEqualTo(NEWS_ID); 18209 assertThat(r1.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); 18210 18211 // Cancel original summary 18212 final boolean hasOriginalSummary = false; 18213 mService.mSummaryByGroupKey.remove(summary.getGroupKey()); 18214 18215 // Unclassify the notification 18216 mService.unclassifyNotification(keyToUnbundle); 18217 18218 // Check that the original channel was restored 18219 assertThat(r1.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18220 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r1), eq(hasOriginalSummary)); 18221 } 18222 18223 @Test 18224 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18225 FLAG_NOTIFICATION_FORCE_GROUPING, 18226 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18227 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18228 public void testReclassifyNotification_restoresBundleChannel() throws Exception { 18229 NotificationManagerService.WorkerHandler handler = mock( 18230 NotificationManagerService.WorkerHandler.class); 18231 mService.setHandler(handler); 18232 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18233 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18234 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18235 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18236 18237 // Post a single notification 18238 final boolean hasOriginalSummary = false; 18239 final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel); 18240 final String keyToUnbundle = r.getKey(); 18241 mService.addNotification(r); 18242 18243 // Classify notification into the NEWS bundle 18244 Bundle signals = new Bundle(); 18245 signals.putInt(Adjustment.KEY_TYPE, Adjustment.TYPE_NEWS); 18246 Adjustment adjustment = new Adjustment( 18247 r.getSbn().getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier()); 18248 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18249 waitForIdle(); 18250 r.applyAdjustments(); 18251 // Check that the NotificationRecord channel is updated 18252 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 18253 assertThat(r.getBundleType()).isEqualTo(Adjustment.TYPE_NEWS); 18254 18255 // Unbundle the notification 18256 mService.unclassifyNotification(keyToUnbundle); 18257 18258 // Check that the original channel was restored 18259 assertThat(r.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18260 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(r), eq(hasOriginalSummary)); 18261 18262 Mockito.reset(mRankingHandler); 18263 Mockito.reset(mGroupHelper); 18264 18265 // Rebundle the notification 18266 mService.reclassifyNotification(keyToUnbundle); 18267 18268 // Actually apply the adjustments 18269 doAnswer(invocationOnMock -> { 18270 ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); 18271 ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); 18272 return null; 18273 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 18274 mService.handleRankingSort(); 18275 verify(handler, times(1)).scheduleSendRankingUpdate(); 18276 18277 // Check that the bundle channel was restored 18278 verify(mRankingHandler, times(1)).requestSort(); 18279 assertThat(r.getChannel().getId()).isEqualTo(NEWS_ID); 18280 } 18281 18282 @Test 18283 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18284 FLAG_NOTIFICATION_FORCE_GROUPING, 18285 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18286 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18287 public void testDisallowTypeAdj_unclassifiesAllNotifications() throws Exception { 18288 NotificationManagerService.WorkerHandler handler = mock( 18289 NotificationManagerService.WorkerHandler.class); 18290 mService.setHandler(handler); 18291 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18292 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18293 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18294 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18295 18296 // Post some notifications and classify in different bundles 18297 final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); 18298 for (int i = 0; i < numNotifications; i++) { 18299 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); 18300 mService.addNotification(r); 18301 Bundle signals = new Bundle(); 18302 final int adjustmentType = i + 1; 18303 signals.putInt(Adjustment.KEY_TYPE, adjustmentType); 18304 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18305 "", r.getUser().getIdentifier()); 18306 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18307 waitForIdle(); 18308 r.applyAdjustments(); 18309 r.setBundleType(adjustmentType); 18310 // Check that the NotificationRecord channel is updated 18311 assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18312 assertThat(r.getBundleType()).isEqualTo(adjustmentType); 18313 } 18314 18315 // Disallow KEY_TYPE adjustment 18316 mBinderService.disallowAssistantAdjustment(Adjustment.KEY_TYPE); 18317 waitForIdle(); 18318 18319 //Check that all notifications have been unbundled 18320 for (NotificationRecord record : mService.mNotificationList) { 18321 // Check that the original channel was restored 18322 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18323 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); 18324 } 18325 18326 // Re-allow KEY_TYPE adjustment 18327 Mockito.reset(mRankingHandler); 18328 Mockito.reset(mGroupHelper); 18329 mBinderService.allowAssistantAdjustment(Adjustment.KEY_TYPE); 18330 waitForIdle(); 18331 18332 // Actually apply the adjustments 18333 doAnswer(invocationOnMock -> { 18334 ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); 18335 ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); 18336 return null; 18337 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 18338 mService.handleRankingSort(); 18339 18340 // Check that the bundle channel was restored for all notifications 18341 verify(handler, times(numNotifications)).scheduleSendRankingUpdate(); 18342 verify(mRankingHandler, times(numNotifications)).requestSort(); 18343 for (NotificationRecord record : mService.mNotificationList) { 18344 assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18345 } 18346 } 18347 18348 @Test 18349 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18350 FLAG_NOTIFICATION_FORCE_GROUPING, 18351 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18352 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18353 public void testDisableBundleAdjustmentByType_unclassifiesNotifications() throws Exception { 18354 NotificationManagerService.WorkerHandler handler = mock( 18355 NotificationManagerService.WorkerHandler.class); 18356 mService.setHandler(handler); 18357 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18358 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18359 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18360 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18361 18362 // Post some notifications and classify in different bundles 18363 final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); 18364 final int numNewsNotifications = 1; 18365 List<String> postedNotificationKeys = new ArrayList(); 18366 for (int i = 0; i < numNotifications; i++) { 18367 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); 18368 mService.addNotification(r); 18369 postedNotificationKeys.add(r.getKey()); 18370 Bundle signals = new Bundle(); 18371 final int adjustmentType = i + 1; 18372 signals.putInt(Adjustment.KEY_TYPE, adjustmentType); 18373 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18374 "", r.getUser().getIdentifier()); 18375 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18376 waitForIdle(); 18377 r.applyAdjustments(); 18378 r.setBundleType(adjustmentType); 18379 // Check that the NotificationRecord channel is updated 18380 assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18381 assertThat(r.getBundleType()).isEqualTo(adjustmentType); 18382 } 18383 18384 // Disable TYPE_NEWS bundle 18385 mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false); 18386 waitForIdle(); 18387 18388 //Check that all notifications classified as TYPE_NEWS have been unbundled 18389 for (String key : postedNotificationKeys) { 18390 NotificationRecord record= mService.mNotificationsByKey.get(key); 18391 // Check that the original channel was restored 18392 // for notifications classified as TYPE_NEWS 18393 if (record.getBundleType() == TYPE_NEWS) { 18394 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18395 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); 18396 } 18397 } 18398 18399 // Re-enable TYPE_NEWS bundle 18400 Mockito.reset(mRankingHandler); 18401 Mockito.reset(mGroupHelper); 18402 mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true); 18403 waitForIdle(); 18404 18405 // Actually apply the adjustments 18406 doAnswer(invocationOnMock -> { 18407 ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); 18408 ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); 18409 return null; 18410 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 18411 mService.handleRankingSort(); 18412 18413 // Check that the bundle channel was restored 18414 verify(mRankingHandler, times(numNewsNotifications)).requestSort(); 18415 for (String key : postedNotificationKeys) { 18416 NotificationRecord record= mService.mNotificationsByKey.get(key); 18417 assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18418 } 18419 } 18420 18421 @Test 18422 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18423 FLAG_NOTIFICATION_FORCE_GROUPING, 18424 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18425 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18426 public void testDisableBundleAdjustmentByPkg_unclassifiesNotifications() throws Exception { 18427 NotificationManagerService.WorkerHandler handler = mock( 18428 NotificationManagerService.WorkerHandler.class); 18429 mService.setHandler(handler); 18430 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18431 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18432 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18433 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18434 18435 // Post some notifications and classify in different bundles 18436 final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); 18437 for (int i = 0; i < numNotifications; i++) { 18438 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); 18439 mService.addNotification(r); 18440 Bundle signals = new Bundle(); 18441 final int adjustmentType = i + 1; 18442 signals.putInt(Adjustment.KEY_TYPE, adjustmentType); 18443 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18444 "", r.getUser().getIdentifier()); 18445 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18446 waitForIdle(); 18447 r.applyAdjustments(); 18448 r.setBundleType(adjustmentType); 18449 // Check that the NotificationRecord channel is updated 18450 assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18451 assertThat(r.getBundleType()).isEqualTo(adjustmentType); 18452 } 18453 18454 // Disable TYPE_NEWS bundle 18455 mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, false); 18456 waitForIdle(); 18457 18458 //Check that all notifications were unbundled 18459 for (NotificationRecord record : mService.mNotificationList) { 18460 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18461 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); 18462 } 18463 18464 // Re-enable bundles for package 18465 Mockito.reset(mRankingHandler); 18466 Mockito.reset(mGroupHelper); 18467 mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, true); 18468 waitForIdle(); 18469 18470 // Actually apply the adjustments 18471 doAnswer(invocationOnMock -> { 18472 ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); 18473 ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); 18474 return null; 18475 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 18476 mService.handleRankingSort(); 18477 18478 // Check that the bundle channel was restored 18479 verify(mRankingHandler, times(numNotifications)).requestSort(); 18480 for (NotificationRecord record : mService.mNotificationList) { 18481 assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18482 } 18483 } 18484 18485 @Test 18486 @EnableFlags({FLAG_NM_SUMMARIZATION}) 18487 public void testDisableBundleAdjustmentByPkg_unsummarizesNotifications() throws Exception { 18488 NotificationManagerService.WorkerHandler handler = mock( 18489 NotificationManagerService.WorkerHandler.class); 18490 mService.setHandler(handler); 18491 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18492 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18493 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18494 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18495 18496 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId); 18497 mService.addNotification(r); 18498 Bundle signals = new Bundle(); 18499 signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello"); 18500 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18501 "", r.getUser().getIdentifier()); 18502 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18503 waitForIdle(); 18504 r.applyAdjustments(); 18505 Mockito.clearInvocations(mRankingHandler); 18506 18507 // Disable summarization for package 18508 mBinderService.setAdjustmentSupportedForPackage(KEY_SUMMARIZATION, mPkg, false); 18509 verify(mRankingHandler).requestSort(); 18510 mService.handleRankingSort(); 18511 18512 assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull(); 18513 } 18514 18515 @Test 18516 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18517 FLAG_NOTIFICATION_FORCE_GROUPING, 18518 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18519 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18520 public void testDisableBundleAdjustmentByPkg_unclassifiesEnqueuedNotifications() 18521 throws Exception { 18522 NotificationManagerService.WorkerHandler handler = mock( 18523 NotificationManagerService.WorkerHandler.class); 18524 mService.setHandler(handler); 18525 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18526 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18527 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18528 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18529 18530 // Enqueue some notifications and classify in different bundles 18531 final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); 18532 for (int i = 0; i < numNotifications; i++) { 18533 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); 18534 mService.addEnqueuedNotification(r); 18535 Bundle signals = new Bundle(); 18536 final int adjustmentType = i + 1; 18537 signals.putInt(Adjustment.KEY_TYPE, adjustmentType); 18538 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18539 "", r.getUser().getIdentifier()); 18540 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 18541 waitForIdle(); 18542 r.applyAdjustments(); 18543 r.setBundleType(adjustmentType); 18544 // Check that the NotificationRecord channel is updated 18545 assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18546 assertThat(r.getBundleType()).isEqualTo(adjustmentType); 18547 } 18548 18549 // Disable type adjustment for the package 18550 mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, false); 18551 waitForIdle(); 18552 18553 //Check that all notifications were unbundled 18554 for (NotificationRecord record : mService.mEnqueuedNotifications) { 18555 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18556 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); 18557 } 18558 18559 // Re-enable bundles for package 18560 Mockito.reset(mRankingHandler); 18561 Mockito.reset(mGroupHelper); 18562 mBinderService.setAdjustmentSupportedForPackage(KEY_TYPE, mPkg, true); 18563 waitForIdle(); 18564 18565 // Actually apply the adjustments 18566 doAnswer(invocationOnMock -> { 18567 ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); 18568 ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); 18569 return null; 18570 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 18571 mService.handleRankingSort(); 18572 18573 // Check that the bundle channel was restored 18574 verify(mRankingHandler, times(numNotifications)).requestSort(); 18575 for (NotificationRecord record : mService.mEnqueuedNotifications) { 18576 record.applyAdjustments(); 18577 assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18578 } 18579 } 18580 18581 @Test 18582 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18583 FLAG_NOTIFICATION_FORCE_GROUPING, 18584 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18585 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18586 public void testDisableBundleAdjustmentByType_unclassifiesEnqueuedNotifications() 18587 throws Exception { 18588 NotificationManagerService.WorkerHandler handler = mock( 18589 NotificationManagerService.WorkerHandler.class); 18590 mService.setHandler(handler); 18591 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18592 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18593 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18594 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18595 18596 // Enqueue some notifications and classify in different bundles 18597 final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); 18598 final int numNewsNotifications = 1; 18599 for (int i = 0; i < numNotifications; i++) { 18600 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); 18601 mService.addEnqueuedNotification(r); 18602 Bundle signals = new Bundle(); 18603 final int adjustmentType = i + 1; 18604 signals.putInt(Adjustment.KEY_TYPE, adjustmentType); 18605 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18606 "", r.getUser().getIdentifier()); 18607 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 18608 waitForIdle(); 18609 r.applyAdjustments(); 18610 r.setBundleType(adjustmentType); 18611 // Check that the NotificationRecord channel is updated 18612 assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18613 assertThat(r.getBundleType()).isEqualTo(adjustmentType); 18614 } 18615 18616 // Disable TYPE_NEWS bundle 18617 mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, false); 18618 waitForIdle(); 18619 18620 //Check that all notifications were unbundled 18621 for (NotificationRecord record : mService.mEnqueuedNotifications) { 18622 // Check that the original channel was restored 18623 // for notifications classified as TYPE_NEWS 18624 if (record.getBundleType() == TYPE_NEWS) { 18625 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18626 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); 18627 } 18628 } 18629 18630 // Re-enable bundles for package 18631 Mockito.reset(mRankingHandler); 18632 Mockito.reset(mGroupHelper); 18633 mBinderService.setAssistantAdjustmentKeyTypeState(TYPE_NEWS, true); 18634 waitForIdle(); 18635 18636 // Actually apply the adjustments 18637 doAnswer(invocationOnMock -> { 18638 ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); 18639 ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); 18640 return null; 18641 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 18642 mService.handleRankingSort(); 18643 18644 // Check that the bundle channel was restored 18645 verify(mRankingHandler, times(numNewsNotifications)).requestSort(); 18646 for (NotificationRecord record : mService.mEnqueuedNotifications) { 18647 record.applyAdjustments(); 18648 assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18649 } 18650 } 18651 18652 @Test 18653 @EnableFlags({FLAG_NOTIFICATION_CLASSIFICATION, 18654 FLAG_NOTIFICATION_FORCE_GROUPING, 18655 FLAG_NOTIFICATION_REGROUP_ON_CLASSIFICATION, 18656 android.app.Flags.FLAG_NOTIFICATION_CLASSIFICATION_UI}) 18657 public void testDisallowTypeAdj_unclassifiesAllEnqueuedNotifications() throws Exception { 18658 NotificationManagerService.WorkerHandler handler = mock( 18659 NotificationManagerService.WorkerHandler.class); 18660 mService.setHandler(handler); 18661 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18662 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18663 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18664 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18665 18666 // Enqueue some notifications and classify in different bundles 18667 final int numNotifications = NotificationChannel.SYSTEM_RESERVED_IDS.size(); 18668 for (int i = 0; i < numNotifications; i++) { 18669 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, i, mUserId); 18670 mService.addEnqueuedNotification(r); 18671 Bundle signals = new Bundle(); 18672 final int adjustmentType = i + 1; 18673 signals.putInt(Adjustment.KEY_TYPE, adjustmentType); 18674 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18675 "", r.getUser().getIdentifier()); 18676 mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment); 18677 waitForIdle(); 18678 r.applyAdjustments(); 18679 r.setBundleType(adjustmentType); 18680 // Check that the NotificationRecord channel is updated 18681 assertThat(r.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18682 assertThat(r.getBundleType()).isEqualTo(adjustmentType); 18683 } 18684 18685 // Disable KEY_TYPE adjustment 18686 mBinderService.disallowAssistantAdjustment(Adjustment.KEY_TYPE); 18687 waitForIdle(); 18688 18689 //Check that all notifications were unbundled 18690 for (NotificationRecord record : mService.mEnqueuedNotifications) { 18691 assertThat(record.getChannel().getId()).isEqualTo(TEST_CHANNEL_ID); 18692 verify(mGroupHelper, times(1)).onNotificationUnbundled(eq(record), anyBoolean()); 18693 } 18694 18695 // Re-enable bundles 18696 Mockito.reset(mRankingHandler); 18697 Mockito.reset(mGroupHelper); 18698 mBinderService.allowAssistantAdjustment(Adjustment.KEY_TYPE); 18699 waitForIdle(); 18700 18701 // Actually apply the adjustments 18702 doAnswer(invocationOnMock -> { 18703 ((NotificationRecord) invocationOnMock.getArguments()[0]).applyAdjustments(); 18704 ((NotificationRecord) invocationOnMock.getArguments()[0]).calculateImportance(); 18705 return null; 18706 }).when(mRankingHelper).extractSignals(any(NotificationRecord.class)); 18707 mService.handleRankingSort(); 18708 18709 // Check that the bundle channel was restored 18710 verify(mRankingHandler, times(numNotifications)).requestSort(); 18711 for (NotificationRecord record : mService.mEnqueuedNotifications) { 18712 record.applyAdjustments(); 18713 assertThat(record.getChannel().getId()).isIn(NotificationChannel.SYSTEM_RESERVED_IDS); 18714 } 18715 } 18716 18717 @Test 18718 @EnableFlags({FLAG_NM_SUMMARIZATION}) 18719 public void testDisableBundleAdjustment_unsummarizesNotifications() throws Exception { 18720 NotificationManagerService.WorkerHandler handler = mock( 18721 NotificationManagerService.WorkerHandler.class); 18722 mService.setHandler(handler); 18723 when(mAssistants.isSameUser(any(), anyInt())).thenReturn(true); 18724 when(mAssistants.isServiceTokenValidLocked(any())).thenReturn(true); 18725 when(mAssistants.isAdjustmentKeyTypeAllowed(anyInt())).thenReturn(true); 18726 when(mAssistants.isAdjustmentAllowedForPackage(anyString(), anyString())).thenReturn(true); 18727 18728 NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, mUserId); 18729 mService.addNotification(r); 18730 Bundle signals = new Bundle(); 18731 signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, "hello"); 18732 Adjustment adjustment = new Adjustment(r.getSbn().getPackageName(), r.getKey(), signals, 18733 "", r.getUser().getIdentifier()); 18734 mBinderService.applyAdjustmentFromAssistant(null, adjustment); 18735 waitForIdle(); 18736 r.applyAdjustments(); 18737 Mockito.clearInvocations(mRankingHandler); 18738 18739 // Disable summarization for package 18740 mBinderService.disallowAssistantAdjustment(KEY_SUMMARIZATION); 18741 verify(mRankingHandler).requestSort(); 18742 mService.handleRankingSort(); 18743 18744 assertThat(mService.mNotificationsByKey.get(r.getKey()).getSummarization()).isNull(); 18745 } 18746 18747 @Test 18748 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 18749 public void clearAll_fromUser_willSendDeleteIntentForCachedSummaries() throws Exception { 18750 NotificationRecord n = generateNotificationRecord( 18751 mTestNotificationChannel, 1, "group", true); 18752 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 18753 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId()); 18754 waitForIdle(); 18755 n = Iterables.getOnlyElement(mService.mNotificationList); 18756 18757 mService.mNotificationDelegate.onClearAll(mUid, Binder.getCallingPid(), n.getUserId()); 18758 waitForIdle(); 18759 18760 verify(mGroupHelper).onNotificationRemoved(eq(n), any(), eq(true)); 18761 } 18762 18763 @Test 18764 @EnableFlags(FLAG_NOTIFICATION_FORCE_GROUPING) 18765 public void cancel_fromApp_willNotSendDeleteIntentForCachedSummaries() throws Exception { 18766 NotificationRecord n = generateNotificationRecord( 18767 mTestNotificationChannel, 1, "group", true); 18768 mBinderService.enqueueNotificationWithTag(mPkg, mPkg, "tag", 18769 n.getSbn().getId(), n.getSbn().getNotification(), n.getSbn().getUserId()); 18770 waitForIdle(); 18771 n = Iterables.getOnlyElement(mService.mNotificationList); 18772 18773 mBinderService.cancelAllNotifications(mPkg, mUserId); 18774 waitForIdle(); 18775 18776 verify(mGroupHelper).onNotificationRemoved(eq(n), any(), eq(false)); 18777 } 18778 18779 @Test 18780 public void onDisplayRemoveSystemDecorations_cancelToasts() throws RemoteException { 18781 final String testPackage = "testPackageName"; 18782 final INotificationManager service = ((INotificationManager) mService.mService); 18783 final IBinder firstExternal = new Binder(); 18784 final IBinder secondExternal = new Binder(); 18785 final IBinder firstBuiltin = new Binder(); 18786 service.enqueueTextToast(testPackage, 18787 firstExternal, "First external", TOAST_DURATION, 18788 /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null); 18789 service.enqueueTextToast(testPackage, 18790 secondExternal, "Second external", TOAST_DURATION, 18791 /* isUiContext= */ true, /* displayId= */ 10, /* callback= */ null); 18792 service.enqueueTextToast(testPackage, 18793 firstBuiltin, "First built-in", TOAST_DURATION, /* isUiContext= */ true, 18794 /* displayId= */ DEFAULT_DISPLAY, /* callback= */ null); 18795 18796 mInternalService.onDisplayRemoveSystemDecorations(10); 18797 18798 verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstExternal), 18799 any(String.class), any(IBinder.class), anyInt(), any(), eq(10)); 18800 verify(mStatusBar).hideToast(eq(testPackage), eq(firstExternal)); 18801 // The second toast has not been shown but invokes hide() anyway as 18802 // NotificationManagerService does not remembered if it invoked show(). 18803 verify(mStatusBar, never()).showToast(anyInt(), eq(testPackage), eq(secondExternal), 18804 any(String.class), any(IBinder.class), anyInt(), any(), eq(10)); 18805 verify(mStatusBar).hideToast(eq(testPackage), eq(secondExternal)); 18806 // The toast on the default display is shown as other notifications are cancelled. 18807 verify(mStatusBar).showToast(anyInt(), eq(testPackage), eq(firstBuiltin), any(String.class), 18808 any(IBinder.class), anyInt(), any(), eq(DEFAULT_DISPLAY)); 18809 verify(mStatusBar, never()).hideToast(eq(testPackage), eq(firstBuiltin)); 18810 } 18811 } 18812