Loading core/java/android/text/StaticLayout.java +53 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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() {} /** Loading Loading @@ -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; Loading core/java/android/util/FeatureFlagUtils.java +5 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; Loading @@ -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); } /** Loading core/java/android/widget/TextView.java +33 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); } Loading @@ -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(); Loading Loading @@ -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( Loading Loading @@ -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) Loading @@ -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); Loading Loading @@ -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) Loading @@ -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); Loading Loading @@ -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()) Loading @@ -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(); Loading core/tests/coretests/src/android/text/StaticLayoutTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } } } graphics/java/android/graphics/text/LineBreakConfig.java +49 −3 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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); } } Loading @@ -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) Loading @@ -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; } /** Loading @@ -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; Loading @@ -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 Loading Loading
core/java/android/text/StaticLayout.java +53 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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() {} /** Loading Loading @@ -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; Loading
core/java/android/util/FeatureFlagUtils.java +5 −0 Original line number Diff line number Diff line Loading @@ -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 { Loading @@ -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; Loading @@ -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); } /** Loading
core/java/android/widget/TextView.java +33 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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); } Loading @@ -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(); Loading Loading @@ -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( Loading Loading @@ -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) Loading @@ -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); Loading Loading @@ -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) Loading @@ -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); Loading Loading @@ -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()) Loading @@ -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(); Loading
core/tests/coretests/src/android/text/StaticLayoutTest.java +21 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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()); } } }
graphics/java/android/graphics/text/LineBreakConfig.java +49 −3 Original line number Diff line number Diff line Loading @@ -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. */ Loading Loading @@ -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); } } Loading @@ -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) Loading @@ -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; } /** Loading @@ -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; Loading @@ -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 Loading