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

Commit 508818fc authored by Allen Su's avatar Allen Su Committed by Android (Google) Code Review
Browse files

Merge "Text Wrapping automation"

parents 85d7605b f7042908
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.graphics.Paint;
import android.graphics.text.LineBreakConfig;
import android.graphics.text.LineBreaker;
import android.os.Build;
import android.os.SystemProperties;
import android.text.style.LeadingMarginSpan;
import android.text.style.LeadingMarginSpan.LeadingMarginSpan2;
import android.text.style.LineHeightSpan;
@@ -32,6 +33,7 @@ import android.text.style.TabStopSpan;
import android.util.Log;
import android.util.Pools.SynchronizedPool;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;

@@ -73,6 +75,13 @@ public class StaticLayout extends Layout {
     * default values.
     */
    public final static class Builder {
        // The content length threshold to enable LINE_BREAK_WORD_STYLE_PHRASE.
        private static final int DEFAULT_LINECOUNT_THRESHOLD_FOR_PHRASE = 3;

        // The property of content length threshold to enable LINE_BREAK_WORD_STYLE_PHRASE.
        private static final String PROPERTY_LINECOUNT_THRESHOLD_FOR_PHRASE =
                "android.phrase.linecount.threshold";

        private Builder() {}

        /**
@@ -431,11 +440,55 @@ public class StaticLayout extends Layout {
         */
        @NonNull
        public StaticLayout build() {
            reviseLineBreakConfig();
            StaticLayout result = new StaticLayout(this);
            Builder.recycle(this);
            return result;
        }

        private void reviseLineBreakConfig() {
            boolean autoPhraseBreaking = mLineBreakConfig.getAutoPhraseBreaking();
            int wordStyle = mLineBreakConfig.getLineBreakWordStyle();
            if (autoPhraseBreaking) {
                if (wordStyle != LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE) {
                    if (shouldEnablePhraseBreaking()) {
                        mLineBreakConfig = LineBreakConfig.getLineBreakConfig(
                                mLineBreakConfig.getLineBreakStyle(),
                                LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
                                mLineBreakConfig.getAutoPhraseBreaking());
                    }
                }
            }
        }

        private boolean shouldEnablePhraseBreaking() {
            if (TextUtils.isEmpty(mText) || mWidth <= 0) {
                return false;
            }
            int lineLimit = SystemProperties.getInt(
                    PROPERTY_LINECOUNT_THRESHOLD_FOR_PHRASE,
                    DEFAULT_LINECOUNT_THRESHOLD_FOR_PHRASE);
            double desiredWidth = (double) Layout.getDesiredWidth(mText, mStart,
                    mEnd, mPaint, mTextDir);
            int lineCount = (int) Math.ceil(desiredWidth / mWidth);
            if (lineCount > 0 && lineCount <= lineLimit) {
                return true;
            }
            return false;
        }

        /**
         * Get the line break word style.
         *
         * @return The current line break word style.
         *
         * @hide
         */
        @VisibleForTesting
        public int getLineBreakWordStyle() {
            return mLineBreakConfig.getLineBreakWordStyle();
        }

        private CharSequence mText;
        private int mStart;
        private int mEnd;
+5 −0
Original line number Diff line number Diff line
@@ -74,6 +74,9 @@ public class FeatureFlagUtils {
    public static final String SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE =
            "settings_hide_second_layer_page_navigate_up_button_in_two_pane";

    /** @hide */
    public static final String SETTINGS_AUTO_TEXT_WRAPPING = "settings_auto_text_wrapping";

    private static final Map<String, String> DEFAULT_FLAGS;

    static {
@@ -100,6 +103,7 @@ public class FeatureFlagUtils {
        DEFAULT_FLAGS.put(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS, "true");
        DEFAULT_FLAGS.put(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME, "false");
        DEFAULT_FLAGS.put(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE, "true");
        DEFAULT_FLAGS.put(SETTINGS_AUTO_TEXT_WRAPPING, "false");
    }

    private static final Set<String> PERSISTENT_FLAGS;
@@ -110,6 +114,7 @@ public class FeatureFlagUtils {
        PERSISTENT_FLAGS.add(SETTINGS_ENABLE_MONITOR_PHANTOM_PROCS);
        PERSISTENT_FLAGS.add(SETTINGS_APP_ALLOW_DARK_THEME_ACTIVATION_AT_BEDTIME);
        PERSISTENT_FLAGS.add(SETTINGS_HIDE_SECOND_LAYER_PAGE_NAVIGATE_UP_BUTTON_IN_TWO_PANE);
        PERSISTENT_FLAGS.add(SETTINGS_AUTO_TEXT_WRAPPING);
    }

    /**
+33 −6
Original line number Diff line number Diff line
@@ -144,6 +144,7 @@ import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FeatureFlagUtils;
import android.util.IntArray;
import android.util.Log;
import android.util.SparseIntArray;
@@ -791,6 +792,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
    private int mLineBreakStyle = DEFAULT_LINE_BREAK_STYLE;
    private int mLineBreakWordStyle = DEFAULT_LINE_BREAK_WORD_STYLE;
    // The auto option for LINE_BREAK_WORD_STYLE_PHRASE may not be applied in recycled view due to
    // one-way flag flipping. This is a tentative limitation during experiment and will not have the
    // issue once this is finalized to LINE_BREAK_WORD_STYLE_PHRASE_AUTO option.
    private boolean mUserSpeficiedLineBreakwordStyle = false;
    // This is used to reflect the current user preference for changing font weight and making text
    // more bold.
    private int mFontWeightAdjustment;
@@ -1462,6 +1468,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    break;
                case com.android.internal.R.styleable.TextView_lineBreakWordStyle:
                    if (a.hasValue(attr)) {
                        mUserSpeficiedLineBreakwordStyle = true;
                    }
                    mLineBreakWordStyle = a.getInt(attr,
                            LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE);
                    break;
@@ -4209,6 +4218,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    break;
                case com.android.internal.R.styleable.TextAppearance_lineBreakWordStyle:
                    attributes.mHasLineBreakWordStyle = true;
                    mUserSpeficiedLineBreakwordStyle = true;
                    attributes.mLineBreakWordStyle =
                            appearance.getInt(attr, attributes.mLineBreakWordStyle);
                    break;
@@ -4910,6 +4920,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * @param lineBreakWordStyle the line break word style for the tet
     */
    public void setLineBreakWordStyle(@LineBreakConfig.LineBreakWordStyle int lineBreakWordStyle) {
        mUserSpeficiedLineBreakwordStyle = true;
        if (mLineBreakWordStyle != lineBreakWordStyle) {
            mLineBreakWordStyle = lineBreakWordStyle;
            if (mLayout != null) {
@@ -4945,8 +4956,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     * @see PrecomputedText
     */
    public @NonNull PrecomputedText.Params getTextMetricsParams() {
        final boolean autoPhraseBreaking =
                !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
                        FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
        return new PrecomputedText.Params(new TextPaint(mTextPaint),
                LineBreakConfig.getLineBreakConfig(mLineBreakStyle, mLineBreakWordStyle),
                LineBreakConfig.getLineBreakConfig(mLineBreakStyle, mLineBreakWordStyle,
                        autoPhraseBreaking),
                getTextDirectionHeuristic(),
                mBreakStrategy, mHyphenationFrequency);
    }
@@ -4966,6 +4981,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        LineBreakConfig lineBreakConfig = params.getLineBreakConfig();
        mLineBreakStyle = lineBreakConfig.getLineBreakStyle();
        mLineBreakWordStyle = lineBreakConfig.getLineBreakWordStyle();
        mUserSpeficiedLineBreakwordStyle = true;
        if (mLayout != null) {
            nullLayouts();
            requestLayout();
@@ -6502,10 +6518,13 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            if (mTextDir == null) {
                mTextDir = getTextDirectionHeuristic();
            }
            final boolean autoPhraseBreaking =
                    !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
                            FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
            final @PrecomputedText.Params.CheckResultUsableResult int checkResult =
                    precomputed.getParams().checkResultUsable(getPaint(), mTextDir, mBreakStrategy,
                            mHyphenationFrequency, LineBreakConfig.getLineBreakConfig(
                                    mLineBreakStyle, mLineBreakWordStyle));
                                    mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
            switch (checkResult) {
                case PrecomputedText.Params.UNUSABLE:
                    throw new IllegalArgumentException(
@@ -9391,6 +9410,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            }
            // TODO: code duplication with makeSingleLayout()
            if (mHintLayout == null) {
                final boolean autoPhraseBreaking =
                        !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
                                FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
                StaticLayout.Builder builder = StaticLayout.Builder.obtain(mHint, 0,
                        mHint.length(), mTextPaint, hintWidth)
                        .setAlignment(alignment)
@@ -9403,7 +9425,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                        .setJustificationMode(mJustificationMode)
                        .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
                        .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                                mLineBreakStyle, mLineBreakWordStyle));
                                mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
                if (shouldEllipsize) {
                    builder.setEllipsize(mEllipsize)
                            .setEllipsizedWidth(ellipsisWidth);
@@ -9507,6 +9529,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
            }
        }
        if (result == null) {
            final boolean autoPhraseBreaking =
                    !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
                            FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
            StaticLayout.Builder builder = StaticLayout.Builder.obtain(mTransformed,
                    0, mTransformed.length(), mTextPaint, wantWidth)
                    .setAlignment(alignment)
@@ -9519,7 +9544,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                    .setJustificationMode(mJustificationMode)
                    .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
                    .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                            mLineBreakStyle, mLineBreakWordStyle));
                            mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
            if (shouldEllipsize) {
                builder.setEllipsize(effectiveEllipsize)
                        .setEllipsizedWidth(ellipsisWidth);
@@ -9877,7 +9902,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
        final StaticLayout.Builder layoutBuilder = StaticLayout.Builder.obtain(
                text, 0, text.length(),  mTempTextPaint, Math.round(availableSpace.right));
        final boolean autoPhraseBreaking =
                !mUserSpeficiedLineBreakwordStyle && FeatureFlagUtils.isEnabled(mContext,
                        FeatureFlagUtils.SETTINGS_AUTO_TEXT_WRAPPING);
        layoutBuilder.setAlignment(getLayoutAlignment())
                .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
                .setIncludePad(getIncludeFontPadding())
@@ -9888,7 +9915,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE)
                .setTextDirection(getTextDirectionHeuristic())
                .setLineBreakConfig(LineBreakConfig.getLineBreakConfig(
                        mLineBreakStyle, mLineBreakWordStyle));
                        mLineBreakStyle, mLineBreakWordStyle, autoPhraseBreaking));
        final StaticLayout layout = layoutBuilder.build();
+21 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import static org.junit.Assert.assertTrue;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.FontMetricsInt;
import android.graphics.text.LineBreakConfig;
import android.os.LocaleList;
import android.platform.test.annotations.Presubmit;
import android.text.Layout.Alignment;
@@ -925,4 +926,24 @@ public class StaticLayoutTest {
        assertEquals(0, layout.getHeight(true));
        assertEquals(2, layout.getLineCount());
    }

    @Test
    public void testBuilder_autoPhraseBreaking() {
        {
            // setAutoPhraseBreaking true
            LineBreakConfig lineBreakConfig = new LineBreakConfig.Builder()
                    .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_STYLE_NONE)
                    .setLineBreakWordStyle(LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE)
                    .setAutoPhraseBreaking(true)
                    .build();
            final String text = "これが正解。";
            // Obtain.
            StaticLayout.Builder builder = StaticLayout.Builder.obtain(text, 0,
                    text.length(), mDefaultPaint, DEFAULT_OUTER_WIDTH);
            builder.setLineBreakConfig(lineBreakConfig);
            builder.build();
            assertEquals(LineBreakConfig.LINE_BREAK_WORD_STYLE_PHRASE,
                    builder.getLineBreakWordStyle());
        }
    }
}
+49 −3
Original line number Diff line number Diff line
@@ -89,6 +89,11 @@ public final class LineBreakConfig {
        private @LineBreakWordStyle int mLineBreakWordStyle =
                LineBreakConfig.LINE_BREAK_WORD_STYLE_NONE;

        // Whether or not enabling phrase breaking automatically.
        // TODO(b/226012260): Remove this and add LINE_BREAK_WORD_STYLE_PHRASE_AUTO after
        // the experiment.
        private boolean mAutoPhraseBreaking = false;

        /**
         * Builder constructor with line break parameters.
         */
@@ -117,13 +122,23 @@ public final class LineBreakConfig {
            return this;
        }

        /**
         * Enable or disable the automation of {@link LINE_BREAK_WORD_STYLE_PHRASE}.
         *
         * @hide
         */
        public @NonNull Builder setAutoPhraseBreaking(boolean autoPhraseBreaking) {
            mAutoPhraseBreaking = autoPhraseBreaking;
            return this;
        }

        /**
         * Build the {@link LineBreakConfig}
         *
         * @return the LineBreakConfig instance.
         */
        public @NonNull LineBreakConfig build() {
            return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle);
            return new LineBreakConfig(mLineBreakStyle, mLineBreakWordStyle, mAutoPhraseBreaking);
        }
    }

@@ -143,6 +158,23 @@ public final class LineBreakConfig {
                .build();
    }

    /**
     * Create the LineBreakConfig instance.
     *
     * @param lineBreakStyle the line break style for text wrapping.
     * @param lineBreakWordStyle the line break word style for text wrapping.
     * @return the {@link LineBreakConfig} instance.     *
     * @hide
     */
    public static @NonNull LineBreakConfig getLineBreakConfig(@LineBreakStyle int lineBreakStyle,
            @LineBreakWordStyle int lineBreakWordStyle, boolean autoPhraseBreaking) {
        LineBreakConfig.Builder builder = new LineBreakConfig.Builder();
        return builder.setLineBreakStyle(lineBreakStyle)
                .setLineBreakWordStyle(lineBreakWordStyle)
                .setAutoPhraseBreaking(autoPhraseBreaking)
                .build();
    }

    /** @hide */
    public static final LineBreakConfig NONE =
            new Builder().setLineBreakStyle(LINE_BREAK_STYLE_NONE)
@@ -150,15 +182,17 @@ public final class LineBreakConfig {

    private final @LineBreakStyle int mLineBreakStyle;
    private final @LineBreakWordStyle int mLineBreakWordStyle;
    private final boolean mAutoPhraseBreaking;

    /**
     * Constructor with the line break parameters.
     * Use the {@link LineBreakConfig.Builder} to create the LineBreakConfig instance.
     */
    private LineBreakConfig(@LineBreakStyle int lineBreakStyle,
            @LineBreakWordStyle int lineBreakWordStyle) {
            @LineBreakWordStyle int lineBreakWordStyle, boolean autoPhraseBreaking) {
        mLineBreakStyle = lineBreakStyle;
        mLineBreakWordStyle = lineBreakWordStyle;
        mAutoPhraseBreaking = autoPhraseBreaking;
    }

    /**
@@ -179,6 +213,17 @@ public final class LineBreakConfig {
        return mLineBreakWordStyle;
    }

    /**
     * Used to identify if the automation of {@link LINE_BREAK_WORD_STYLE_PHRASE} is enabled.
     *
     * @return The result that records whether or not the automation of
     * {@link LINE_BREAK_WORD_STYLE_PHRASE} is enabled.
     * @hide
     */
    public boolean getAutoPhraseBreaking() {
        return mAutoPhraseBreaking;
    }

    @Override
    public boolean equals(Object o) {
        if (o == null) return false;
@@ -186,7 +231,8 @@ public final class LineBreakConfig {
        if (!(o instanceof LineBreakConfig)) return false;
        LineBreakConfig that = (LineBreakConfig) o;
        return (mLineBreakStyle == that.mLineBreakStyle)
                && (mLineBreakWordStyle == that.mLineBreakWordStyle);
                && (mLineBreakWordStyle == that.mLineBreakWordStyle)
                && (mAutoPhraseBreaking == that.mAutoPhraseBreaking);
    }

    @Override