• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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