Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 09526194 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Exempt APP_STREAMING role holders from screenshare protections" into main

parents 768289ae 4a7539be
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.systemui.statusbar.policy

import android.app.IActivityManager
import android.app.role.RoleManager
import android.content.pm.PackageManager
import android.media.projection.MediaProjectionManager
import android.os.Handler
@@ -48,6 +49,7 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase(
    @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
    @Mock private lateinit var packageManager: PackageManager
    @Mock private lateinit var telephonyManager: TelephonyManager
    @Mock private lateinit var roleManager: RoleManager
    private lateinit var controller: SensitiveNotificationProtectionControllerImpl

    @Before
@@ -62,9 +64,10 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase(
                activityManager,
                packageManager,
                telephonyManager,
                roleManager,
                handler,
                FakeExecutor(FakeSystemClock()),
                logger
                logger,
            )
    }

+64 −1
Original line number Diff line number Diff line
@@ -24,6 +24,9 @@ import static com.android.systemui.Flags.screenshareNotificationHidingBugFix;

import android.annotation.MainThread;
import android.app.IActivityManager;
import android.app.role.OnRoleHoldersChangedListener;
import android.app.role.RoleManager;
import android.companion.AssociationRequest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.database.ExecutorContentObserver;
@@ -51,6 +54,8 @@ import com.android.systemui.util.Assert;
import com.android.systemui.util.ListenerSet;
import com.android.systemui.util.settings.GlobalSettings;

import java.util.List;
import java.util.Objects;
import java.util.Random;
import java.util.concurrent.Executor;

@@ -63,12 +68,14 @@ public class SensitiveNotificationProtectionControllerImpl
    private static final String LOG_TAG = "SNPC";
    private final SensitiveNotificationProtectionControllerLogger mLogger;
    private final PackageManager mPackageManager;
    private final RoleManager mRoleManager;
    // Packages exempt from projection session protections (if they start a projection session)
    private final ArraySet<String> mSessionProtectionExemptPackages = new ArraySet<>();
    // Packages exempt from individual notification protections (if they post a notification)
    private final ArraySet<String> mNotificationProtectionExemptPackages = new ArraySet<>();
    private final ListenerSet<Runnable> mListeners = new ListenerSet<>();
    private volatile MediaProjectionInfo mProjection;
    private ArraySet<RoleHolder> mNotificationProtectionExemptByRolePackages = new ArraySet<>();
    private SensitiveNotificatioMediaProjectionSession mActiveMediaProjectionSession;
    boolean mDisableScreenShareProtections = false;

@@ -128,6 +135,27 @@ public class SensitiveNotificationProtectionControllerImpl
                }
            };

    @VisibleForTesting
    final OnRoleHoldersChangedListener mRoleHoldersChangedListener =
            new OnRoleHoldersChangedListener() {
                @Override
                public void onRoleHoldersChanged(@NonNull String roleName,
                        @NonNull UserHandle user) {
                    if (!roleName.equals(AssociationRequest.DEVICE_PROFILE_APP_STREAMING)) {
                        return;
                    }

                    List<String> appStreamingRoleHolders = mRoleManager.getRoleHoldersAsUser(
                            roleName, user);
                    ArraySet<RoleHolder> roleHolders = new ArraySet<>();
                    for (String appStreamingRoleHolder : appStreamingRoleHolders) {
                        RoleHolder roleHolder = new RoleHolder(appStreamingRoleHolder, user);
                        roleHolders.add(roleHolder);
                    }
                    mNotificationProtectionExemptByRolePackages = roleHolders;
                }
            };

    private void logSensitiveContentProtectionSessionStart(
            long sessionId, int projectionAppUid, boolean exempt) {
        mActiveMediaProjectionSession =
@@ -166,11 +194,13 @@ public class SensitiveNotificationProtectionControllerImpl
            IActivityManager activityManager,
            PackageManager packageManager,
            TelephonyManager telephonyManager,
            RoleManager roleManager,
            @Main Handler mainHandler,
            @Background Executor bgExecutor,
            SensitiveNotificationProtectionControllerLogger logger) {
        mLogger = logger;
        mPackageManager = packageManager;
        mRoleManager = roleManager;

        if (!screenshareNotificationHiding()) {
            return;
@@ -215,6 +245,8 @@ public class SensitiveNotificationProtectionControllerImpl
        });

        mediaProjectionManager.addCallback(mMediaProjectionCallback, mainHandler);
        roleManager.addOnRoleHoldersChangedListenerAsUser(bgExecutor, mRoleHoldersChangedListener,
                UserHandle.ALL);
    }

    @NonNull
