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

Commit e94a75a1 authored by Abodunrinwa Toki's avatar Abodunrinwa Toki
Browse files

Implement text baseline attributes for TextView.

Bug: 71816223
Test: bit CtsWidgetTestCases:android.widget.cts.TextViewTest
Change-Id: I0a9121ded88f954c5180ea35df0e666801cd8978
parent 02c0e986
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -602,6 +602,7 @@ package android {
    field public static final int fingerprintAuthDrawable = 16844008; // 0x10104e8
    field public static final int finishOnCloseSystemDialogs = 16843431; // 0x10102a7
    field public static final int finishOnTaskLaunch = 16842772; // 0x1010014
    field public static final int firstBaselineToTopHeight = 16844157; // 0x101057d
    field public static final int firstDayOfWeek = 16843581; // 0x101033d
    field public static final int fitsSystemWindows = 16842973; // 0x10100dd
    field public static final int flipInterval = 16843129; // 0x1010179
@@ -798,6 +799,7 @@ package android {
    field public static final int largeHeap = 16843610; // 0x101035a
    field public static final int largeScreens = 16843398; // 0x1010286
    field public static final int largestWidthLimitDp = 16843622; // 0x1010366
    field public static final int lastBaselineToBottomHeight = 16844158; // 0x101057e
    field public static final int launchMode = 16842781; // 0x101001d
    field public static final int launchTaskBehindSourceAnimation = 16843922; // 0x1010492
    field public static final int launchTaskBehindTargetAnimation = 16843921; // 0x1010491
@@ -855,6 +857,7 @@ package android {
    field public static final int left = 16843181; // 0x10101ad
    field public static final int letterSpacing = 16843958; // 0x10104b6
    field public static final int level = 16844032; // 0x1010500
    field public static final int lineHeight = 16844159; // 0x101057f
    field public static final int lineSpacingExtra = 16843287; // 0x1010217
    field public static final int lineSpacingMultiplier = 16843288; // 0x1010218
    field public static final int lines = 16843092; // 0x1010154
@@ -52504,6 +52507,7 @@ package android.widget {
    method public int getExtendedPaddingBottom();
    method public int getExtendedPaddingTop();
    method public android.text.InputFilter[] getFilters();
    method public int getFirstBaselineToTopHeight();
    method public java.lang.String getFontFeatureSettings();
    method public java.lang.String getFontVariationSettings();
    method public boolean getFreezesText();
@@ -52521,6 +52525,7 @@ package android.widget {
    method public int getInputType();
    method public int getJustificationMode();
    method public final android.text.method.KeyListener getKeyListener();
    method public int getLastBaselineToBottomHeight();
    method public final android.text.Layout getLayout();
    method public float getLetterSpacing();
    method public int getLineBounds(int, android.graphics.Rect);
@@ -52617,6 +52622,7 @@ package android.widget {
    method public void setExtractedText(android.view.inputmethod.ExtractedText);
    method public void setFallbackLineSpacing(boolean);
    method public void setFilters(android.text.InputFilter[]);
    method public void setFirstBaselineToTopHeight(int);
    method public void setFontFeatureSettings(java.lang.String);
    method public boolean setFontVariationSettings(java.lang.String);
    method protected boolean setFrame(int, int, int, int);
@@ -52638,7 +52644,9 @@ package android.widget {
    method public void setInputType(int);
    method public void setJustificationMode(int);
    method public void setKeyListener(android.text.method.KeyListener);
    method public void setLastBaselineToBottomHeight(int);
    method public void setLetterSpacing(float);
    method public void setLineHeight(int);
    method public void setLineSpacing(float, float);
    method public void setLines(int);
    method public final void setLinkTextColor(int);
+153 −0
Original line number Diff line number Diff line
@@ -27,8 +27,10 @@ import android.annotation.ColorInt;
import android.annotation.DrawableRes;
import android.annotation.FloatRange;
import android.annotation.IntDef;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Px;
import android.annotation.Size;
import android.annotation.StringRes;
import android.annotation.StyleRes;
@@ -52,6 +54,7 @@ import android.graphics.BaseCanvas;
import android.graphics.Canvas;
import android.graphics.Insets;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Rect;
@@ -924,6 +927,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        int inputType = EditorInfo.TYPE_NULL;
        a = theme.obtainStyledAttributes(
                    attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
        int firstBaselineToTopHeight = -1;
        int lastBaselineToBottomHeight = -1;
        int lineHeight = -1;

        readTextAppearance(context, a, attributes, true /* styleArray */);

@@ -1249,6 +1255,18 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                case com.android.internal.R.styleable.TextView_justificationMode:
                    mJustificationMode = a.getInt(attr, Layout.JUSTIFICATION_MODE_NONE);
                    break;

                case com.android.internal.R.styleable.TextView_firstBaselineToTopHeight:
                    firstBaselineToTopHeight = a.getDimensionPixelSize(attr, -1);
                    break;

                case com.android.internal.R.styleable.TextView_lastBaselineToBottomHeight:
                    lastBaselineToBottomHeight = a.getDimensionPixelSize(attr, -1);
                    break;

                case com.android.internal.R.styleable.TextView_lineHeight:
                    lineHeight = a.getDimensionPixelSize(attr, -1);
                    break;
            }
        }

@@ -1563,6 +1581,16 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        } else {
            mAutoSizeTextType = AUTO_SIZE_TEXT_TYPE_NONE;
        }

        if (firstBaselineToTopHeight >= 0) {
            setFirstBaselineToTopHeight(firstBaselineToTopHeight);
        }
        if (lastBaselineToBottomHeight >= 0) {
            setLastBaselineToBottomHeight(lastBaselineToBottomHeight);
        }
        if (lineHeight >= 0) {
            setLineHeight(lineHeight);
        }
    }

    /**
@@ -3165,6 +3193,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        }
    }

    /**
     * @inheritDoc
     *
     * @see #setFirstBaselineToTopHeight(int)
     * @see #setLastBaselineToBottomHeight(int)
     */
    @Override
    public void setPadding(int left, int top, int right, int bottom) {
        if (left != mPaddingLeft
@@ -3179,6 +3213,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        invalidate();
    }

    /**
     * @inheritDoc
     *
     * @see #setFirstBaselineToTopHeight(int)
     * @see #setLastBaselineToBottomHeight(int)
     */
    @Override
    public void setPaddingRelative(int start, int top, int end, int bottom) {
        if (start != getPaddingStart()
@@ -3193,6 +3233,97 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        invalidate();
    }

    /**
     * Updates the top padding of the TextView so that {@code firstBaselineToTopHeight} is
     * equal to the distance between the firt text baseline and the top of this TextView.
     * <strong>Note</strong> that if {@code FontMetrics.top} or {@code FontMetrics.ascent} was
     * already greater than {@code firstBaselineToTopHeight}, the top padding is not updated.
     *
     * @param firstBaselineToTopHeight distance between first baseline to top of the container
     *      in pixels
     *
     * @see #getFirstBaselineToTopHeight()
     * @see #setPadding(int, int, int, int)
     * @see #setPaddingRelative(int, int, int, int)
     *
     * @attr ref android.R.styleable#TextView_firstBaselineToTopHeight
     */
    public void setFirstBaselineToTopHeight(@Px @IntRange(from = 0) int firstBaselineToTopHeight) {
        Preconditions.checkArgumentNonnegative(firstBaselineToTopHeight);

        final FontMetricsInt fontMetrics = getPaint().getFontMetricsInt();
        final int fontMetricsTop;
        if (getIncludeFontPadding()) {
            fontMetricsTop = fontMetrics.top;
        } else {
            fontMetricsTop = fontMetrics.ascent;
        }

        // TODO: Decide if we want to ignore density ratio (i.e. when the user changes font size
        // in settings). At the moment, we don't.

        if (firstBaselineToTopHeight > Math.abs(fontMetricsTop)) {
            final int paddingTop = firstBaselineToTopHeight - (-fontMetricsTop);
            setPadding(getPaddingLeft(), paddingTop, getPaddingRight(), getPaddingBottom());
        }
    }

    /**
     * Updates the bottom padding of the TextView so that {@code lastBaselineToBottomHeight} is
     * equal to the distance between the last text baseline and the bottom of this TextView.
     * <strong>Note</strong> that if {@code FontMetrics.bottom} or {@code FontMetrics.descent} was
     * already greater than {@code lastBaselineToBottomHeight}, the bottom padding is not updated.
     *
     * @param lastBaselineToBottomHeight distance between last baseline to bottom of the container
     *      in pixels
     *
     * @see #getLastBaselineToBottomHeight()
     * @see #setPadding(int, int, int, int)
     * @see #setPaddingRelative(int, int, int, int)
     *
     * @attr ref android.R.styleable#TextView_lastBaselineToBottomHeight
     */
    public void setLastBaselineToBottomHeight(
            @Px @IntRange(from = 0) int lastBaselineToBottomHeight) {
        Preconditions.checkArgumentNonnegative(lastBaselineToBottomHeight);

        final FontMetricsInt fontMetrics = getPaint().getFontMetricsInt();
        final int fontMetricsBottom;
        if (getIncludeFontPadding()) {
            fontMetricsBottom = fontMetrics.bottom;
        } else {
            fontMetricsBottom = fontMetrics.descent;
        }

        // TODO: Decide if we want to ignore density ratio (i.e. when the user changes font size
        // in settings). At the moment, we don't.

        if (lastBaselineToBottomHeight > Math.abs(fontMetricsBottom)) {
            final int paddingBottom = lastBaselineToBottomHeight - fontMetricsBottom;
            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), paddingBottom);
        }
    }

    /**
     * Returns the distance between the first text baseline and the top of this TextView.
     *
     * @see #setFirstBaselineToTopHeight(int)
     * @attr ref android.R.styleable#TextView_firstBaselineToTopHeight
     */
    public int getFirstBaselineToTopHeight() {
        return getPaddingTop() - getPaint().getFontMetricsInt().top;
    }

    /**
     * Returns the distance between the last text baseline and the bottom of this TextView.
     *
     * @see #setLastBaselineToBottomHeight(int)
     * @attr ref android.R.styleable#TextView_lastBaselineToBottomHeight
     */
    public int getLastBaselineToBottomHeight() {
        return getPaddingBottom() + getPaint().getFontMetricsInt().bottom;
    }

    /**
     * Gets the autolink mask of the text.  See {@link
     * android.text.util.Linkify#ALL Linkify.ALL} and peers for
@@ -4973,6 +5104,28 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return mSpacingAdd;
    }

    /**
     * Sets an explicit line height for this TextView. This is equivalent to the vertical distance
     * between subsequent baselines in the TextView.
     *
     * @param lineHeight the line height in pixels
     *
     * @see #setLineSpacing(float, float)
     * @see #getLineSpacing()
     *
     * @attr ref android.R.styleable#TextView_lineHeight
     */
    public void setLineHeight(@Px @IntRange(from = 0) int lineHeight) {
        Preconditions.checkArgumentNonnegative(lineHeight);

        final int fontHeight = getPaint().getFontMetricsInt(null);
        // Make sure we don't setLineSpacing if it's not needed to avoid unnecessary redraw.
        if (lineHeight != fontHeight) {
            // Set lineSpacingExtra by the difference of lineSpacing with lineHeight
            setLineSpacing(lineHeight - fontHeight, 1f);
        }
    }

    /**
     * Convenience method to append the specified text to the TextView's
     * display buffer, upgrading it to {@link android.widget.TextView.BufferType#EDITABLE}
+9 −0
Original line number Diff line number Diff line
@@ -4739,6 +4739,15 @@
        <!-- Extra spacing between lines of text, as a multiplier. The value will not be applied
             for the last line of text.-->
        <attr name="lineSpacingMultiplier" format="float" />
        <!-- Explicit height between lines of text. If set, this will override the values set
             for lineSpacingExtra and lineSpacingMultiplier. -->
        <attr name="lineHeight" format="dimension" />
        <!-- Distance from the top of the TextView to the first text baseline. If set, this
             overrides the value set for paddingTop. -->
        <attr name="firstBaselineToTopHeight" format="dimension" />
        <!-- Distance from the bottom of the TextView to the last text baseline. If set, this
             overrides the value set for paddingBottom. -->
        <attr name="lastBaselineToBottomHeight" format="dimension" />
        <!-- The number of times to repeat the marquee animation. Only applied if the
             TextView has marquee enabled. -->
        <attr name="marqueeRepeatLimit" format="integer">
+3 −0
Original line number Diff line number Diff line
@@ -2862,6 +2862,9 @@
      <public name="appComponentFactory" />
      <public name="fallbackLineSpacing" />
      <public name="accessibilityPaneTitle" />
      <public name="firstBaselineToTopHeight" />
      <public name="lastBaselineToBottomHeight" />
      <public name="lineHeight" />
    </public-group>

    <public-group type="style" first-id="0x010302e0">