Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d4797ad4 authored by Matt Casey's avatar Matt Casey
Browse files

Allow dev tools to suppress clipboard overlay.

Overlay can be suppressed with the extra com.android.systemui.SUPPRESS_CLIPBOARD_OVERLAY
That extra is *only* honored in two cases:
1. We are running in the emulator
2. The source package is com.android.shell

Test: atest ClipboardListenerTest
Bug: 222604628
Change-Id: I826eb0bc9b418de783b62b5ed7ab197aef35f84a
parent dd2c72a6
Loading
Loading
Loading
Loading
+39 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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);
    }
}
+30 −0
Original line number Diff line number Diff line
@@ -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;
@@ -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;
@@ -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));
    }
}