@@ -314,6 +346,10 @@ public class SensitiveNotificationProtectionControllerImpl
            Log.w(LOG_TAG, "Screen share protections exempt for package " + info.getPackageName()
                    + " via permission");
            return null;
        } else if (info != null && isAppStreamingRoleHolder(info)) {
            Log.w(LOG_TAG, "Screen share protections exempt for package " + info.getPackageName()
                    + " via role(s) held");
            return null;
        } else if (info != null && info.getLaunchCookie() != null) {
            // Only enable sensitive content protection if sharing full screen
            // Launch cookie only set (non-null) if sharing single app/task
@@ -323,6 +359,11 @@ public class SensitiveNotificationProtectionControllerImpl
        return info;
    }

    private boolean isAppStreamingRoleHolder(@NonNull MediaProjectionInfo info) {
        return mNotificationProtectionExemptByRolePackages.contains(
                new RoleHolder(info.getPackageName(), info.getUserHandle()));
    }

    private boolean canRecordSensitiveContent(@NonNull String packageName) {
        // RECORD_SENSITIVE_CONTENT is flagged api on sensitiveNotificationAppProtection
        if (sensitiveNotificationAppProtection()) {
@@ -382,4 +423,26 @@ public class SensitiveNotificationProtectionControllerImpl
        boolean userForcesRedaction = entry.isChannelVisibilityPrivate();
        return notificationRequestsRedaction || userForcesRedaction;
    }

    private static final class RoleHolder {
        private final String mPackageName;
        private final UserHandle mUserHandle;

        RoleHolder(String packageName, UserHandle userHandle) {
            mPackageName = packageName;
            mUserHandle = userHandle;
        }

        @Override
        public boolean equals(Object o) {
            if (!(o instanceof RoleHolder that)) return false;
            return Objects.equals(mPackageName, that.mPackageName) && Objects.equals(
                    mUserHandle, that.mUserHandle);
        }

        @Override
        public int hashCode() {
            return Objects.hash(mPackageName, mUserHandle);
        }
    }
}
+47 −19
Original line number Diff line number Diff line
@@ -25,6 +25,9 @@ import android.app.Notification.VISIBILITY_PUBLIC
import android.app.NotificationChannel
import android.app.NotificationManager.IMPORTANCE_HIGH
import android.app.NotificationManager.VISIBILITY_NO_OVERRIDE
import android.app.role.OnRoleHoldersChangedListener
import android.app.role.RoleManager
import android.companion.AssociationRequest
import android.content.pm.PackageManager
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
@@ -89,6 +92,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
    @Mock private lateinit var activityManager: IActivityManager
    @Mock private lateinit var mediaProjectionManager: MediaProjectionManager
    @Mock private lateinit var packageManager: PackageManager
    @Mock private lateinit var roleManager: RoleManager
    @Mock private lateinit var telephonyManager: TelephonyManager
    @Mock private lateinit var listener1: Runnable
    @Mock private lateinit var listener2: Runnable
@@ -98,6 +102,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
    private lateinit var executor: FakeExecutor
    private lateinit var globalSettings: FakeGlobalSettings
    private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback
    private lateinit var roleHolderCallback: OnRoleHoldersChangedListener
    private lateinit var controller: SensitiveNotificationProtectionControllerImpl
    private lateinit var mediaProjectionInfo: MediaProjectionInfo

@@ -117,14 +122,14 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        whenever(
                packageManager.getPackageUidAsUser(
                    TEST_PROJECTION_PACKAGE_NAME,
                    UserHandle.CURRENT.identifier
                    UserHandle.CURRENT.identifier,
                )
            )
            .thenReturn(TEST_PROJECTION_PACKAGE_UID)
        whenever(
                packageManager.getPackageUidAsUser(
                    BUGREPORT_PACKAGE_NAME,
                    UserHandle.CURRENT.identifier
                    UserHandle.CURRENT.identifier,
                )
            )
            .thenReturn(BUGREPORT_PACKAGE_UID)
@@ -134,7 +139,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        whenever(
                packageManager.getPackageUidAsUser(
                    mContext.packageName,
                    UserHandle.CURRENT.identifier
                    UserHandle.CURRENT.identifier,
                )
            )
            .thenReturn(mContext.applicationInfo.uid)
@@ -155,9 +160,10 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                activityManager,
                packageManager,
                telephonyManager,
                roleManager,
                mockExecutorHandler(executor),
                executor,
                logger
                logger,
            )

        // Process pending work (getting global setting and list of exemptions)
