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

Commit 4d5c48d9 authored by Oli Lan's avatar Oli Lan
Browse files

Add ClipDescription method to determine if the clip is styled text.

This adds a new method to ClipDescription to allow callers to
determine if the associated ClipData is styled text, without
accessing the ClipData directly.

This information is used by editors such as TextView or WebView
when they show a selection toolbar, in order to determine if a
"Paste as plain text" option should be shown. Currently, ClipData
must be accessed in order to do this, so a clipboard access
occurs whenever text is selected.

Avoiding these clipboard accesses is desirable because a user-visible
message may in future be shown whenever ClipData is accessed
(see b/167676460), which may cause user confusion.

Bug: 167660455
Test: new tests added to ClipDescriptionTest in CTS
Change-Id: I48bea4d11a68b198d60016b364a3cfa0b0bf277e
parent 8ce6b9fb
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -9815,6 +9815,7 @@ package android.content {
    method public int getMimeTypeCount();
    method public long getTimestamp();
    method public boolean hasMimeType(String);
    method public boolean isStyledText();
    method public void setExtras(android.os.PersistableBundle);
    method public void writeToParcel(android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.content.ClipDescription> CREATOR;
+19 −0
Original line number Diff line number Diff line
@@ -740,6 +740,7 @@ public class ClipData implements Parcelable {
        mIcon = null;
        mItems = new ArrayList<Item>();
        mItems.add(item);
        mClipDescription.setIsStyledText(isStyledText());
    }

    /**
@@ -756,6 +757,7 @@ public class ClipData implements Parcelable {
        mIcon = null;
        mItems = new ArrayList<Item>();
        mItems.add(item);
        mClipDescription.setIsStyledText(isStyledText());
    }

    /**
@@ -914,6 +916,9 @@ public class ClipData implements Parcelable {
            throw new NullPointerException("item is null");
        }
        mItems.add(item);
        if (mItems.size() == 1) {
            mClipDescription.setIsStyledText(isStyledText());
        }
    }

    /**
@@ -1049,6 +1054,20 @@ public class ClipData implements Parcelable {
        }
    }

    private boolean isStyledText() {
        if (mItems.isEmpty()) {
            return false;
        }
        final CharSequence text = mItems.get(0).getText();
        if (text instanceof Spanned) {
            Spanned spanned = (Spanned) text;
            if (TextUtils.hasStyleSpan(spanned)) {
                return true;
            }
        }
        return false;
    }

    @Override
    public String toString() {
        StringBuilder b = new StringBuilder(128);
+23 −0
Original line number Diff line number Diff line
@@ -120,6 +120,7 @@ public class ClipDescription implements Parcelable {
    private final ArrayList<String> mMimeTypes;
    private PersistableBundle mExtras;
    private long mTimeStamp;
    private boolean mIsStyledText;

    /**
     * Create a new clip.
@@ -325,6 +326,26 @@ public class ClipDescription implements Parcelable {
        }
    }

    /**
     * Returns true if the first item of the associated {@link ClipData} contains styled text, i.e.
     * if it contains spans such as {@link android.text.style.CharacterStyle CharacterStyle}, {@link
     * android.text.style.ParagraphStyle ParagraphStyle}, or {@link
     * android.text.style.UpdateAppearance UpdateAppearance}. Returns false if it does not, or if
     * there is no associated clip data.
     */
    public boolean isStyledText() {
        return mIsStyledText;
    }

    /**
     * Sets whether the associated {@link ClipData} contains styled text in its first item. This
     * should be called when this description is associated with clip data or when the first item
     * is added to the associated clip data.
     */
    void setIsStyledText(boolean isStyledText) {
        mIsStyledText = isStyledText;
    }

    @Override
    public String toString() {
        StringBuilder b = new StringBuilder(128);
@@ -429,6 +450,7 @@ public class ClipDescription implements Parcelable {
        dest.writeStringList(mMimeTypes);
        dest.writePersistableBundle(mExtras);
        dest.writeLong(mTimeStamp);
        dest.writeBoolean(mIsStyledText);
    }

    ClipDescription(Parcel in) {
@@ -436,6 +458,7 @@ public class ClipDescription implements Parcelable {
        mMimeTypes = in.createStringArrayList();
        mExtras = in.readPersistableBundle();
        mTimeStamp = in.readLong();
        mIsStyledText = in.readBoolean();
    }

    public static final @android.annotation.NonNull Parcelable.Creator<ClipDescription> CREATOR =
+4 −10
Original line number Diff line number Diff line
@@ -12940,17 +12940,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            return false;
        }
        final ClipData clipData = getClipboardManagerForUser().getPrimaryClip();
        final ClipDescription description = clipData.getDescription();
        final ClipDescription description =
                getClipboardManagerForUser().getPrimaryClipDescription();
        final boolean isPlainType = description.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN);
        final CharSequence text = clipData.getItemAt(0).getText();
        if (isPlainType && (text instanceof Spanned)) {
            Spanned spanned = (Spanned) text;
            if (TextUtils.hasStyleSpan(spanned)) {
                return true;
            }
        }
        return description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML);
        return (isPlainType && description.isStyledText())
                || description.hasMimeType(ClipDescription.MIMETYPE_TEXT_HTML);
    }
    boolean canProcessText() {