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

Commit f77fce7b authored by Seigo Nonaka's avatar Seigo Nonaka Committed by Android (Google) Code Review
Browse files

Merge "Fix minimum line height for TextView use case" into main

parents a41fbddf fe2cff11
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -1804,6 +1804,7 @@ package android {
    field public static final int useEmbeddedDex = 16844190; // 0x101059e
    field public static final int useIntrinsicSizeAsMinimum = 16843536; // 0x1010310
    field public static final int useLevel = 16843167; // 0x101019f
    field @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public static final int useLocalePreferredLineHeightForMinimum;
    field public static final int userVisible = 16843409; // 0x1010291
    field public static final int usesCleartextTraffic = 16844012; // 0x10104ec
    field public static final int usesPermissionFlags = 16844356; // 0x1010644
@@ -60535,6 +60536,7 @@ package android.widget {
    method public boolean isFallbackLineSpacing();
    method public final boolean isHorizontallyScrollable();
    method public boolean isInputMethodTarget();
    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public boolean isLocalePreferredLineHeightForMinimumUsed();
    method public boolean isSingleLine();
    method public boolean isSuggestionsEnabled();
    method public boolean isTextSelectable();
@@ -60617,6 +60619,7 @@ package android.widget {
    method public final void setLinkTextColor(@ColorInt int);
    method public final void setLinkTextColor(android.content.res.ColorStateList);
    method public final void setLinksClickable(boolean);
    method @FlaggedApi("com.android.text.flags.fix_line_height_for_locale") public void setLocalePreferredLineHeightForMinimumUsed(boolean);
    method public void setMarqueeRepeatLimit(int);
    method public void setMaxEms(int);
    method public void setMaxHeight(int);
+1 −3
Original line number Diff line number Diff line
@@ -585,9 +585,7 @@ public class BoringLayout extends Layout implements TextUtils.EllipsizeCallback
        }

        if (ClientFlags.fixLineHeightForLocale()) {
            if (minimumFontMetrics == null) {
                paint.getFontMetricsIntForLocale(fm);
            } else {
            if (minimumFontMetrics != null) {
                fm.set(minimumFontMetrics);
                // Because the font metrics is provided by public APIs, adjust the top/bottom with
                // ascent/descent: top must be smaller than ascent, bottom must be larger than
+12 −20
Original line number Diff line number Diff line
@@ -767,22 +767,14 @@ public class StaticLayout extends Layout {
        }

        int defaultTop;
        int defaultAscent;
        int defaultDescent;
        final int defaultAscent;
        final int defaultDescent;
        int defaultBottom;
        if (ClientFlags.fixLineHeightForLocale()) {
            if (b.mMinimumFontMetrics != null) {
        if (ClientFlags.fixLineHeightForLocale() && b.mMinimumFontMetrics != null) {
            defaultTop = (int) Math.floor(b.mMinimumFontMetrics.top);
            defaultAscent = Math.round(b.mMinimumFontMetrics.ascent);
            defaultDescent = Math.round(b.mMinimumFontMetrics.descent);
            defaultBottom = (int) Math.ceil(b.mMinimumFontMetrics.bottom);
            } else {
                paint.getFontMetricsIntForLocale(fm);
                defaultTop = fm.top;
                defaultAscent = fm.ascent;
                defaultDescent = fm.descent;
                defaultBottom = fm.bottom;
            }

            // Because the font metrics is provided by public APIs, adjust the top/bottom with
            // ascent/descent: top must be smaller than ascent, bottom must be larger than descent.
@@ -1043,10 +1035,10 @@ public class StaticLayout extends Layout {

                    if (endPos < spanEnd) {
                        // preserve metrics for current span
                        fmTop = fm.top;
                        fmBottom = fm.bottom;
                        fmAscent = fm.ascent;
                        fmDescent = fm.descent;
                        fmTop = Math.min(defaultTop, fm.top);
                        fmBottom = Math.max(defaultBottom, fm.bottom);
                        fmAscent = Math.min(defaultAscent, fm.ascent);
                        fmDescent = Math.max(defaultDescent, fm.descent);
                    } else {
                        fmTop = fmBottom = fmAscent = fmDescent = 0;
                    }
@@ -1069,7 +1061,7 @@ public class StaticLayout extends Layout {
                && mLineCount < mMaximumVisibleLineCount) {
            final MeasuredParagraph measuredPara =
                    MeasuredParagraph.buildForBidi(source, bufEnd, bufEnd, textDir, null);
            if (ClientFlags.fixLineHeightForLocale()) {
            if (defaultAscent != 0 && defaultDescent != 0) {
                fm.top = defaultTop;
                fm.ascent = defaultAscent;
                fm.descent = defaultDescent;
+42 −7
Original line number Diff line number Diff line
@@ -16,9 +16,13 @@

package android.widget;

import android.app.compat.CompatChanges;
import android.compat.annotation.ChangeId;
import android.compat.annotation.EnabledSince;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.os.Build;
import android.text.Editable;
import android.text.Selection;
import android.text.Spannable;
@@ -29,6 +33,8 @@ import android.text.style.SpanUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;

import com.android.internal.R;

/*
 * This is supposed to be a *very* thin veneer over TextView.
 * Do not make any changes here that do anything that a TextView
@@ -85,6 +91,11 @@ public class EditText extends TextView {
    private static final int ID_ITALIC = android.R.id.italic;
    private static final int ID_UNDERLINE = android.R.id.underline;

    /** @hide */
    @ChangeId
    @EnabledSince(targetSdkVersion = Build.VERSION_CODES.VANILLA_ICE_CREAM)
    public static final long LINE_HEIGHT_FOR_LOCALE = 303326708L;

    public EditText(Context context) {
        this(context, null);
    }
@@ -104,6 +115,7 @@ public class EditText extends TextView {
        final TypedArray a = theme.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.EditText, defStyleAttr, defStyleRes);

        try {
            final int n = a.getIndexCount();
            for (int i = 0; i < n; ++i) {
                int attr = a.getIndex(i);
@@ -113,6 +125,29 @@ public class EditText extends TextView {
                        break;
                }
            }
        } finally {
            a.recycle();
        }

        boolean hasUseLocalePreferredLineHeightForMinimumInt = false;
        boolean useLocalePreferredLineHeightForMinimumInt = false;
        TypedArray tvArray = theme.obtainStyledAttributes(attrs,
                com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
        try {
            hasUseLocalePreferredLineHeightForMinimumInt =
                    tvArray.hasValue(R.styleable.TextView_useLocalePreferredLineHeightForMinimum);
            if (hasUseLocalePreferredLineHeightForMinimumInt) {
                useLocalePreferredLineHeightForMinimumInt = tvArray.getBoolean(
                        R.styleable.TextView_useLocalePreferredLineHeightForMinimum, false);
            }
        } finally {
            tvArray.recycle();
        }
        if (!hasUseLocalePreferredLineHeightForMinimumInt) {
            useLocalePreferredLineHeightForMinimumInt =
                    CompatChanges.isChangeEnabled(LINE_HEIGHT_FOR_LOCALE);
        }
        setLocalePreferredLineHeightForMinimumUsed(useLocalePreferredLineHeightForMinimumInt);
    }

    @Override
+73 −12
Original line number Diff line number Diff line
@@ -867,6 +867,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    private boolean mUseBoundsForWidth;
    @Nullable private Paint.FontMetrics mMinimumFontMetrics;
    @Nullable private Paint.FontMetrics mLocalePreferredFontMetrics;
    private boolean mUseLocalePreferredLineHeightForMinimum;
    @ViewDebug.ExportedProperty(category = "text")
    @UnsupportedAppUsage
@@ -1617,6 +1619,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                case com.android.internal.R.styleable.TextView_useBoundsForWidth:
                    mUseBoundsForWidth = a.getBoolean(attr, false);
                    hasUseBoundForWidthValue = true;
                    break;
                case com.android.internal.R.styleable
                        .TextView_useLocalePreferredLineHeightForMinimum:
                    mUseLocalePreferredLineHeightForMinimum = a.getBoolean(attr, false);
                    break;
            }
        }
@@ -4991,6 +4998,41 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return mMinimumFontMetrics;
    }
    /**
     * Returns true if the locale preferred line height is used for the minimum line height.
     *
     * @return true if using locale preferred line height for the minimum line height. Otherwise
     *         false.
     *
     * @see #setLocalePreferredLineHeightForMinimumUsed(boolean)
     * @see #setMinimumFontMetrics(Paint.FontMetrics)
     * @see #getMinimumFontMetrics()
     */
    @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
    public boolean isLocalePreferredLineHeightForMinimumUsed() {
        return mUseLocalePreferredLineHeightForMinimum;
    }
    /**
     * Set true if the locale preferred line height is used for the minimum line height.
     *
     * By setting this flag to true is equivalenet to call
     * {@link #setMinimumFontMetrics(Paint.FontMetrics)} with the one obtained by
     * {@link Paint#getFontMetricsForLocale(Paint.FontMetrics)}.
     *
     * If custom minimum line height was specified by
     * {@link #setMinimumFontMetrics(Paint.FontMetrics)}, this flag will be ignored.
     *
     * @param flag true for using locale preferred line height for the minimum line height.
     * @see #isLocalePreferredLineHeightForMinimumUsed()
     * @see #setMinimumFontMetrics(Paint.FontMetrics)
     * @see #getMinimumFontMetrics()
     */
    @FlaggedApi(FLAG_FIX_LINE_HEIGHT_FOR_LOCALE)
    public void setLocalePreferredLineHeightForMinimumUsed(boolean flag) {
        mUseLocalePreferredLineHeightForMinimum = flag;
    }
    /**
     * @return whether fallback line spacing is enabled, {@code true} by default
     *
@@ -10728,6 +10770,21 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        return alignment;
    }
    private Paint.FontMetrics getResolvedMinimumFontMetrics() {
        if (mMinimumFontMetrics != null) {
            return mMinimumFontMetrics;
        }
        if (!mUseLocalePreferredLineHeightForMinimum) {
            return null;
        }
        if (mLocalePreferredFontMetrics == null) {
            mLocalePreferredFontMetrics = new Paint.FontMetrics();
        }
        mTextPaint.getFontMetricsForLocale(mLocalePreferredFontMetrics);
        return mLocalePreferredFontMetrics;
    }
    /**
     * The width passed in is now the desired layout width,
     * not the full view width with padding.
@@ -10792,7 +10849,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            if (hintBoring == UNKNOWN_BORING) {
                hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
                        isFallbackLineSpacingForBoringLayout(),
                        mMinimumFontMetrics, mHintBoring);
                        getResolvedMinimumFontMetrics(), mHintBoring);
                if (hintBoring != null) {
                    mHintBoring = hintBoring;
                }
@@ -10842,7 +10900,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                        .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                                mLineBreakStyle, mLineBreakWordStyle))
                        .setUseBoundsForWidth(mUseBoundsForWidth)
                        .setMinimumFontMetrics(mMinimumFontMetrics);
                        .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
                if (shouldEllipsize) {
                    builder.setEllipsize(mEllipsize)
                            .setEllipsizedWidth(ellipsisWidth);
@@ -10907,12 +10966,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    .setUseBoundsForWidth(mUseBoundsForWidth)
                    .setEllipsize(getKeyListener() == null ? effectiveEllipsize : null)
                    .setEllipsizedWidth(ellipsisWidth)
                    .setMinimumFontMetrics(mMinimumFontMetrics);
                    .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
            result = builder.build();
        } else {
            if (boring == UNKNOWN_BORING) {
                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
                        isFallbackLineSpacingForBoringLayout(), mMinimumFontMetrics, mBoring);
                        isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
                        mBoring);
                if (boring != null) {
                    mBoring = boring;
                }
@@ -10926,7 +10986,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                wantWidth, alignment, mSpacingMult, mSpacingAdd,
                                boring, mIncludePad, null, wantWidth,
                                isFallbackLineSpacingForBoringLayout(),
                                mUseBoundsForWidth, mMinimumFontMetrics);
                                mUseBoundsForWidth, getResolvedMinimumFontMetrics());
                    } else {
                        result = new BoringLayout(
                                mTransformed,
@@ -10941,7 +11001,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                null,
                                boring,
                                mUseBoundsForWidth,
                                mMinimumFontMetrics);
                                getResolvedMinimumFontMetrics());
                    }
                    if (useSaved) {
@@ -10953,7 +11013,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                wantWidth, alignment, mSpacingMult, mSpacingAdd,
                                boring, mIncludePad, effectiveEllipsize,
                                ellipsisWidth, isFallbackLineSpacingForBoringLayout(),
                                mUseBoundsForWidth, mMinimumFontMetrics);
                                mUseBoundsForWidth, getResolvedMinimumFontMetrics());
                    } else {
                        result = new BoringLayout(
                                mTransformed,
@@ -10968,7 +11028,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                                effectiveEllipsize,
                                boring,
                                mUseBoundsForWidth,
                                mMinimumFontMetrics);
                                getResolvedMinimumFontMetrics());
                    }
                }
            }
@@ -10988,7 +11048,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                            mLineBreakStyle, mLineBreakWordStyle))
                    .setUseBoundsForWidth(mUseBoundsForWidth)
                    .setMinimumFontMetrics(mMinimumFontMetrics);
                    .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
            if (shouldEllipsize) {
                builder.setEllipsize(effectiveEllipsize)
                        .setEllipsizedWidth(ellipsisWidth);
@@ -11116,7 +11176,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            if (des < 0) {
                boring = BoringLayout.isBoring(mTransformed, mTextPaint, mTextDir,
                        isFallbackLineSpacingForBoringLayout(), mMinimumFontMetrics, mBoring);
                        isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
                        mBoring);
                if (boring != null) {
                    mBoring = boring;
                }
@@ -11156,7 +11217,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                if (hintDes < 0) {
                    hintBoring = BoringLayout.isBoring(mHint, mTextPaint, mTextDir,
                            isFallbackLineSpacingForBoringLayout(), mMinimumFontMetrics,
                            isFallbackLineSpacingForBoringLayout(), getResolvedMinimumFontMetrics(),
                            mHintBoring);
                    if (hintBoring != null) {
                        mHintBoring = hintBoring;
@@ -11370,7 +11431,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                        mLineBreakStyle, mLineBreakWordStyle))
                .setUseBoundsForWidth(mUseBoundsForWidth)
                .setMinimumFontMetrics(mMinimumFontMetrics);
                .setMinimumFontMetrics(getResolvedMinimumFontMetrics());
        final StaticLayout layout = layoutBuilder.build();
Loading