@@ -167,6 +173,9 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        mediaProjectionCallback = withArgCaptor {
            verify(mediaProjectionManager).addCallback(capture(), any())
        }
        roleHolderCallback = withArgCaptor {
            verify(roleManager).addOnRoleHoldersChangedListenerAsUser(any(), capture(), any())
        }
    }

    @After
@@ -307,7 +316,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        whenever(
                packageManager.checkPermission(
                    android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
                    mediaProjectionInfo.packageName
                    mediaProjectionInfo.packageName,
                )
            )
            .thenReturn(PackageManager.PERMISSION_GRANTED)
@@ -322,7 +331,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        whenever(
                packageManager.checkPermission(
                    android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
                    mediaProjectionInfo.packageName
                    mediaProjectionInfo.packageName,
                )
            )
            .thenReturn(PackageManager.PERMISSION_GRANTED)
@@ -339,6 +348,25 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        assertFalse(controller.isSensitiveStateActive)
    }

    @Test
    fun isSensitiveStateActive_projectionActive_appStreamingRoleHolderExempt_false() {
        setShareFullScreen()
        whenever(
                roleManager.getRoleHoldersAsUser(
                    AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
                    mediaProjectionInfo.userHandle,
                )
            )
            .thenReturn(listOf(TEST_PROJECTION_PACKAGE_NAME))
        roleHolderCallback.onRoleHoldersChanged(
            AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
            mediaProjectionInfo.userHandle,
        )
        mediaProjectionCallback.onStart(mediaProjectionInfo)

        assertFalse(controller.isSensitiveStateActive)
    }

    @Test
    fun isSensitiveStateActive_projectionActive_disabledViaDevOption_false() {
        setDisabledViaDeveloperOption()
@@ -449,7 +477,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        whenever(
                packageManager.checkPermission(
                    android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
                    mediaProjectionInfo.packageName
                    mediaProjectionInfo.packageName,
                )
            )
            .thenReturn(PackageManager.PERMISSION_GRANTED)
@@ -466,7 +494,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        whenever(
                packageManager.checkPermission(
                    android.Manifest.permission.RECORD_SENSITIVE_CONTENT,
                    mediaProjectionInfo.packageName
                    mediaProjectionInfo.packageName,
                )
            )
            .thenReturn(PackageManager.PERMISSION_GRANTED)
@@ -528,7 +556,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(TEST_PROJECTION_PACKAGE_UID),
                eq(false),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }

@@ -541,7 +569,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(TEST_PROJECTION_PACKAGE_UID),
                eq(false),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }
    }
@@ -559,7 +587,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(TEST_PROJECTION_PACKAGE_UID),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }

@@ -572,7 +600,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(TEST_PROJECTION_PACKAGE_UID),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }
    }
@@ -590,7 +618,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(TEST_PROJECTION_PACKAGE_UID),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }

@@ -603,7 +631,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(TEST_PROJECTION_PACKAGE_UID),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }
    }
@@ -623,7 +651,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(mContext.applicationInfo.uid),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }

@@ -636,7 +664,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(mContext.applicationInfo.uid),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }
    }
@@ -654,7 +682,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(BUGREPORT_PACKAGE_UID),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__START),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }

@@ -667,7 +695,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
                eq(BUGREPORT_PACKAGE_UID),
                eq(true),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__STATE__STOP),
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI)
                eq(FrameworkStatsLog.SENSITIVE_CONTENT_MEDIA_PROJECTION_SESSION__SOURCE__SYS_UI),
            )
        }
    }
@@ -757,7 +785,7 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        return setupNotificationEntry(
            packageName,
            overrideVisibility = true,
            overrideChannelVisibility = true
            overrideChannelVisibility = true,
        )
    }

+18 −3
Original line number Diff line number Diff line
@@ -31,6 +31,8 @@ import static com.android.server.wm.WindowManagerInternal.OnWindowRemovedListene

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.role.RoleManager;
import android.companion.AssociationRequest;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -81,6 +83,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic

    private PackageManagerInternal mPackageManagerInternal;

    private RoleManager mRoleManager;

    @Nullable
    private WindowManagerInternal mWindowManager;

