Fix notification visibility when screensharing
Do not redact if notification marked as public visiblity and not
overridden by user channel visiblity
Bug: 324111564
Test: atest SensitiveNotificationProtectionControllerTest
Flag: ACONFIG com.android.server.notification.screenshare_notification_hiding DISABLED
Change-Id: Ib678f277f6422eb87d9cea11438d9d2e603064ca
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 2b0a92c..6956a7d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java
@@ -221,10 +221,15 @@
// Exempt foreground service notifications from protection in effort to keep screen share
// stop actions easily accessible
StatusBarNotification sbn = entry.getSbn();
- if (sbn.getNotification().isFgsOrUij()) {
- return !sbn.getPackageName().equals(projection.getPackageName());
+ if (sbn.getNotification().isFgsOrUij()
+ && sbn.getPackageName().equals(projection.getPackageName())) {
+ return false;
}
- return true;
+ // Only protect/redact notifications if the developer has not explicitly set notification
+ // visibility as public and users has not adjusted default channel visibility to private
+ boolean notificationRequestsRedaction = entry.isNotificationVisibilityPrivate();
+ boolean userForcesRedaction = entry.isChannelVisibilityPrivate();
+ return notificationRequestsRedaction || userForcesRedaction;
}
}
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 1dac642..a2af38f 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
@@ -19,17 +19,24 @@
import android.app.ActivityOptions
import android.app.IActivityManager
import android.app.Notification
+import android.app.Notification.FLAG_FOREGROUND_SERVICE
+import android.app.Notification.VISIBILITY_PRIVATE
+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.media.projection.MediaProjectionInfo
import android.media.projection.MediaProjectionManager
import android.platform.test.annotations.EnableFlags
import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS
-import android.service.notification.StatusBarNotification
import android.testing.AndroidTestingRunner
import android.testing.TestableLooper.RunWithLooper
import androidx.test.filters.SmallTest
import com.android.server.notification.Flags
import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.RankingBuilder
import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.concurrency.mockExecutorHandler
import com.android.systemui.util.mockito.whenever
@@ -316,6 +323,25 @@
assertFalse(controller.shouldProtectNotification(notificationEntry))
}
+ @Test
+ fun shouldProtectNotification_projectionActive_publicNotification_false() {
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ // App marked notification visibility as public
+ val notificationEntry = setupPublicNotificationEntry(TEST_PROJECTION_PACKAGE_NAME)
+
+ assertFalse(controller.shouldProtectNotification(notificationEntry))
+ }
+
+ @Test
+ fun shouldProtectNotification_projectionActive_publicNotificationUserChannelOverride_true() {
+ mediaProjectionCallback.onStart(mediaProjectionInfo)
+
+ val notificationEntry =
+ setupPublicNotificationEntryWithUserOverriddenChannel(TEST_PROJECTION_PACKAGE_NAME)
+
+ assertTrue(controller.shouldProtectNotification(notificationEntry))
+ }
private fun setDisabledViaDeveloperOption() {
globalSettings.putInt(DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1)
@@ -336,21 +362,50 @@
private fun setupNotificationEntry(
packageName: String,
- isFgs: Boolean = false
+ isFgs: Boolean = false,
+ overrideVisibility: Boolean = false,
+ overrideChannelVisibility: Boolean = false,
): NotificationEntry {
- val notificationEntry = mock(NotificationEntry::class.java)
- val sbn = mock(StatusBarNotification::class.java)
- val notification = mock(Notification::class.java)
- whenever(notificationEntry.sbn).thenReturn(sbn)
- whenever(sbn.packageName).thenReturn(packageName)
- whenever(sbn.notification).thenReturn(notification)
- whenever(notification.isFgsOrUij).thenReturn(isFgs)
-
+ val notification = Notification()
+ if (isFgs) {
+ notification.flags = notification.flags or FLAG_FOREGROUND_SERVICE
+ }
+ if (overrideVisibility) {
+ // Developer has marked notification as public
+ notification.visibility = VISIBILITY_PUBLIC
+ }
+ val notificationEntry =
+ NotificationEntryBuilder().setNotification(notification).setPkg(packageName).build()
+ val channel = NotificationChannel("1", "1", IMPORTANCE_HIGH)
+ if (overrideChannelVisibility) {
+ // User doesn't allow private notifications at the channel level
+ channel.lockscreenVisibility = VISIBILITY_PRIVATE
+ }
+ notificationEntry.setRanking(
+ RankingBuilder(notificationEntry.ranking)
+ .setChannel(channel)
+ .setVisibilityOverride(VISIBILITY_NO_OVERRIDE)
+ .build()
+ )
return notificationEntry
}
private fun setupFgsNotificationEntry(packageName: String): NotificationEntry {
- return setupNotificationEntry(packageName, /* isFgs= */ true)
+ return setupNotificationEntry(packageName, isFgs = true)
+ }
+
+ private fun setupPublicNotificationEntry(packageName: String): NotificationEntry {
+ return setupNotificationEntry(packageName, overrideVisibility = true)
+ }
+
+ private fun setupPublicNotificationEntryWithUserOverriddenChannel(
+ packageName: String
+ ): NotificationEntry {
+ return setupNotificationEntry(
+ packageName,
+ overrideVisibility = true,
+ overrideChannelVisibility = true
+ )
}
companion object {