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

Commit f10b604a authored by Richard MacGregor's avatar Richard MacGregor Committed by Android (Google) Code Review
Browse files

Merge "Add sensitive notification protection exemptions" into main

parents 0b727717 d521c63f
Loading
Loading
Loading
Loading
+29 −7
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.media.projection.MediaProjectionInfo;
import android.media.projection.MediaProjectionManager;
import android.os.Handler;
import android.os.Trace;
import android.service.notification.StatusBarNotification;

import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.dagger.SysUISingleton;
@@ -46,8 +47,9 @@ public class SensitiveNotificationProtectionControllerImpl
                public void onStart(MediaProjectionInfo info) {
                    Trace.beginSection(
                            "SNPC.onProjectionStart");
                    mProjection = info;
                    mListeners.forEach(Runnable::run);
                    // Only enable sensitive content protection if sharing full screen
                    // Launch cookie only set (non-null) if sharing single app/task
                    updateProjectionState((info.getLaunchCookie() == null) ? info : null);
                    Trace.endSection();
                }

@@ -55,10 +57,22 @@ public class SensitiveNotificationProtectionControllerImpl
                public void onStop(MediaProjectionInfo info) {
                    Trace.beginSection(
                            "SNPC.onProjectionStop");
                    mProjection = null;
                    mListeners.forEach(Runnable::run);
                    updateProjectionState(null);
                    Trace.endSection();
                }

                private void updateProjectionState(MediaProjectionInfo info) {
                    // capture previous state
                    boolean wasSensitive = isSensitiveStateActive();

                    // update internal state
                    mProjection = info;

                    // if either previous or new state is sensitive, notify listeners.
                    if (wasSensitive || isSensitiveStateActive()) {
                        mListeners.forEach(Runnable::run);
                    }
                }
            };

    @Inject
@@ -86,7 +100,6 @@ public class SensitiveNotificationProtectionControllerImpl
    public boolean isSensitiveStateActive() {
        // TODO(b/316955558): Add disabled by developer option
        // TODO(b/316955306): Add feature exemption for sysui and bug handlers
        // TODO(b/316955346): Add feature exemption for single app screen sharing
        return mProjection != null;
    }

@@ -96,9 +109,18 @@ public class SensitiveNotificationProtectionControllerImpl
            return false;
        }

        MediaProjectionInfo projection = mProjection;
        if (projection == null) {
            return false;
        }

        // Exempt foreground service notifications from protection in effort to keep screen share
        // stop actions easily accessible
        // TODO(b/316955208): Exempt FGS notifications only for app that started projection
        return !entry.getSbn().getNotification().isFgsOrUij();
        StatusBarNotification sbn = entry.getSbn();
        if (sbn.getNotification().isFgsOrUij()) {
            return !sbn.getPackageName().equals(projection.getPackageName());
        }

        return true;
    }
}
+64 −9
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package com.android.systemui.statusbar.policy

import android.app.ActivityOptions
import android.app.Notification
import android.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
@@ -69,6 +70,8 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        MockitoAnnotations.initMocks(this)
        mSetFlagsRule.enableFlags(Flags.FLAG_SCREENSHARE_NOTIFICATION_HIDING)

        setShareFullScreen()

        controller = SensitiveNotificationProtectionControllerImpl(mediaProjectionManager, handler)

        // Obtain useful MediaProjectionCallback
@@ -194,6 +197,14 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
        assertTrue(controller.isSensitiveStateActive)
    }

    @Test
    fun isSensitiveStateActive_projectionActive_singleActivity_false() {
        setShareSingleApp()
        mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)

        assertFalse(controller.isSensitiveStateActive)
    }

    @Test
    fun shouldProtectNotification_projectionInactive_false() {
        val notificationEntry = mock(NotificationEntry::class.java)
@@ -202,30 +213,74 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() {
    }

    @Test
    fun shouldProtectNotification_projectionActive_fgsNotification_false() {
    fun shouldProtectNotification_projectionActive_singleActivity_false() {
        setShareSingleApp()
        mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)

        val notificationEntry = mock(NotificationEntry::class.java)
        val sbn = mock(StatusBarNotification::class.java)
        val notification = mock(Notification::class.java)
        `when`(notificationEntry.sbn).thenReturn(sbn)
        `when`(sbn.notification).thenReturn(notification)
        `when`(notification.isFgsOrUij).thenReturn(true)
        val notificationEntry = setupNotificationEntry(TEST_PACKAGE_NAME)

        assertFalse(controller.shouldProtectNotification(notificationEntry))
    }

    @Test
    fun shouldProtectNotification_projectionActive_fgsNotificationFromProjectionApp_false() {
        mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)

        val notificationEntry = setupFgsNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)

        assertFalse(controller.shouldProtectNotification(notificationEntry))
    }

    @Test
    fun shouldProtectNotification_projectionActive_fgsNotificationNotFromProjectionApp_true() {
        mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)

        val notificationEntry = setupFgsNotificationEntry(TEST_PACKAGE_NAME)

        assertTrue(controller.shouldProtectNotification(notificationEntry))
    }

    @Test
    fun shouldProtectNotification_projectionActive_notFgsNotification_true() {
        mediaProjectionCallbackCaptor.value.onStart(mediaProjectionInfo)

        val notificationEntry = setupNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)

        assertTrue(controller.shouldProtectNotification(notificationEntry))
    }

    private fun setShareFullScreen() {
        `when`(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
        `when`(mediaProjectionInfo.launchCookie).thenReturn(null)
    }

    private fun setShareSingleApp() {
        `when`(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME)
        `when`(mediaProjectionInfo.launchCookie).thenReturn(ActivityOptions.LaunchCookie())
    }

    private fun setupNotificationEntry(
        packageName: String,
        isFgs: Boolean = false
    ): NotificationEntry {
        val notificationEntry = mock(NotificationEntry::class.java)
        val sbn = mock(StatusBarNotification::class.java)
        val notification = mock(Notification::class.java)
        `when`(notificationEntry.sbn).thenReturn(sbn)
        `when`(sbn.packageName).thenReturn(packageName)
        `when`(sbn.notification).thenReturn(notification)
        `when`(notification.isFgsOrUij).thenReturn(false)
        `when`(notification.isFgsOrUij).thenReturn(isFgs)

        assertTrue(controller.shouldProtectNotification(notificationEntry))
        return notificationEntry
    }

    private fun setupFgsNotificationEntry(packageName: String): NotificationEntry {
        return setupNotificationEntry(packageName, /* isFgs= */ true)
    }

    companion object {
        private const val TEST_PROJECTION_PACKAGE_NAME =
            "com.android.systemui.statusbar.policy.projectionpackage"
        private const val TEST_PACKAGE_NAME = "com.android.systemui.statusbar.policy.testpackage"
    }
}