1 /* 2 * Copyright (C) 2023 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; 18 19 import static android.permission.flags.Flags.FLAG_SENSITIVE_CONTENT_METRICS_BUGFIX; 20 import static android.permission.flags.Flags.FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION; 21 22 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; 23 24 import static org.mockito.ArgumentMatchers.any; 25 import static org.mockito.ArgumentMatchers.anyInt; 26 import static org.mockito.ArgumentMatchers.anyLong; 27 import static org.mockito.ArgumentMatchers.eq; 28 import static org.mockito.Mockito.doNothing; 29 import static org.mockito.Mockito.doReturn; 30 import static org.mockito.Mockito.doThrow; 31 import static org.mockito.Mockito.never; 32 import static org.mockito.Mockito.spy; 33 import static org.mockito.Mockito.verify; 34 import static org.mockito.Mockito.when; 35 36 import android.app.role.RoleManager; 37 import android.companion.AssociationRequest; 38 import android.content.pm.PackageManagerInternal; 39 import android.media.projection.MediaProjectionInfo; 40 import android.media.projection.MediaProjectionManager; 41 import android.os.Process; 42 import android.os.RemoteException; 43 import android.platform.test.annotations.RequiresFlagsDisabled; 44 import android.platform.test.annotations.RequiresFlagsEnabled; 45 import android.platform.test.flag.junit.CheckFlagsRule; 46 import android.platform.test.flag.junit.DeviceFlagsValueProvider; 47 import android.provider.Settings; 48 import android.service.notification.NotificationListenerService.Ranking; 49 import android.service.notification.NotificationListenerService.RankingMap; 50 import android.service.notification.StatusBarNotification; 51 import android.testing.AndroidTestingRunner; 52 import android.testing.TestableContext; 53 import android.testing.TestableLooper.RunWithLooper; 54 import android.util.ArraySet; 55 56 import androidx.test.filters.SmallTest; 57 58 import com.android.server.wm.SensitiveContentPackages.PackageInfo; 59 import com.android.server.wm.WindowManagerInternal; 60 61 import org.junit.After; 62 import org.junit.Before; 63 import org.junit.Rule; 64 import org.junit.Test; 65 import org.junit.runner.RunWith; 66 import org.mockito.ArgumentCaptor; 67 import org.mockito.Captor; 68 import org.mockito.Mock; 69 import org.mockito.Mockito; 70 import org.mockito.MockitoAnnotations; 71 72 import java.util.List; 73 import java.util.Set; 74 75 @SmallTest 76 @RunWith(AndroidTestingRunner.class) 77 @RunWithLooper 78 @RequiresFlagsEnabled(FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION) 79 /** 80 * Test {@link SensitiveContentProtectionManagerService} for sensitive notification protection, 81 * the service protects sensitive content during screen share. 82 */ 83 public class SensitiveContentProtectionManagerServiceNotificationTest { 84 private static final String NOTIFICATION_KEY_1 = "com.android.server.notification.TEST_KEY_1"; 85 private static final String NOTIFICATION_KEY_2 = "com.android.server.notification.TEST_KEY_2"; 86 87 private static final String NOTIFICATION_PKG_1 = "com.android.server.notification.one"; 88 private static final String NOTIFICATION_PKG_2 = "com.android.server.notification.two"; 89 90 private static final String SCREEN_RECORDER_PACKAGE = "test.screen.recorder.package"; 91 private static final String EXEMPTED_SCREEN_RECORDER_PACKAGE = "exempt.screen.recorder.package"; 92 93 private static final int NOTIFICATION_UID_1 = 5; 94 private static final int NOTIFICATION_UID_2 = 6; 95 96 private static final ArraySet<PackageInfo> EMPTY_SET = new ArraySet<>(); 97 98 @Rule 99 public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); 100 101 @Rule 102 public final TestableContext mContext = 103 new TestableContext(getInstrumentation().getTargetContext(), null); 104 105 private SensitiveContentProtectionManagerService mSensitiveContentProtectionManagerService; 106 107 @Captor 108 ArgumentCaptor<MediaProjectionManager.Callback> mMediaProjectionCallbackCaptor; 109 @Captor 110 private ArgumentCaptor<ArraySet<PackageInfo>> mPackageInfoCaptor; 111 112 @Mock 113 private MediaProjectionManager mProjectionManager; 114 115 @Mock 116 private WindowManagerInternal mWindowManager; 117 118 @Mock 119 private PackageManagerInternal mPackageManagerInternal; 120 121 @Mock 122 private RoleManager mRoleManager; 123 124 @Mock 125 private StatusBarNotification mNotification1; 126 127 @Mock 128 private StatusBarNotification mNotification2; 129 130 @Mock 131 private RankingMap mRankingMap; 132 133 @Mock 134 private Ranking mSensitiveRanking; 135 136 @Mock 137 private Ranking mNonSensitiveRanking; 138 139 @Before setUp()140 public void setUp() { 141 MockitoAnnotations.initMocks(this); 142 143 mSensitiveContentProtectionManagerService = 144 new SensitiveContentProtectionManagerService(mContext); 145 146 mSensitiveContentProtectionManagerService.mNotificationListener = 147 spy(mSensitiveContentProtectionManagerService.mNotificationListener); 148 149 // Unexpected NLS interactions when registered cause test flakes. For purposes of this test, 150 // the test will control any NLS calls. 151 try { 152 doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener) 153 .registerAsSystemService(any(), any(), anyInt()); 154 doNothing().when(mSensitiveContentProtectionManagerService.mNotificationListener) 155 .unregisterAsSystemService(); 156 } catch (RemoteException e) { 157 // Intra-process call, should never happen. 158 } 159 160 // Setup RankingMap and two possilbe rankings 161 when(mSensitiveRanking.hasSensitiveContent()).thenReturn(true); 162 when(mNonSensitiveRanking.hasSensitiveContent()).thenReturn(false); 163 doReturn(mRankingMap) 164 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 165 .getCurrentRanking(); 166 167 setupSensitiveNotification(); 168 169 mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager, 170 mPackageManagerInternal, mRoleManager, 171 new ArraySet<>(Set.of(EXEMPTED_SCREEN_RECORDER_PACKAGE))); 172 173 // Obtain useful mMediaProjectionCallback 174 verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any()); 175 } 176 177 @After tearDown()178 public void tearDown() { 179 mSensitiveContentProtectionManagerService.onDestroy(); 180 } 181 setupSensitiveNotification()182 private ArraySet<PackageInfo> setupSensitiveNotification() { 183 // Setup Notification Values 184 when(mNotification1.getKey()).thenReturn(NOTIFICATION_KEY_1); 185 when(mNotification1.getPackageName()).thenReturn(NOTIFICATION_PKG_1); 186 when(mNotification1.getUid()).thenReturn(NOTIFICATION_UID_1); 187 188 when(mNotification2.getKey()).thenReturn(NOTIFICATION_KEY_2); 189 when(mNotification2.getPackageName()).thenReturn(NOTIFICATION_PKG_2); 190 when(mNotification2.getUid()).thenReturn(NOTIFICATION_UID_1); 191 192 StatusBarNotification[] mNotifications = 193 new StatusBarNotification[] {mNotification1, mNotification2}; 194 doReturn(mNotifications) 195 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 196 .getActiveNotifications(); 197 198 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))) 199 .thenReturn(mSensitiveRanking); 200 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_2))) 201 .thenReturn(mNonSensitiveRanking); 202 203 return new ArraySet<>( 204 Set.of(new PackageInfo(NOTIFICATION_PKG_1, NOTIFICATION_UID_1))); 205 } 206 setupMultipleSensitiveNotificationsFromSamePackageAndUid()207 private ArraySet<PackageInfo> setupMultipleSensitiveNotificationsFromSamePackageAndUid() { 208 // Setup Notification Values 209 when(mNotification1.getKey()).thenReturn(NOTIFICATION_KEY_1); 210 when(mNotification1.getPackageName()).thenReturn(NOTIFICATION_PKG_1); 211 when(mNotification1.getUid()).thenReturn(NOTIFICATION_UID_1); 212 213 when(mNotification2.getKey()).thenReturn(NOTIFICATION_KEY_2); 214 when(mNotification2.getPackageName()).thenReturn(NOTIFICATION_PKG_1); 215 when(mNotification2.getUid()).thenReturn(NOTIFICATION_UID_1); 216 217 StatusBarNotification[] mNotifications = 218 new StatusBarNotification[] {mNotification1, mNotification2}; 219 doReturn(mNotifications) 220 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 221 .getActiveNotifications(); 222 223 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))) 224 .thenReturn(mSensitiveRanking); 225 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_2))) 226 .thenReturn(mSensitiveRanking); 227 228 return new ArraySet<>( 229 Set.of(new PackageInfo(NOTIFICATION_PKG_1, NOTIFICATION_UID_1))); 230 } 231 setupMultipleSensitiveNotificationsFromDifferentPackage()232 private ArraySet<PackageInfo> setupMultipleSensitiveNotificationsFromDifferentPackage() { 233 // Setup Notification Values 234 when(mNotification1.getKey()).thenReturn(NOTIFICATION_KEY_1); 235 when(mNotification1.getPackageName()).thenReturn(NOTIFICATION_PKG_1); 236 when(mNotification1.getUid()).thenReturn(NOTIFICATION_UID_1); 237 238 when(mNotification2.getKey()).thenReturn(NOTIFICATION_KEY_2); 239 when(mNotification2.getPackageName()).thenReturn(NOTIFICATION_PKG_2); 240 when(mNotification2.getUid()).thenReturn(NOTIFICATION_UID_1); 241 242 StatusBarNotification[] mNotifications = 243 new StatusBarNotification[] {mNotification1, mNotification2}; 244 doReturn(mNotifications) 245 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 246 .getActiveNotifications(); 247 248 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))) 249 .thenReturn(mSensitiveRanking); 250 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_2))) 251 .thenReturn(mSensitiveRanking); 252 253 return new ArraySet<>( 254 Set.of(new PackageInfo(NOTIFICATION_PKG_1, NOTIFICATION_UID_1), 255 new PackageInfo(NOTIFICATION_PKG_2, NOTIFICATION_UID_1))); 256 } 257 setupMultipleSensitiveNotificationsFromDifferentUid()258 private ArraySet<PackageInfo> setupMultipleSensitiveNotificationsFromDifferentUid() { 259 // Setup Notification Values 260 when(mNotification1.getKey()).thenReturn(NOTIFICATION_KEY_1); 261 when(mNotification1.getPackageName()).thenReturn(NOTIFICATION_PKG_1); 262 when(mNotification1.getUid()).thenReturn(NOTIFICATION_UID_1); 263 264 when(mNotification2.getKey()).thenReturn(NOTIFICATION_KEY_2); 265 when(mNotification2.getPackageName()).thenReturn(NOTIFICATION_PKG_1); 266 when(mNotification2.getUid()).thenReturn(NOTIFICATION_UID_2); 267 268 StatusBarNotification[] mNotifications = 269 new StatusBarNotification[] {mNotification1, mNotification2}; 270 doReturn(mNotifications) 271 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 272 .getActiveNotifications(); 273 274 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))) 275 .thenReturn(mSensitiveRanking); 276 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_2))) 277 .thenReturn(mSensitiveRanking); 278 279 return new ArraySet<>( 280 Set.of(new PackageInfo(NOTIFICATION_PKG_1, NOTIFICATION_UID_1), 281 new PackageInfo(NOTIFICATION_PKG_1, NOTIFICATION_UID_2))); 282 } 283 setupNoSensitiveNotifications()284 private void setupNoSensitiveNotifications() { 285 // Setup Notification Values 286 when(mNotification1.getKey()).thenReturn(NOTIFICATION_KEY_1); 287 when(mNotification1.getPackageName()).thenReturn(NOTIFICATION_PKG_1); 288 when(mNotification1.getUid()).thenReturn(NOTIFICATION_UID_1); 289 290 StatusBarNotification[] mNotifications = new StatusBarNotification[] {mNotification1}; 291 doReturn(mNotifications) 292 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 293 .getActiveNotifications(); 294 295 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))) 296 .thenReturn(mNonSensitiveRanking); 297 } 298 setupNoNotifications()299 private void setupNoNotifications() { 300 // Setup Notification Values 301 StatusBarNotification[] mNotifications = new StatusBarNotification[] {}; 302 doReturn(mNotifications) 303 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 304 .getActiveNotifications(); 305 } 306 setupNullNotifications()307 private void setupNullNotifications() { 308 // Setup Notification Values 309 StatusBarNotification[] mNotifications = new StatusBarNotification[] { null, null}; 310 doReturn(mNotifications) 311 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 312 .getActiveNotifications(); 313 } 314 createMediaProjectionInfo()315 private MediaProjectionInfo createMediaProjectionInfo() { 316 return new MediaProjectionInfo(SCREEN_RECORDER_PACKAGE, Process.myUserHandle(), null); 317 } 318 createExemptMediaProjectionInfo()319 private MediaProjectionInfo createExemptMediaProjectionInfo() { 320 return new MediaProjectionInfo( 321 EXEMPTED_SCREEN_RECORDER_PACKAGE, Process.myUserHandle(), null); 322 } 323 324 @Test mediaProjectionOnStart_verifyExemptedAppStreamingPackage()325 public void mediaProjectionOnStart_verifyExemptedAppStreamingPackage() { 326 MediaProjectionInfo mediaProjectionInfo = createMediaProjectionInfo(); 327 when(mRoleManager.getRoleHoldersAsUser(AssociationRequest.DEVICE_PROFILE_APP_STREAMING, 328 mediaProjectionInfo.getUserHandle())).thenReturn( 329 List.of(mediaProjectionInfo.getPackageName())); 330 331 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 332 333 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 334 } 335 336 @Test mediaProjectionOnStart_verifyExemptedRecorderPackage()337 public void mediaProjectionOnStart_verifyExemptedRecorderPackage() { 338 MediaProjectionInfo mediaProjectionInfo = createExemptMediaProjectionInfo(); 339 340 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 341 342 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 343 } 344 345 @Test 346 @RequiresFlagsDisabled(FLAG_SENSITIVE_CONTENT_METRICS_BUGFIX) mediaProjectionOnStart_flagDisabled_neverSetBlockScreenCaptureForAppsSessionId()347 public void mediaProjectionOnStart_flagDisabled_neverSetBlockScreenCaptureForAppsSessionId() { 348 setupSensitiveNotification(); 349 350 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 351 352 verify(mWindowManager, never()).setBlockScreenCaptureForAppsSessionId(anyLong()); 353 } 354 355 @Test 356 @RequiresFlagsEnabled(FLAG_SENSITIVE_CONTENT_METRICS_BUGFIX) mediaProjectionOnStart_setBlockScreenCaptureForAppsSessionId()357 public void mediaProjectionOnStart_setBlockScreenCaptureForAppsSessionId() { 358 setupSensitiveNotification(); 359 360 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 361 362 verify(mWindowManager).setBlockScreenCaptureForAppsSessionId(anyLong()); 363 } 364 365 @Test mediaProjectionOnStart_onProjectionStart_setWmBlockedPackages()366 public void mediaProjectionOnStart_onProjectionStart_setWmBlockedPackages() { 367 ArraySet<PackageInfo> expectedBlockedPackages = setupSensitiveNotification(); 368 369 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 370 371 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 372 } 373 374 @Test mediaProjectionOnStart_noSensitiveNotifications_noBlockedPackages()375 public void mediaProjectionOnStart_noSensitiveNotifications_noBlockedPackages() { 376 setupNoSensitiveNotifications(); 377 378 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 379 380 verify(mWindowManager, never()).addBlockScreenCaptureForApps(any()); 381 } 382 383 @Test mediaProjectionOnStart_noNotifications_noBlockedPackages()384 public void mediaProjectionOnStart_noNotifications_noBlockedPackages() { 385 setupNoNotifications(); 386 387 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 388 389 verify(mWindowManager, never()).addBlockScreenCaptureForApps(any()); 390 } 391 392 @Test mediaProjectionOnStart_multipleNotifications_setWmBlockedPackages()393 public void mediaProjectionOnStart_multipleNotifications_setWmBlockedPackages() { 394 ArraySet<PackageInfo> expectedBlockedPackages = 395 setupMultipleSensitiveNotificationsFromSamePackageAndUid(); 396 397 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 398 399 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 400 } 401 402 @Test mediaProjectionOnStart_multiplePackages_setWmBlockedPackages()403 public void mediaProjectionOnStart_multiplePackages_setWmBlockedPackages() { 404 ArraySet<PackageInfo> expectedBlockedPackages = 405 setupMultipleSensitiveNotificationsFromDifferentPackage(); 406 407 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 408 409 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 410 } 411 412 @Test mediaProjectionOnStart_multipleUid_setWmBlockedPackages()413 public void mediaProjectionOnStart_multipleUid_setWmBlockedPackages() { 414 ArraySet<PackageInfo> expectedBlockedPackages = 415 setupMultipleSensitiveNotificationsFromDifferentUid(); 416 417 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 418 419 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 420 } 421 422 @Test mediaProjectionOnStop_onProjectionEnd_clearWmBlockedPackages()423 public void mediaProjectionOnStop_onProjectionEnd_clearWmBlockedPackages() { 424 setupSensitiveNotification(); 425 426 MediaProjectionInfo mediaProjectionInfo = createMediaProjectionInfo(); 427 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 428 Mockito.reset(mWindowManager); 429 430 mMediaProjectionCallbackCaptor.getValue().onStop(mediaProjectionInfo); 431 432 verify(mWindowManager).clearBlockedApps(); 433 } 434 435 @Test mediaProjectionOnStart_afterOnStop_onProjectionStart_setWmBlockedPackages()436 public void mediaProjectionOnStart_afterOnStop_onProjectionStart_setWmBlockedPackages() { 437 ArraySet<PackageInfo> expectedBlockedPackages = setupSensitiveNotification(); 438 439 MediaProjectionInfo mediaProjectionInfo = createMediaProjectionInfo(); 440 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 441 mMediaProjectionCallbackCaptor.getValue().onStop(mediaProjectionInfo); 442 Mockito.reset(mWindowManager); 443 444 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 445 446 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 447 } 448 449 @Test mediaProjectionOnStart_getActiveNotificationsThrows_noBlockedPackages()450 public void mediaProjectionOnStart_getActiveNotificationsThrows_noBlockedPackages() { 451 doThrow(SecurityException.class) 452 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 453 .getActiveNotifications(); 454 455 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 456 457 verify(mWindowManager, never()).addBlockScreenCaptureForApps(any()); 458 } 459 460 @Test mediaProjectionOnStart_getCurrentRankingThrows_noBlockedPackages()461 public void mediaProjectionOnStart_getCurrentRankingThrows_noBlockedPackages() { 462 doThrow(SecurityException.class) 463 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 464 .getCurrentRanking(); 465 466 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 467 468 verify(mWindowManager, never()).addBlockScreenCaptureForApps(any()); 469 } 470 471 @Test mediaProjectionOnStart_getCurrentRanking_nullRankingMap_noBlockedPackages()472 public void mediaProjectionOnStart_getCurrentRanking_nullRankingMap_noBlockedPackages() { 473 doReturn(null) 474 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 475 .getCurrentRanking(); 476 477 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 478 479 verify(mWindowManager, never()).addBlockScreenCaptureForApps(any()); 480 } 481 482 @Test mediaProjectionOnStart_getCurrentRanking_missingRanking_noBlockedPackages()483 public void mediaProjectionOnStart_getCurrentRanking_missingRanking_noBlockedPackages() { 484 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))).thenReturn(null); 485 486 doReturn(mRankingMap) 487 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 488 .getCurrentRanking(); 489 490 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 491 492 verify(mWindowManager, never()).addBlockScreenCaptureForApps(any()); 493 } 494 495 @Test mediaProjectionOnStart_disabledViaDevOption_noBlockedPackages()496 public void mediaProjectionOnStart_disabledViaDevOption_noBlockedPackages() { 497 mockDisabledViaDevelopOption(); 498 setupSensitiveNotification(); 499 500 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 501 502 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 503 } 504 505 @Test nlsOnListenerConnected_projectionNotStarted_noop()506 public void nlsOnListenerConnected_projectionNotStarted_noop() { 507 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 508 // as non-sensitive 509 setupSensitiveNotification(); 510 511 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 512 513 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 514 } 515 516 @Test nlsOnListenerConnected_projectionStopped_noop()517 public void nlsOnListenerConnected_projectionStopped_noop() { 518 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 519 // as non-sensitive 520 setupSensitiveNotification(); 521 MediaProjectionInfo mediaProjectionInfo = createMediaProjectionInfo(); 522 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 523 mMediaProjectionCallbackCaptor.getValue().onStop(mediaProjectionInfo); 524 Mockito.reset(mWindowManager); 525 526 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 527 528 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 529 } 530 531 @Test nlsOnListenerConnected_projectionStarted_setWmBlockedPackages()532 public void nlsOnListenerConnected_projectionStarted_setWmBlockedPackages() { 533 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 534 // as non-sensitive 535 ArraySet<PackageInfo> expectedBlockedPackages = setupSensitiveNotification(); 536 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 537 Mockito.reset(mWindowManager); 538 539 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 540 541 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 542 } 543 544 @Test nlsOnListenerConnected_noSensitiveNotifications_noBlockedPackages()545 public void nlsOnListenerConnected_noSensitiveNotifications_noBlockedPackages() { 546 setupNoSensitiveNotifications(); 547 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 548 Mockito.reset(mWindowManager); 549 550 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 551 552 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 553 } 554 555 @Test nlsOnListenerConnected_noNotifications_noBlockedPackages()556 public void nlsOnListenerConnected_noNotifications_noBlockedPackages() { 557 setupNoNotifications(); 558 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 559 Mockito.reset(mWindowManager); 560 561 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 562 563 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 564 } 565 566 @Test nlsOnListenerConnected_nullNotifications_noBlockedPackages()567 public void nlsOnListenerConnected_nullNotifications_noBlockedPackages() { 568 setupNullNotifications(); 569 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 570 Mockito.reset(mWindowManager); 571 572 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 573 574 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 575 } 576 577 @Test nlsOnListenerConnected_nullRankingMap_noBlockedPackages()578 public void nlsOnListenerConnected_nullRankingMap_noBlockedPackages() { 579 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 580 // as non-sensitive 581 setupSensitiveNotification(); 582 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 583 Mockito.reset(mWindowManager); 584 doReturn(null) 585 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 586 .getCurrentRanking(); 587 588 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 589 590 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 591 } 592 593 @Test nlsOnListenerConnected_missingRanking_noBlockedPackages()594 public void nlsOnListenerConnected_missingRanking_noBlockedPackages() { 595 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 596 // as non-sensitive 597 setupSensitiveNotification(); 598 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 599 Mockito.reset(mWindowManager); 600 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))).thenReturn(null); 601 doReturn(mRankingMap) 602 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 603 .getCurrentRanking(); 604 605 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 606 607 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 608 } 609 610 @Test nlsOnListenerConnected_disabledViaDevOption_noBlockedPackages()611 public void nlsOnListenerConnected_disabledViaDevOption_noBlockedPackages() { 612 mockDisabledViaDevelopOption(); 613 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 614 // as non-sensitive 615 setupSensitiveNotification(); 616 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 617 mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); 618 619 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 620 } 621 622 @Test nlsOnNotificationRankingUpdate_projectionNotStarted_noop()623 public void nlsOnNotificationRankingUpdate_projectionNotStarted_noop() { 624 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 625 // as non-sensitive 626 setupSensitiveNotification(); 627 628 mSensitiveContentProtectionManagerService.mNotificationListener 629 .onNotificationRankingUpdate(mRankingMap); 630 631 verifyNoBlockOrClearInteractionWithWindowManager(); 632 } 633 634 @Test nlsOnNotificationRankingUpdate_projectionStopped_noop()635 public void nlsOnNotificationRankingUpdate_projectionStopped_noop() { 636 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 637 // as non-sensitive 638 setupSensitiveNotification(); 639 MediaProjectionInfo mediaProjectionInfo = createMediaProjectionInfo(); 640 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 641 mMediaProjectionCallbackCaptor.getValue().onStop(mediaProjectionInfo); 642 Mockito.reset(mWindowManager); 643 644 mSensitiveContentProtectionManagerService.mNotificationListener 645 .onNotificationRankingUpdate(mRankingMap); 646 647 verifyNoBlockOrClearInteractionWithWindowManager(); 648 } 649 650 @Test nlsOnNotificationRankingUpdate_projectionStarted_setWmBlockedPackages()651 public void nlsOnNotificationRankingUpdate_projectionStarted_setWmBlockedPackages() { 652 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 653 // as non-sensitive 654 ArraySet<PackageInfo> expectedBlockedPackages = setupSensitiveNotification(); 655 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 656 Mockito.reset(mWindowManager); 657 658 mSensitiveContentProtectionManagerService.mNotificationListener 659 .onNotificationRankingUpdate(mRankingMap); 660 661 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 662 } 663 664 @Test nlsOnNotificationRankingUpdate_noSensitiveNotifications_noBlockedPackages()665 public void nlsOnNotificationRankingUpdate_noSensitiveNotifications_noBlockedPackages() { 666 setupNoSensitiveNotifications(); 667 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 668 Mockito.reset(mWindowManager); 669 670 mSensitiveContentProtectionManagerService.mNotificationListener 671 .onNotificationRankingUpdate(mRankingMap); 672 673 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 674 } 675 676 @Test nlsOnNotificationRankingUpdate_noNotifications_noBlockedPackages()677 public void nlsOnNotificationRankingUpdate_noNotifications_noBlockedPackages() { 678 setupNoNotifications(); 679 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 680 Mockito.reset(mWindowManager); 681 682 mSensitiveContentProtectionManagerService.mNotificationListener 683 .onNotificationRankingUpdate(mRankingMap); 684 685 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 686 } 687 688 @Test nlsOnNotificationRankingUpdate_nullRankingMap_noBlockedPackages()689 public void nlsOnNotificationRankingUpdate_nullRankingMap_noBlockedPackages() { 690 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 691 // as non-sensitive 692 setupSensitiveNotification(); 693 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 694 Mockito.reset(mWindowManager); 695 696 mSensitiveContentProtectionManagerService.mNotificationListener 697 .onNotificationRankingUpdate(null); 698 699 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 700 } 701 702 @Test nlsOnNotificationRankingUpdate_missingRanking_noBlockedPackages()703 public void nlsOnNotificationRankingUpdate_missingRanking_noBlockedPackages() { 704 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 705 // as non-sensitive 706 setupSensitiveNotification(); 707 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 708 Mockito.reset(mWindowManager); 709 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))).thenReturn(null); 710 doReturn(mRankingMap) 711 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 712 .getCurrentRanking(); 713 714 mSensitiveContentProtectionManagerService.mNotificationListener 715 .onNotificationRankingUpdate(mRankingMap); 716 717 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 718 } 719 720 @Test nlsOnNotificationRankingUpdate_getActiveNotificationsThrows_noBlockedPackages()721 public void nlsOnNotificationRankingUpdate_getActiveNotificationsThrows_noBlockedPackages() { 722 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 723 // as non-sensitive 724 setupSensitiveNotification(); 725 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 726 Mockito.reset(mWindowManager); 727 728 doThrow(SecurityException.class) 729 .when(mSensitiveContentProtectionManagerService.mNotificationListener) 730 .getActiveNotifications(); 731 732 mSensitiveContentProtectionManagerService.mNotificationListener 733 .onNotificationRankingUpdate(mRankingMap); 734 735 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 736 } 737 738 @Test nlsOnNotificationRankingUpdate_disabledViaDevOption_noBlockedPackages()739 public void nlsOnNotificationRankingUpdate_disabledViaDevOption_noBlockedPackages() { 740 mockDisabledViaDevelopOption(); 741 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 742 // as non-sensitive 743 setupSensitiveNotification(); 744 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 745 mSensitiveContentProtectionManagerService.mNotificationListener 746 .onNotificationRankingUpdate(mRankingMap); 747 748 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 749 } 750 751 @Test nlsOnNotificationPosted_projectionNotStarted_noop()752 public void nlsOnNotificationPosted_projectionNotStarted_noop() { 753 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 754 // as non-sensitive 755 setupSensitiveNotification(); 756 757 mSensitiveContentProtectionManagerService.mNotificationListener 758 .onNotificationPosted(mNotification1, mRankingMap); 759 760 verifyNoBlockOrClearInteractionWithWindowManager(); 761 } 762 763 @Test nlsOnNotificationPosted_projectionStopped_noop()764 public void nlsOnNotificationPosted_projectionStopped_noop() { 765 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 766 // as non-sensitive 767 setupSensitiveNotification(); 768 MediaProjectionInfo mediaProjectionInfo = createMediaProjectionInfo(); 769 mMediaProjectionCallbackCaptor.getValue().onStart(mediaProjectionInfo); 770 mMediaProjectionCallbackCaptor.getValue().onStop(mediaProjectionInfo); 771 Mockito.reset(mWindowManager); 772 773 mSensitiveContentProtectionManagerService.mNotificationListener 774 .onNotificationPosted(mNotification1, mRankingMap); 775 776 verifyNoBlockOrClearInteractionWithWindowManager(); 777 } 778 779 @Test nlsOnNotificationPosted_projectionStarted_setWmBlockedPackages()780 public void nlsOnNotificationPosted_projectionStarted_setWmBlockedPackages() { 781 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 782 // as non-sensitive 783 setupSensitiveNotification(); 784 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 785 Mockito.reset(mWindowManager); 786 787 mSensitiveContentProtectionManagerService.mNotificationListener 788 .onNotificationPosted(mNotification1, mRankingMap); 789 790 ArraySet<PackageInfo> expectedBlockedPackages = new ArraySet<>( 791 Set.of(new PackageInfo(NOTIFICATION_PKG_1, NOTIFICATION_UID_1))); 792 verify(mWindowManager).addBlockScreenCaptureForApps(expectedBlockedPackages); 793 } 794 795 @Test nlsOnNotificationPosted_noSensitiveNotifications_noBlockedPackages()796 public void nlsOnNotificationPosted_noSensitiveNotifications_noBlockedPackages() { 797 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 798 // as non-sensitive 799 setupSensitiveNotification(); 800 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 801 Mockito.reset(mWindowManager); 802 803 mSensitiveContentProtectionManagerService.mNotificationListener 804 .onNotificationPosted(mNotification2, mRankingMap); 805 806 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 807 } 808 809 @Test nlsOnNotificationPosted_noNotifications_noBlockedPackages()810 public void nlsOnNotificationPosted_noNotifications_noBlockedPackages() { 811 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 812 // as non-sensitive 813 setupSensitiveNotification(); 814 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 815 Mockito.reset(mWindowManager); 816 817 mSensitiveContentProtectionManagerService.mNotificationListener 818 .onNotificationPosted(null, mRankingMap); 819 820 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 821 } 822 823 @Test nlsOnNotificationPosted_nullRankingMap_noBlockedPackages()824 public void nlsOnNotificationPosted_nullRankingMap_noBlockedPackages() { 825 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 826 // as non-sensitive 827 setupSensitiveNotification(); 828 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 829 Mockito.reset(mWindowManager); 830 831 mSensitiveContentProtectionManagerService.mNotificationListener 832 .onNotificationPosted(mNotification1, null); 833 834 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 835 } 836 837 @Test nlsOnNotificationPosted_missingRanking_noBlockedPackages()838 public void nlsOnNotificationPosted_missingRanking_noBlockedPackages() { 839 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 840 // as non-sensitive 841 setupSensitiveNotification(); 842 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 843 Mockito.reset(mWindowManager); 844 when(mRankingMap.getRawRankingObject(eq(NOTIFICATION_KEY_1))).thenReturn(null); 845 846 mSensitiveContentProtectionManagerService.mNotificationListener 847 .onNotificationPosted(mNotification1, mRankingMap); 848 849 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 850 } 851 852 @Test nlsOnNotificationPosted_disabledViaDevOption_noBlockedPackages()853 public void nlsOnNotificationPosted_disabledViaDevOption_noBlockedPackages() { 854 mockDisabledViaDevelopOption(); 855 // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 856 // as non-sensitive 857 setupSensitiveNotification(); 858 mMediaProjectionCallbackCaptor.getValue().onStart(createMediaProjectionInfo()); 859 mSensitiveContentProtectionManagerService.mNotificationListener 860 .onNotificationPosted(mNotification1, mRankingMap); 861 862 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 863 } 864 verifyNoBlockOrClearInteractionWithWindowManager()865 private void verifyNoBlockOrClearInteractionWithWindowManager() { 866 verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 867 verify(mWindowManager, never()).clearBlockedApps(); 868 verify(mWindowManager, never()) 869 .removeBlockScreenCaptureForApps(mPackageInfoCaptor.capture()); 870 } 871 mockDisabledViaDevelopOption()872 private void mockDisabledViaDevelopOption() { 873 // mContext (TestableContext) uses [TestableSettingsProvider] and it will be cleared after 874 // the test 875 Settings.Global.putInt( 876 mContext.getContentResolver(), 877 Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 878 1); 879 } 880 } 881