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

Commit dff51595 authored by Matt Casey's avatar Matt Casey Committed by Automerger Merge Worker
Browse files

Merge changes I4c1e118c,Id66f2971 into tm-qpr-dev am: d6819393 am: 75e4894e

parents ca4f170c 75e4894e
Loading
Loading
Loading
Loading
+3 −2
Original line number Diff line number Diff line
@@ -97,8 +97,9 @@ public class ClipboardListener implements
            return;
        }

        if (!isUserSetupComplete()) {
            // just show a toast, user should not access intents from this state
        if (!isUserSetupComplete() // user should not access intents from this state
                || clipData == null // shouldn't happen, but just in case
                || clipData.getItemCount() == 0) {
            if (shouldShowToast(clipData)) {
                mUiEventLogger.log(CLIPBOARD_TOAST_SHOWN, 0, clipSource);
                mClipboardToast.showCopiedToast();
+31 −20
Original line number Diff line number Diff line
@@ -19,19 +19,23 @@ import android.content.ClipData
import android.content.ClipDescription.EXTRA_IS_SENSITIVE
import android.content.Context
import android.graphics.Bitmap
import android.net.Uri
import android.text.TextUtils
import android.util.Log
import android.util.Size
import android.view.textclassifier.TextLinks
import com.android.systemui.R
import java.io.IOException

data class ClipboardModel(
    val clipData: ClipData?,
    val clipData: ClipData,
    val source: String,
    val type: Type = Type.OTHER,
    val item: ClipData.Item? = null,
    val isSensitive: Boolean = false,
    val isRemote: Boolean = false,
    val type: Type,
    val text: CharSequence?,
    val textLinks: TextLinks?,
    val uri: Uri?,
    val isSensitive: Boolean,
    val isRemote: Boolean,
) {
    private var _bitmap: Bitmap? = null

@@ -41,17 +45,16 @@ data class ClipboardModel(
        }
        return source == other.source &&
            type == other.type &&
            item?.text == other.item?.text &&
            item?.uri == other.item?.uri &&
            text == other.text &&
            uri == other.uri &&
            isSensitive == other.isSensitive
    }

    fun loadThumbnail(context: Context): Bitmap? {
        if (_bitmap == null && type == Type.IMAGE && item?.uri != null) {
        if (_bitmap == null && type == Type.IMAGE && uri != null) {
            try {
                val size = context.resources.getDimensionPixelSize(R.dimen.overlay_x_scale)
                _bitmap =
                    context.contentResolver.loadThumbnail(item.uri, Size(size, size * 4), null)
                _bitmap = context.contentResolver.loadThumbnail(uri, Size(size, size * 4), null)
            } catch (e: IOException) {
                Log.e(TAG, "Thumbnail loading failed!", e)
            }
@@ -66,27 +69,34 @@ data class ClipboardModel(
        fun fromClipData(
            context: Context,
            utils: ClipboardOverlayUtils,
            clipData: ClipData?,
            clipData: ClipData,
            source: String
        ): ClipboardModel {
            if (clipData == null || clipData.itemCount == 0) {
                return ClipboardModel(clipData, source)
            }
            val sensitive = clipData.description?.extras?.getBoolean(EXTRA_IS_SENSITIVE) ?: false
            val item = clipData.getItemAt(0)!!
            val type = getType(context, item)
            val remote = utils.isRemoteCopy(context, clipData, source)
            return ClipboardModel(clipData, source, type, item, sensitive, remote)
            return ClipboardModel(
                clipData,
                source,
                type,
                item.text,
                item.textLinks,
                item.uri,
                sensitive,
                remote
            )
        }

        private fun getType(context: Context, item: ClipData.Item): Type {
            return if (!TextUtils.isEmpty(item.text)) {
                Type.TEXT
            } else if (
                item.uri != null &&
                    context.contentResolver.getType(item.uri)?.startsWith("image") == true
            ) {
            } else if (item.uri != null) {
                if (context.contentResolver.getType(item.uri)?.startsWith("image") == true) {
                    Type.IMAGE
                } else {
                    Type.URI
                }
            } else {
                Type.OTHER
            }
@@ -96,6 +106,7 @@ data class ClipboardModel(
    enum class Type {
        TEXT,
        IMAGE,
        URI,
        OTHER
    }
}
+8 −7
Original line number Diff line number Diff line
@@ -309,14 +309,14 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
                if ((mFeatureFlags.isEnabled(CLIPBOARD_REMOTE_BEHAVIOR) && model.isRemote())
                        || DeviceConfig.getBoolean(
                        DeviceConfig.NAMESPACE_SYSTEMUI, CLIPBOARD_OVERLAY_SHOW_ACTIONS, false)) {
                    if (model.getItem().getTextLinks() != null) {
                    if (model.getTextLinks() != null) {
                        classifyText(model);
                    }
                }
                if (model.isSensitive()) {
                    mView.showTextPreview(mContext.getString(R.string.clipboard_asterisks), true);
                } else {
                    mView.showTextPreview(model.getItem().getText(), false);
                    mView.showTextPreview(model.getText(), false);
                }
                mView.setEditAccessibilityAction(true);
                mOnPreviewTapped = this::editText;
@@ -326,12 +326,13 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
                    mView.showImagePreview(
                            model.isSensitive() ? null : model.loadThumbnail(mContext));
                    mView.setEditAccessibilityAction(true);
                    mOnPreviewTapped = () -> editImage(model.getItem().getUri());
                    mOnPreviewTapped = () -> editImage(model.getUri());
                } else {
                    // image loading failed
                    mView.showDefaultTextPreview();
                }
                break;
            case URI:
            case OTHER:
                mView.showDefaultTextPreview();
                break;
@@ -371,8 +372,8 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv

    private void classifyText(ClipboardModel model) {
        mBgExecutor.execute(() -> {
            Optional<RemoteAction> remoteAction =
                    mClipboardUtils.getAction(model.getItem(), model.getSource());
            Optional<RemoteAction> remoteAction = mClipboardUtils.getAction(
                            model.getText(), model.getTextLinks(), model.getSource());
            if (model.equals(mClipboardModel)) {
                remoteAction.ifPresent(action -> {
                    mClipboardLogger.logUnguarded(CLIPBOARD_OVERLAY_ACTION_SHOWN);
@@ -419,10 +420,10 @@ public class ClipboardOverlayController implements ClipboardListener.ClipboardOv
            accessibilityAnnouncement = mContext.getString(R.string.clipboard_text_copied);
        } else if (clipData.getItemAt(0).getUri() != null) {
            if (tryShowEditableImage(clipData.getItemAt(0).getUri(), isSensitive)) {
                mOnShareTapped = () -> shareContent(clipData);
                mView.showShareChip();
                accessibilityAnnouncement = mContext.getString(R.string.clipboard_image_copied);
            }
            mOnShareTapped = () -> shareContent(clipData);
            mView.showShareChip();
        } else {
            mView.showDefaultTextPreview();
        }
+17 −0
Original line number Diff line number Diff line
@@ -65,6 +65,23 @@ class ClipboardOverlayUtils {
        return false;
    }

    public Optional<RemoteAction> getAction(CharSequence text, TextLinks textLinks, String source) {
        return getActions(text, textLinks).stream().filter(remoteAction -> {
            ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
            return component != null && !TextUtils.equals(source, component.getPackageName());
        }).findFirst();
    }

    private ArrayList<RemoteAction> getActions(CharSequence text, TextLinks textLinks) {
        ArrayList<RemoteAction> actions = new ArrayList<>();
        for (TextLinks.TextLink link : textLinks.getLinks()) {
            TextClassification classification = mTextClassifier.classifyText(
                    text, link.getStart(), link.getEnd(), null);
            actions.addAll(classification.getActions());
        }
        return actions;
    }

    public Optional<RemoteAction> getAction(ClipData.Item item, String source) {
        return getActions(item).stream().filter(remoteAction -> {
            ComponentName component = remoteAction.getActionIntent().getIntent().getComponent();
+29 −0
Original line number Diff line number Diff line
@@ -51,6 +51,8 @@ import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

import java.util.ArrayList;

import javax.inject.Provider;

@SmallTest
@@ -194,6 +196,33 @@ public class ClipboardListenerTest extends SysuiTestCase {
        verifyZeroInteractions(mOverlayControllerProvider);
    }

    @Test
    public void test_nullClipData_showsNothing() {
        when(mClipboardManager.getPrimaryClip()).thenReturn(null);

        mClipboardListener.start();
        mClipboardListener.onPrimaryClipChanged();

        verifyZeroInteractions(mUiEventLogger);
        verifyZeroInteractions(mClipboardToast);
        verifyZeroInteractions(mOverlayControllerProvider);
    }

    @Test
    public void test_emptyClipData_showsToast() {
        ClipDescription description = new ClipDescription("Test", new String[0]);
        ClipData noItems = new ClipData(description, new ArrayList<>());
        when(mClipboardManager.getPrimaryClip()).thenReturn(noItems);

        mClipboardListener.start();
        mClipboardListener.onPrimaryClipChanged();

        verify(mUiEventLogger, times(1)).log(
                ClipboardOverlayEvent.CLIPBOARD_TOAST_SHOWN, 0, mSampleSource);
        verify(mClipboardToast, times(1)).showCopiedToast();
        verifyZeroInteractions(mOverlayControllerProvider);
    }

    @Test
    public void test_minimizedLayoutFlagOff_usesLegacy() {
        mFeatureFlags.set(CLIPBOARD_MINIMIZED_LAYOUT, false);
Loading