@@ -225,7 +229,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
    }

    @Override
    public void onStart() {}
    public void onStart() {
    }

    @Override
    public void onBootPhase(int phase) {
@@ -237,6 +242,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
        init(getContext().getSystemService(MediaProjectionManager.class),
                LocalServices.getService(WindowManagerInternal.class),
                LocalServices.getService(PackageManagerInternal.class),
                getContext().getSystemService(RoleManager.class),
                getExemptedPackages()
        );
        if (sensitiveContentAppProtection()) {
@@ -247,7 +253,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic

    @VisibleForTesting
    void init(MediaProjectionManager projectionManager, WindowManagerInternal windowManager,
            PackageManagerInternal packageManagerInternal, ArraySet<String> exemptedPackages) {
            PackageManagerInternal packageManagerInternal, RoleManager roleManager,
            ArraySet<String> exemptedPackages) {
        if (DEBUG) Log.d(TAG, "init");

        Objects.requireNonNull(projectionManager);
@@ -256,6 +263,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
        mProjectionManager = projectionManager;
        mWindowManager = windowManager;
        mPackageManagerInternal = packageManagerInternal;
        mRoleManager = roleManager;
        mExemptedPackages = exemptedPackages;

        // TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary
@@ -312,6 +320,8 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
        boolean isPackageExempted = (mExemptedPackages != null && mExemptedPackages.contains(
                projectionInfo.getPackageName()))
                || canRecordSensitiveContent(projectionInfo.getPackageName())
                || holdsAppStreamingRole(projectionInfo.getPackageName(),
                projectionInfo.getUserHandle())
                || isAutofillServiceRecorderPackage(projectionInfo.getUserHandle().getIdentifier(),
                projectionInfo.getPackageName());
        // TODO(b/324447419): move GlobalSettings lookup to background thread
@@ -348,6 +358,11 @@ public final class SensitiveContentProtectionManagerService extends SystemServic
        }
    }

    private boolean holdsAppStreamingRole(String packageName, UserHandle userHandle) {
        return mRoleManager.getRoleHoldersAsUser(
                AssociationRequest.DEVICE_PROFILE_APP_STREAMING, userHandle).contains(packageName);
    }

    private void onProjectionEnd() {
        synchronized (mSensitiveContentProtectionLock) {
            mProjectionActive = false;
+21 −2
Original line number Diff line number Diff line
@@ -26,7 +26,10 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.atLeast;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.role.RoleManager;
import android.companion.AssociationRequest;
import android.content.pm.PackageManagerInternal;
import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
@@ -54,6 +57,7 @@ import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.List;
import java.util.Set;

@SmallTest
@@ -74,6 +78,7 @@ public class SensitiveContentProtectionManagerServiceContentTest {
    @Mock private WindowManagerInternal mWindowManager;
    @Mock private MediaProjectionManager mProjectionManager;
    @Mock private PackageManagerInternal mPackageManagerInternal;
    @Mock private RoleManager mRoleManager;
    private MediaProjectionInfo mMediaProjectionInfo;

    @Captor
@@ -93,7 +98,8 @@ public class SensitiveContentProtectionManagerServiceContentTest {
        mSensitiveContentProtectionManagerService =
                new SensitiveContentProtectionManagerService(mContext);
        mSensitiveContentProtectionManagerService.init(mProjectionManager, mWindowManager,
                mPackageManagerInternal, new ArraySet<>(Set.of(mExemptedScreenRecorderPackage)));
                mPackageManagerInternal, mRoleManager,
                new ArraySet<>(Set.of(mExemptedScreenRecorderPackage)));
        verify(mProjectionManager).addCallback(mMediaProjectionCallbackCaptor.capture(), any());
        mMediaPorjectionCallback = mMediaProjectionCallbackCaptor.getValue();
        mMediaProjectionInfo =
@@ -169,6 +175,19 @@ public class SensitiveContentProtectionManagerServiceContentTest {
        verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture());
    }

    @Test
    public void testAppStreamingRoleHolderExemption() {
        when(mRoleManager.getRoleHoldersAsUser(
                AssociationRequest.DEVICE_PROFILE_APP_STREAMING,
                mMediaProjectionInfo.getUserHandle())).thenReturn(
                List.of(mMediaProjectionInfo.getPackageName()));

        mMediaPorjectionCallback.onStart(mMediaProjectionInfo);
        mSensitiveContentProtectionManagerService.setSensitiveContentProtection(
                mPackageInfo.getWindowToken(), mPackageInfo.getPkg(), mPackageInfo.getUid(), true);
        verify(mWindowManager, never()).addBlockScreenCaptureForApps(mPackageInfoCaptor.capture());
    }

    private void mockDisabledViaDeveloperOption() {
        Settings.Global.putInt(
                mContext.getContentResolver(),
Loading