diff options
| author | 2024-02-09 21:12:31 +0000 | |
|---|---|---|
| committer | 2024-02-09 21:12:31 +0000 | |
| commit | acd54ab873142ac3cf7b88c2f702866dd28571bb (patch) | |
| tree | 7454bdc8854d0bf73f887f20128bcc6cdeeffe48 | |
| parent | c695aa4be887a02e915283b8645e8a276e2c7937 (diff) | |
| parent | 69e54bfd23c61768bebbfd0ac2f325883e5ff947 (diff) | |
Merge changes Ic5f78244,Ie84e6441 into main
* changes:
Move global settings lookup off main thread
Use dev option to disable notification protections
5 files changed, 137 insertions, 6 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 d4c180df7442..2b0a92c6ecd7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerImpl.java @@ -16,11 +16,14 @@ package com.android.systemui.statusbar.policy; +import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS; + import static com.android.server.notification.Flags.screenshareNotificationHiding; import android.annotation.MainThread; import android.app.IActivityManager; import android.content.Context; +import android.database.ExecutorContentObserver; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; import android.os.Handler; @@ -37,6 +40,7 @@ import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.util.Assert; import com.android.systemui.util.ListenerSet; +import com.android.systemui.util.settings.GlobalSettings; import java.util.concurrent.Executor; @@ -50,6 +54,7 @@ public class SensitiveNotificationProtectionControllerImpl private final ArraySet<String> mExemptPackages = new ArraySet<>(); private final ListenerSet<Runnable> mListeners = new ListenerSet<>(); private volatile MediaProjectionInfo mProjection; + boolean mDisableScreenShareProtections = false; @VisibleForTesting final MediaProjectionManager.Callback mMediaProjectionCallback = @@ -58,6 +63,12 @@ public class SensitiveNotificationProtectionControllerImpl public void onStart(MediaProjectionInfo info) { Trace.beginSection("SNPC.onProjectionStart"); try { + if (mDisableScreenShareProtections) { + Log.w(LOG_TAG, + "Screen share protections disabled, ignoring projectionstart"); + return; + } + // Only enable sensitive content protection if sharing full screen // Launch cookie only set (non-null) if sharing single app/task updateProjectionStateAndNotifyListeners( @@ -81,6 +92,7 @@ public class SensitiveNotificationProtectionControllerImpl @Inject public SensitiveNotificationProtectionControllerImpl( Context context, + GlobalSettings settings, MediaProjectionManager mediaProjectionManager, IActivityManager activityManager, @Main Handler mainHandler, @@ -89,6 +101,25 @@ public class SensitiveNotificationProtectionControllerImpl return; } + ExecutorContentObserver developerOptionsObserver = new ExecutorContentObserver(bgExecutor) { + @Override + public void onChange(boolean selfChange) { + super.onChange(selfChange); + boolean disableScreenShareProtections = settings.getInt( + DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, + 0) != 0; + mainHandler.post(() -> { + mDisableScreenShareProtections = disableScreenShareProtections; + }); + } + }; + settings.registerContentObserver( + DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, + developerOptionsObserver); + + // Get current setting value + bgExecutor.execute(() -> developerOptionsObserver.onChange(true)); + bgExecutor.execute(() -> { ArraySet<String> exemptPackages = new ArraySet<>(); // Exempt SystemUI diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt index 98be163bdf34..759235655eca 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/SensitiveNotificationProtectionControllerFlagDisabledTest.kt @@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest import com.android.server.notification.Flags import com.android.systemui.SysuiTestCase import com.android.systemui.util.concurrency.FakeExecutor +import com.android.systemui.util.settings.FakeGlobalSettings import com.android.systemui.util.time.FakeSystemClock import org.junit.Before import org.junit.Test @@ -49,6 +50,7 @@ class SensitiveNotificationProtectionControllerFlagDisabledTest : SysuiTestCase( controller = SensitiveNotificationProtectionControllerImpl( mContext, + FakeGlobalSettings(), mediaProjectionManager, activityManager, handler, 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 a1aff48ae1b7..1dac642836c6 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 @@ -22,6 +22,7 @@ import android.app.Notification 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 @@ -33,6 +34,7 @@ import com.android.systemui.util.concurrency.FakeExecutor import com.android.systemui.util.concurrency.mockExecutorHandler import com.android.systemui.util.mockito.whenever import com.android.systemui.util.mockito.withArgCaptor +import com.android.systemui.util.settings.FakeGlobalSettings import com.android.systemui.util.time.FakeSystemClock import org.junit.Assert.assertFalse import org.junit.Assert.assertNotNull @@ -61,6 +63,8 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { @Mock private lateinit var listener2: Runnable @Mock private lateinit var listener3: Runnable + private lateinit var executor: FakeExecutor + private lateinit var globalSettings: FakeGlobalSettings private lateinit var mediaProjectionCallback: MediaProjectionManager.Callback private lateinit var controller: SensitiveNotificationProtectionControllerImpl @@ -73,18 +77,19 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { whenever(activityManager.bugreportWhitelistedPackages) .thenReturn(listOf(BUGREPORT_PACKAGE_NAME)) - val executor = FakeExecutor(FakeSystemClock()) - + executor = FakeExecutor(FakeSystemClock()) + globalSettings = FakeGlobalSettings() controller = SensitiveNotificationProtectionControllerImpl( mContext, + globalSettings, mediaProjectionManager, activityManager, mockExecutorHandler(executor), executor ) - // Process exemption processing + // Process pending work (getting global setting and list of exemptions) executor.runAllReady() // Obtain useful MediaProjectionCallback @@ -229,6 +234,14 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { } @Test + fun isSensitiveStateActive_projectionActive_disabledViaDevOption_false() { + setDisabledViaDeveloperOption() + mediaProjectionCallback.onStart(mediaProjectionInfo) + + assertFalse(controller.isSensitiveStateActive) + } + + @Test fun shouldProtectNotification_projectionInactive_false() { val notificationEntry = mock(NotificationEntry::class.java) @@ -294,6 +307,23 @@ class SensitiveNotificationProtectionControllerTest : SysuiTestCase() { assertFalse(controller.shouldProtectNotification(notificationEntry)) } + @Test + fun shouldProtectNotification_projectionActive_disabledViaDevOption_false() { + setDisabledViaDeveloperOption() + mediaProjectionCallback.onStart(mediaProjectionInfo) + + val notificationEntry = setupNotificationEntry(TEST_PROJECTION_PACKAGE_NAME) + + assertFalse(controller.shouldProtectNotification(notificationEntry)) + } + + private fun setDisabledViaDeveloperOption() { + globalSettings.putInt(DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 1) + + // Process pending work that gets current developer option global setting + executor.runAllReady() + } + private fun setShareFullScreen() { whenever(mediaProjectionInfo.packageName).thenReturn(TEST_PROJECTION_PACKAGE_NAME) whenever(mediaProjectionInfo.launchCookie).thenReturn(null) diff --git a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java index f619ca3f66a2..44d0132ef9a8 100644 --- a/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java +++ b/services/core/java/com/android/server/SensitiveContentProtectionManagerService.java @@ -16,6 +16,8 @@ package com.android.server; +import static android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS; + import static com.android.internal.util.Preconditions.checkNotNull; import android.annotation.NonNull; @@ -24,11 +26,10 @@ import android.content.ComponentName; import android.content.Context; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; -import android.os.Handler; -import android.os.Looper; import android.os.RemoteException; import android.os.Trace; import android.os.UserHandle; +import android.provider.Settings; import android.service.notification.NotificationListenerService; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; @@ -117,7 +118,7 @@ public final class SensitiveContentProtectionManagerService extends SystemServic // TODO(b/317250444): use MediaProjectionManagerService directly, reduces unnecessary // handler, delegate, and binder death recipient - mProjectionManager.addCallback(mProjectionCallback, new Handler(Looper.getMainLooper())); + mProjectionManager.addCallback(mProjectionCallback, getContext().getMainThreadHandler()); try { mNotificationListener.registerAsSystemService( @@ -148,6 +149,15 @@ public final class SensitiveContentProtectionManagerService extends SystemServic } private void onProjectionStart() { + // TODO(b/324447419): move GlobalSettings lookup to background thread + boolean disableScreenShareProtections = + Settings.Global.getInt(getContext().getContentResolver(), + DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, 0) != 0; + if (disableScreenShareProtections) { + Log.w(TAG, "Screen share protections disabled, ignoring projection start"); + return; + } + synchronized (mSensitiveContentProtectionLock) { mProjectionActive = true; updateAppsThatShouldBlockScreenCapture(); diff --git a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceTest.java index d78143381ae5..9e98105e5495 100644 --- a/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/SensitiveContentProtectionManagerServiceTest.java @@ -31,6 +31,7 @@ import static org.mockito.Mockito.when; import android.media.projection.MediaProjectionInfo; import android.media.projection.MediaProjectionManager; +import android.provider.Settings; import android.service.notification.NotificationListenerService.Ranking; import android.service.notification.NotificationListenerService.RankingMap; import android.service.notification.StatusBarNotification; @@ -391,6 +392,16 @@ public class SensitiveContentProtectionManagerServiceTest { } @Test + public void mediaProjectionOnStart_disabledViaDevOption_noBlockedPackages() { + mockDisabledViaDevelopOption(); + setupSensitiveNotification(); + + mMediaProjectionCallbackCaptor.getValue().onStart(mock(MediaProjectionInfo.class)); + + verifyZeroInteractions(mWindowManager); + } + + @Test public void nlsOnListenerConnected_projectionNotStarted_noop() { // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 // as non-sensitive @@ -484,6 +495,18 @@ public class SensitiveContentProtectionManagerServiceTest { } @Test + public void nlsOnListenerConnected_disabledViaDevOption_noBlockedPackages() { + mockDisabledViaDevelopOption(); + // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 + // as non-sensitive + setupSensitiveNotification(); + mMediaProjectionCallbackCaptor.getValue().onStart(mock(MediaProjectionInfo.class)); + mSensitiveContentProtectionManagerService.mNotificationListener.onListenerConnected(); + + verifyZeroInteractions(mWindowManager); + } + + @Test public void nlsOnNotificationRankingUpdate_projectionNotStarted_noop() { // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 // as non-sensitive @@ -599,6 +622,19 @@ public class SensitiveContentProtectionManagerServiceTest { } @Test + public void nlsOnNotificationRankingUpdate_disabledViaDevOption_noBlockedPackages() { + mockDisabledViaDevelopOption(); + // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 + // as non-sensitive + setupSensitiveNotification(); + mMediaProjectionCallbackCaptor.getValue().onStart(mock(MediaProjectionInfo.class)); + mSensitiveContentProtectionManagerService.mNotificationListener + .onNotificationRankingUpdate(mRankingMap); + + verifyZeroInteractions(mWindowManager); + } + + @Test public void nlsOnNotificationPosted_projectionNotStarted_noop() { // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 // as non-sensitive @@ -697,4 +733,26 @@ public class SensitiveContentProtectionManagerServiceTest { verifyZeroInteractions(mWindowManager); } + + @Test + public void nlsOnNotificationPosted_disabledViaDevOption_noBlockedPackages() { + mockDisabledViaDevelopOption(); + // Sets up mNotification1 & mRankingMap to be a sensitive notification, and mNotification2 + // as non-sensitive + setupSensitiveNotification(); + mMediaProjectionCallbackCaptor.getValue().onStart(mock(MediaProjectionInfo.class)); + mSensitiveContentProtectionManagerService.mNotificationListener + .onNotificationPosted(mNotification1, mRankingMap); + + verifyZeroInteractions(mWindowManager); + } + + private void mockDisabledViaDevelopOption() { + // mContext (TestableContext) uses [TestableSettingsProvider] and it will be cleared after + // the test + Settings.Global.putInt( + mContext.getContentResolver(), + Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS, + 1); + } } |