summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java36
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerTest.kt73
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"
}
}