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

Commit 143000b2 authored by Kevin Chang's avatar Kevin Chang Committed by Android (Google) Code Review
Browse files

Merge "Create new API for ImageSpan"

parents 95870ec6 78840ec0
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -47136,7 +47136,9 @@ package android.text.style {
  public abstract class ReplacementSpan extends android.text.style.MetricAffectingSpan {
    ctor public ReplacementSpan();
    method public abstract void draw(@NonNull android.graphics.Canvas, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, float, int, int, int, @NonNull android.graphics.Paint);
    method @Nullable public CharSequence getContentDescription();
    method public abstract int getSize(@NonNull android.graphics.Paint, CharSequence, @IntRange(from=0) int, @IntRange(from=0) int, @Nullable android.graphics.Paint.FontMetricsInt);
    method public void setContentDescription(@Nullable CharSequence);
    method public void updateDrawState(android.text.TextPaint);
    method public void updateMeasureState(android.text.TextPaint);
  }
+9 −2
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.os.Parcelable;
import android.sysprop.DisplayProperties;
import android.text.style.AbsoluteSizeSpan;
import android.text.style.AccessibilityClickableSpan;
import android.text.style.AccessibilityReplacementSpan;
import android.text.style.AccessibilityURLSpan;
import android.text.style.AlignmentSpan;
import android.text.style.BackgroundColorSpan;
@@ -735,6 +736,8 @@ public class TextUtils {
    /** @hide */
    public static final int LINE_HEIGHT_SPAN = 28;
    /** @hide */
    public static final int ACCESSIBILITY_REPLACEMENT_SPAN = 29;
    /** @hide */
    public static final int LAST_SPAN = LINE_HEIGHT_SPAN;

    /**
@@ -934,6 +937,10 @@ public class TextUtils {
                    readSpan(p, sp, new LineHeightSpan.Standard(p));
                    break;

                case ACCESSIBILITY_REPLACEMENT_SPAN:
                    readSpan(p, sp, new AccessibilityReplacementSpan(p));
                    break;

                default:
                    throw new RuntimeException("bogus span encoding " + kind);
                }
+100 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.text.style;

import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.ParcelableSpan;
import android.text.TextUtils;

/**
 * This class serves as a parcelable placeholder for the ReplacementSpans.
 *
 * This span contains content description of original span to let Accessibility service to do the
 * substitution for it.
 *
 * @hide
 */
public class AccessibilityReplacementSpan extends ReplacementSpan
        implements ParcelableSpan {
    // The content description of the span this one replaces
    private CharSequence mContentDescription;

    /**
     * @param contentDescription The content description of the span this one replaces
     */
    public AccessibilityReplacementSpan(CharSequence contentDescription) {
        this.setContentDescription(contentDescription);
        mContentDescription = contentDescription;
    }

    public AccessibilityReplacementSpan(Parcel p) {
        mContentDescription = p.readCharSequence();
    }

    @Override
    public int getSpanTypeId() {
        return getSpanTypeIdInternal();
    }

    @Override
    public int getSpanTypeIdInternal() {
        return TextUtils.ACCESSIBILITY_REPLACEMENT_SPAN;
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        writeToParcelInternal(dest, flags);
    }

    @Override
    public void writeToParcelInternal(Parcel dest, int flags) {
        dest.writeCharSequence(mContentDescription);
    }

    @Override
    public int getSize(Paint paint, CharSequence text, int start, int end,
            Paint.FontMetricsInt fm) {
        return 0;
    }

    @Override
    public void draw(Canvas canvas, CharSequence text, int start, int end, float x, int top, int y,
            int bottom, Paint paint) {
    }

    public static final @android.annotation.NonNull
    Parcelable.Creator<AccessibilityReplacementSpan> CREATOR =
            new Parcelable.Creator<AccessibilityReplacementSpan>() {
        @Override
        public AccessibilityReplacementSpan createFromParcel(Parcel parcel) {
            return new AccessibilityReplacementSpan(parcel);
        }

        @Override
        public AccessibilityReplacementSpan[] newArray(int size) {
            return new AccessibilityReplacementSpan[size];
        }
    };
}
+23 −0
Original line number Diff line number Diff line
@@ -25,6 +25,8 @@ import android.text.TextPaint;

public abstract class ReplacementSpan extends MetricAffectingSpan {

    private CharSequence mContentDescription = null;

    /**
     * Returns the width of the span. Extending classes can set the height of the span by updating
     * attributes of {@link android.graphics.Paint.FontMetricsInt}. If the span covers the whole
@@ -60,6 +62,27 @@ public abstract class ReplacementSpan extends MetricAffectingSpan {
                              @IntRange(from = 0) int start, @IntRange(from = 0) int end, float x,
                              int top, int y, int bottom, @NonNull Paint paint);

    /**
     * Gets a brief description of this ImageSpan for use in accessibility support.
     *
     * @return The content description.
     */
    @Nullable
    public CharSequence getContentDescription() {
        return mContentDescription;
    }

    /**
     * Sets the specific content description into ImageSpan.
     * ReplacementSpans are shared with accessibility services,
     * but only the content description is available from them.
     *
     * @param contentDescription content description. The default value is null.
     */
    public void setContentDescription(@Nullable CharSequence contentDescription) {
        mContentDescription = contentDescription;
    }

    /**
     * This method does nothing, since ReplacementSpans are measured
     * explicitly instead of affecting Paint properties.
+76 −25
Original line number Diff line number Diff line
@@ -39,8 +39,10 @@ import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextUtils;
import android.text.style.AccessibilityClickableSpan;
import android.text.style.AccessibilityReplacementSpan;
import android.text.style.AccessibilityURLSpan;
import android.text.style.ClickableSpan;
import android.text.style.ReplacementSpan;
import android.text.style.URLSpan;
import android.util.ArrayMap;
import android.util.ArraySet;
@@ -2641,14 +2643,32 @@ public class AccessibilityNodeInfo implements Parcelable {
    public void setText(CharSequence text) {
        enforceNotSealed();
        mOriginalText = text;
        // Replace any ClickableSpans in mText with placeholders
        if (text instanceof Spanned) {
            ClickableSpan[] spans =
            CharSequence tmpText = text;
            tmpText = replaceClickableSpan(tmpText);
            tmpText = replaceReplacementSpan(tmpText);
            mText = tmpText;
            return;
        }
        mText = (text == null) ? null : text.subSequence(0, text.length());
    }

    /**
     * Replaces any ClickableSpans in mText with placeholders.
     *
     * @param text The text.
     *
     * @return The spannable with ClickableSpan replacement.
     */
    private CharSequence replaceClickableSpan(CharSequence text) {
        ClickableSpan[] clickableSpans =
                ((Spanned) text).getSpans(0, text.length(), ClickableSpan.class);
            if (spans.length > 0) {
        Spannable spannable = new SpannableStringBuilder(text);
                for (int i = 0; i < spans.length; i++) {
                    ClickableSpan span = spans[i];
        if (clickableSpans.length == 0) {
            return text;
        }
        for (int i = 0; i < clickableSpans.length; i++) {
            ClickableSpan span = clickableSpans[i];
            if ((span instanceof AccessibilityClickableSpan)
                    || (span instanceof AccessibilityURLSpan)) {
                // We've already done enough
@@ -2664,11 +2684,42 @@ public class AccessibilityNodeInfo implements Parcelable {
            spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
                    spanToReplaceFlags);
        }
                mText = spannable;
                return;
        return spannable;
    }

    /**
     * Replace any ImageSpans in mText with its content description.
     *
     * @param text The text.
     *
     * @return The spannable with ReplacementSpan replacement.
     */
    private CharSequence replaceReplacementSpan(CharSequence text) {
        ReplacementSpan[] replacementSpans =
                ((Spanned) text).getSpans(0, text.length(), ReplacementSpan.class);
        SpannableStringBuilder spannable = new SpannableStringBuilder(text);
        if (replacementSpans.length == 0) {
            return text;
        }
        mText = (text == null) ? null : text.subSequence(0, text.length());
        for (int i = 0; i < replacementSpans.length; i++) {
            ReplacementSpan span = replacementSpans[i];
            CharSequence replacementText = span.getContentDescription();
            if (span instanceof AccessibilityReplacementSpan) {
                // We've already done enough
                break;
            }
            if (replacementText == null) {
                continue;
            }
            int spanToReplaceStart = spannable.getSpanStart(span);
            int spanToReplaceEnd = spannable.getSpanEnd(span);
            int spanToReplaceFlags = spannable.getSpanFlags(span);
            spannable.removeSpan(span);
            ReplacementSpan replacementSpan = new AccessibilityReplacementSpan(replacementText);
            spannable.setSpan(replacementSpan, spanToReplaceStart, spanToReplaceEnd,
                    spanToReplaceFlags);
        }
        return spannable;
    }

    /**