Loading packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +39 −2 Original line number Diff line number Diff line Loading @@ -20,10 +20,14 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBO import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.os.SystemProperties; import android.provider.DeviceConfig; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; Loading @@ -37,6 +41,13 @@ import javax.inject.Inject; @SysUISingleton public class ClipboardListener extends CoreStartable implements ClipboardManager.OnPrimaryClipChangedListener { private static final String TAG = "ClipboardListener"; @VisibleForTesting static final String SHELL_PACKAGE = "com.android.shell"; @VisibleForTesting static final String EXTRA_SUPPRESS_OVERLAY = "com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY"; private final DeviceConfigProxy mDeviceConfig; private final ClipboardOverlayControllerFactory mOverlayFactory; Loading Loading @@ -68,18 +79,44 @@ public class ClipboardListener extends CoreStartable if (!mClipboardManager.hasPrimaryClip()) { return; } String clipSource = mClipboardManager.getPrimaryClipSource(); ClipData clipData = mClipboardManager.getPrimaryClip(); if (shouldSuppressOverlay(clipData, clipSource, isEmulator())) { Log.i(TAG, "Clipboard overlay suppressed."); return; } if (mClipboardOverlayController == null) { mClipboardOverlayController = mOverlayFactory.create(mContext); mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource); } else { mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource); } mClipboardOverlayController.setClipData( mClipboardManager.getPrimaryClip(), clipSource); mClipboardOverlayController.setClipData(clipData, clipSource); mClipboardOverlayController.setOnSessionCompleteListener(() -> { // Session is complete, free memory until it's needed again. mClipboardOverlayController = null; }); } // The overlay is suppressed if EXTRA_SUPPRESS_OVERLAY is true and the device is an emulator or // the source package is SHELL_PACKAGE. This is meant to suppress the overlay when the emulator // or a mirrored device is syncing the clipboard. @VisibleForTesting static boolean shouldSuppressOverlay(ClipData clipData, String clipSource, boolean isEmulator) { if (!(isEmulator || SHELL_PACKAGE.equals(clipSource))) { return false; } if (clipData == null || clipData.getDescription().getExtras() == null) { return false; } return clipData.getDescription().getExtras().getBoolean(EXTRA_SUPPRESS_OVERLAY, false); } private static boolean isEmulator() { return SystemProperties.getBoolean("ro.boot.qemu", false); } } packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.systemui.clipboardoverlay; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -26,7 +28,9 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.content.ClipData; import android.content.ClipDescription; import android.content.ClipboardManager; import android.os.PersistableBundle; import android.provider.DeviceConfig; import androidx.test.filters.SmallTest; Loading Loading @@ -139,4 +143,30 @@ public class ClipboardListenerTest extends SysuiTestCase { verify(mClipboardOverlayControllerFactory, times(2)).create(any()); } @Test public void test_shouldSuppressOverlay() { // Regardless of the package or emulator, nothing should be suppressed without the flag assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, mSampleSource, false)); assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, ClipboardListener.SHELL_PACKAGE, false)); assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, mSampleSource, true)); ClipDescription desc = new ClipDescription("Test", new String[]{"text/plain"}); PersistableBundle bundle = new PersistableBundle(); bundle.putBoolean(ClipboardListener.EXTRA_SUPPRESS_OVERLAY, true); desc.setExtras(bundle); ClipData suppressableClipData = new ClipData(desc, new ClipData.Item("Test Item")); // Clip data with the suppression extra is only honored in the emulator or with the shell // package. assertFalse(ClipboardListener.shouldSuppressOverlay(suppressableClipData, mSampleSource, false)); assertTrue(ClipboardListener.shouldSuppressOverlay(suppressableClipData, mSampleSource, true)); assertTrue(ClipboardListener.shouldSuppressOverlay(suppressableClipData, ClipboardListener.SHELL_PACKAGE, false)); } } Loading
packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardListener.java +39 −2 Original line number Diff line number Diff line Loading @@ -20,10 +20,14 @@ import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBO import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_ENTERED; import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_UPDATED; import android.content.ClipData; import android.content.ClipboardManager; import android.content.Context; import android.os.SystemProperties; import android.provider.DeviceConfig; import android.util.Log; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.UiEventLogger; import com.android.systemui.CoreStartable; import com.android.systemui.dagger.SysUISingleton; Loading @@ -37,6 +41,13 @@ import javax.inject.Inject; @SysUISingleton public class ClipboardListener extends CoreStartable implements ClipboardManager.OnPrimaryClipChangedListener { private static final String TAG = "ClipboardListener"; @VisibleForTesting static final String SHELL_PACKAGE = "com.android.shell"; @VisibleForTesting static final String EXTRA_SUPPRESS_OVERLAY = "com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY"; private final DeviceConfigProxy mDeviceConfig; private final ClipboardOverlayControllerFactory mOverlayFactory; Loading Loading @@ -68,18 +79,44 @@ public class ClipboardListener extends CoreStartable if (!mClipboardManager.hasPrimaryClip()) { return; } String clipSource = mClipboardManager.getPrimaryClipSource(); ClipData clipData = mClipboardManager.getPrimaryClip(); if (shouldSuppressOverlay(clipData, clipSource, isEmulator())) { Log.i(TAG, "Clipboard overlay suppressed."); return; } if (mClipboardOverlayController == null) { mClipboardOverlayController = mOverlayFactory.create(mContext); mUiEventLogger.log(CLIPBOARD_OVERLAY_ENTERED, 0, clipSource); } else { mUiEventLogger.log(CLIPBOARD_OVERLAY_UPDATED, 0, clipSource); } mClipboardOverlayController.setClipData( mClipboardManager.getPrimaryClip(), clipSource); mClipboardOverlayController.setClipData(clipData, clipSource); mClipboardOverlayController.setOnSessionCompleteListener(() -> { // Session is complete, free memory until it's needed again. mClipboardOverlayController = null; }); } // The overlay is suppressed if EXTRA_SUPPRESS_OVERLAY is true and the device is an emulator or // the source package is SHELL_PACKAGE. This is meant to suppress the overlay when the emulator // or a mirrored device is syncing the clipboard. @VisibleForTesting static boolean shouldSuppressOverlay(ClipData clipData, String clipSource, boolean isEmulator) { if (!(isEmulator || SHELL_PACKAGE.equals(clipSource))) { return false; } if (clipData == null || clipData.getDescription().getExtras() == null) { return false; } return clipData.getDescription().getExtras().getBoolean(EXTRA_SUPPRESS_OVERLAY, false); } private static boolean isEmulator() { return SystemProperties.getBoolean("ro.boot.qemu", false); } }
packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardListenerTest.java +30 −0 Original line number Diff line number Diff line Loading @@ -19,6 +19,8 @@ package com.android.systemui.clipboardoverlay; import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.CLIPBOARD_OVERLAY_ENABLED; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; Loading @@ -26,7 +28,9 @@ import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; import android.content.ClipData; import android.content.ClipDescription; import android.content.ClipboardManager; import android.os.PersistableBundle; import android.provider.DeviceConfig; import androidx.test.filters.SmallTest; Loading Loading @@ -139,4 +143,30 @@ public class ClipboardListenerTest extends SysuiTestCase { verify(mClipboardOverlayControllerFactory, times(2)).create(any()); } @Test public void test_shouldSuppressOverlay() { // Regardless of the package or emulator, nothing should be suppressed without the flag assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, mSampleSource, false)); assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, ClipboardListener.SHELL_PACKAGE, false)); assertFalse(ClipboardListener.shouldSuppressOverlay(mSampleClipData, mSampleSource, true)); ClipDescription desc = new ClipDescription("Test", new String[]{"text/plain"}); PersistableBundle bundle = new PersistableBundle(); bundle.putBoolean(ClipboardListener.EXTRA_SUPPRESS_OVERLAY, true); desc.setExtras(bundle); ClipData suppressableClipData = new ClipData(desc, new ClipData.Item("Test Item")); // Clip data with the suppression extra is only honored in the emulator or with the shell // package. assertFalse(ClipboardListener.shouldSuppressOverlay(suppressableClipData, mSampleSource, false)); assertTrue(ClipboardListener.shouldSuppressOverlay(suppressableClipData, mSampleSource, true)); assertTrue(ClipboardListener.shouldSuppressOverlay(suppressableClipData, ClipboardListener.SHELL_PACKAGE, false)); } }