Block clipboard UI when device is locked
In some situations (see bug for details) it's possible to enter the
clipboard even while the device is locked, and from there access the
provided intents. Users should not be able to access intents from this
state; this change adds an additional check before showing the interactive UI.
The behavior is identical to what we do when user setup is not complete
(b/251778420): we show a toast to note that content has been copied, but no interactive UI.
Interactive UI is only blocked when device is locked (i.e. requiring pin
entry/password/biometric/etc), not if the keyguard is up but trivially
dismissable.
Bug: 317048495
Flag: ACONFIG com.android.systemui.clipboard_noninteractive_on_lockscreen DEVELOPMENT
Test: atest ClipboardListenerTest; verification using steps in linked
bug as well as forcing text content to appear client-side, to verify
that even if text content is received in the ClipboardListener, no
interactive UI appears.
Change-Id: I1a48cbe64852dce3fba69915ca11dad8878f66eb
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 4ed1965..7df8f03f 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -489,3 +489,13 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "clipboard_noninteractive_on_lockscreen"
+ namespace: "systemui"
+ description: "Prevents the interactive clipboard UI from appearing when device is locked"
+ bug: "317048495"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
index e0ce3db..c7a47b1 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java
@@ -18,12 +18,14 @@
import static android.content.ClipDescription.CLASSIFICATION_COMPLETE;
+import static com.android.systemui.Flags.clipboardNoninteractiveOnLockscreen;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED;
import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN;
import static com.google.android.setupcompat.util.WizardManagerHelper.SETTINGS_SECURE_USER_SETUP_COMPLETE;
+import android.app.KeyguardManager;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
@@ -57,6 +59,7 @@
private final Provider<ClipboardOverlayController> mOverlayProvider;
private final ClipboardToast mClipboardToast;
private final ClipboardManager mClipboardManager;
+ private final KeyguardManager mKeyguardManager;
private final UiEventLogger mUiEventLogger;
private ClipboardOverlay mClipboardOverlay;
@@ -65,11 +68,13 @@
Provider<ClipboardOverlayController> clipboardOverlayControllerProvider,
ClipboardToast clipboardToast,
ClipboardManager clipboardManager,
+ KeyguardManager keyguardManager,
UiEventLogger uiEventLogger) {
mContext = context;
mOverlayProvider = clipboardOverlayControllerProvider;
mClipboardToast = clipboardToast;
mClipboardManager = clipboardManager;
+ mKeyguardManager = keyguardManager;
mUiEventLogger = uiEventLogger;
}
@@ -92,7 +97,9 @@
return;
}
- if (!isUserSetupComplete() // user should not access intents from this state
+ // user should not access intents before setup or while device is locked
+ if ((clipboardNoninteractiveOnLockscreen() && mKeyguardManager.isDeviceLocked())
+ || !isUserSetupComplete()
|| clipData == null // shouldn't happen, but just in case
|| clipData.getItemCount() == 0) {
if (shouldShowToast(clipData)) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
index 1851582..c65a117 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java
@@ -27,16 +27,20 @@
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
+import android.app.KeyguardManager;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.ClipboardManager;
import android.os.PersistableBundle;
+import android.platform.test.annotations.DisableFlags;
+import android.platform.test.annotations.EnableFlags;
import android.provider.Settings;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
import com.android.internal.logging.UiEventLogger;
+import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
@@ -59,6 +63,8 @@
@Mock
private ClipboardManager mClipboardManager;
@Mock
+ private KeyguardManager mKeyguardManager;
+ @Mock
private ClipboardOverlayController mOverlayController;
@Mock
private ClipboardToast mClipboardToast;
@@ -96,7 +102,7 @@
when(mClipboardManager.getPrimaryClipSource()).thenReturn(mSampleSource);
mClipboardListener = new ClipboardListener(getContext(), mOverlayControllerProvider,
- mClipboardToast, mClipboardManager, mUiEventLogger);
+ mClipboardToast, mClipboardManager, mKeyguardManager, mUiEventLogger);
}
@@ -191,6 +197,34 @@
}
@Test
+ @EnableFlags(Flags.FLAG_CLIPBOARD_NONINTERACTIVE_ON_LOCKSCREEN)
+ public void test_deviceLocked_showsToast() {
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(true);
+
+ mClipboardListener.start();
+ mClipboardListener.onPrimaryClipChanged();
+
+ verify(mUiEventLogger, times(1)).log(
+ ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource);
+ verify(mClipboardToast, times(1)).showCopiedToast();
+ verifyZeroInteractions(mOverlayControllerProvider);
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_CLIPBOARD_NONINTERACTIVE_ON_LOCKSCREEN)
+ public void test_deviceLocked_legacyBehavior_showsInteractiveUI() {
+ when(mKeyguardManager.isDeviceLocked()).thenReturn(true);
+
+ mClipboardListener.start();
+ mClipboardListener.onPrimaryClipChanged();
+
+ verify(mUiEventLogger, times(1)).log(
+ ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED, 0, mSampleSource);
+ verify(mOverlayController).setClipData(mSampleClipData, mSampleSource);
+ verifyZeroInteractions(mClipboardToast);
+ }
+
+ @Test
public void test_nullClipData_showsNothing() {
when(mClipboardManager.getPrimaryClip()).thenReturn(null);