diff options
| author | 2024-01-22 15:42:26 -0800 | |
|---|---|---|
| committer | 2024-01-31 14:53:36 -0800 | |
| commit | d521c63f46c71bb43279a59d7b1fe5102ad4fb50 (patch) | |
| tree | 8ea4d83bb2e8425da7f94aeb422bfb698a14b5d6 | |
| parent | 3459cd0e5728c0f29d5c492f4e75a8592d35a8cc (diff) | |
Add sensitive notification protection exemptions
- Add exemption for FGS notifications from the app that started
projection
- Add exemption for single activity/task projection session
Bug: 316955208
Bug: 316955346
Test: atest SensitiveNotificationProtectionControllerTest
Flag: ACONFIG com.android.systemui.screenshare_notification_hiding DISABLED
Change-Id: I4dfb3af641f0ce6a89fa95e798cab9a63af96beb
2 files changed, 93 insertions, 16 deletions
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java index 3c4ca4465874..b0192c0f5ee5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java @@ -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; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt index cd5d5ed0d08e..9d53e7d8c9b8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt @@ -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 @@ -195,6 +198,14 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { } @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" } } |