Add hyphenationFrequency attribute to TextView and StaticLayout.
This patch adds plumbing to TextView and StaticLayout to control the
frequency of automatic hyphenation used in laying out paragraphs.
Bug: 21038249
Change-Id: Ib45de190eb0a1ed738e69fd61f2b39561b11aec7
diff --git a/api/current.txt b/api/current.txt
index c307199..9ff983f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -653,6 +653,7 @@
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
+ field public static final int hyphenationFrequency = 16844024; // 0x10104f8
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
field public static final int iconTint = 16843999; // 0x10104df
@@ -32166,6 +32167,9 @@
field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
+ field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
+ field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
+ field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
}
public static final class Layout.Alignment extends java.lang.Enum {
@@ -32364,6 +32368,7 @@
method public android.text.StaticLayout.Builder setBreakStrategy(int);
method public android.text.StaticLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
method public android.text.StaticLayout.Builder setEllipsizedWidth(int);
+ method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
method public android.text.StaticLayout.Builder setIncludePad(boolean);
method public android.text.StaticLayout.Builder setIndents(int[], int[]);
method public android.text.StaticLayout.Builder setLineSpacing(float, float);
@@ -41446,6 +41451,7 @@
method public int getHighlightColor();
method public java.lang.CharSequence getHint();
method public final android.content.res.ColorStateList getHintTextColors();
+ method public int getHyphenationFrequency();
method public int getImeActionId();
method public java.lang.CharSequence getImeActionLabel();
method public int getImeOptions();
@@ -41552,6 +41558,7 @@
method public final void setHintTextColor(int);
method public final void setHintTextColor(android.content.res.ColorStateList);
method public void setHorizontallyScrolling(boolean);
+ method public void setHyphenationFrequency(int);
method public void setImeActionLabel(java.lang.CharSequence, int);
method public void setImeOptions(int);
method public void setIncludeFontPadding(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 57b4c6c..f3fc88d 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -725,6 +725,7 @@
field public static final int horizontalScrollViewStyle = 16843603; // 0x1010353
field public static final int horizontalSpacing = 16843028; // 0x1010114
field public static final int host = 16842792; // 0x1010028
+ field public static final int hyphenationFrequency = 16844024; // 0x10104f8
field public static final int icon = 16842754; // 0x1010002
field public static final int iconPreview = 16843337; // 0x1010249
field public static final int iconTint = 16843999; // 0x10104df
@@ -34388,6 +34389,9 @@
field public static final int BREAK_STRATEGY_SIMPLE = 0; // 0x0
field public static final int DIR_LEFT_TO_RIGHT = 1; // 0x1
field public static final int DIR_RIGHT_TO_LEFT = -1; // 0xffffffff
+ field public static final int HYPHENATION_FREQUENCY_FULL = 2; // 0x2
+ field public static final int HYPHENATION_FREQUENCY_NONE = 0; // 0x0
+ field public static final int HYPHENATION_FREQUENCY_NORMAL = 1; // 0x1
}
public static final class Layout.Alignment extends java.lang.Enum {
@@ -34586,6 +34590,7 @@
method public android.text.StaticLayout.Builder setBreakStrategy(int);
method public android.text.StaticLayout.Builder setEllipsize(android.text.TextUtils.TruncateAt);
method public android.text.StaticLayout.Builder setEllipsizedWidth(int);
+ method public android.text.StaticLayout.Builder setHyphenationFrequency(int);
method public android.text.StaticLayout.Builder setIncludePad(boolean);
method public android.text.StaticLayout.Builder setIndents(int[], int[]);
method public android.text.StaticLayout.Builder setLineSpacing(float, float);
@@ -43979,6 +43984,7 @@
method public int getHighlightColor();
method public java.lang.CharSequence getHint();
method public final android.content.res.ColorStateList getHintTextColors();
+ method public int getHyphenationFrequency();
method public int getImeActionId();
method public java.lang.CharSequence getImeActionLabel();
method public int getImeOptions();
@@ -44085,6 +44091,7 @@
method public final void setHintTextColor(int);
method public final void setHintTextColor(android.content.res.ColorStateList);
method public void setHorizontallyScrolling(boolean);
+ method public void setHyphenationFrequency(int);
method public void setImeActionLabel(java.lang.CharSequence, int);
method public void setImeOptions(int);
method public void setIncludeFontPadding(boolean);
diff --git a/core/java/android/text/DynamicLayout.java b/core/java/android/text/DynamicLayout.java
index fc65f63..e99a960 100644
--- a/core/java/android/text/DynamicLayout.java
+++ b/core/java/android/text/DynamicLayout.java
@@ -79,7 +79,8 @@
boolean includepad,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
this(base, display, paint, width, align, TextDirectionHeuristics.FIRSTSTRONG_LTR,
- spacingmult, spacingadd, includepad, StaticLayout.BREAK_STRATEGY_SIMPLE,
+ spacingmult, spacingadd, includepad,
+ StaticLayout.BREAK_STRATEGY_SIMPLE, StaticLayout.HYPHENATION_FREQUENCY_NONE,
ellipsize, ellipsizedWidth);
}
@@ -96,7 +97,7 @@
TextPaint paint,
int width, Alignment align, TextDirectionHeuristic textDir,
float spacingmult, float spacingadd,
- boolean includepad, int breakStrategy,
+ boolean includepad, int breakStrategy, int hyphenationFrequency,
TextUtils.TruncateAt ellipsize, int ellipsizedWidth) {
super((ellipsize == null)
? display
@@ -122,6 +123,7 @@
mIncludePad = includepad;
mBreakStrategy = breakStrategy;
+ mHyphenationFrequency = hyphenationFrequency;
/*
* This is annoying, but we can't refer to the layout until
@@ -293,7 +295,8 @@
.setLineSpacing(getSpacingAdd(), getSpacingMultiplier())
.setEllipsizedWidth(mEllipsizedWidth)
.setEllipsize(mEllipsizeAt)
- .setBreakStrategy(mBreakStrategy);
+ .setBreakStrategy(mBreakStrategy)
+ .setHyphenationFrequency(mHyphenationFrequency);
reflowed.generate(b, false, true);
int n = reflowed.getLineCount();
@@ -719,6 +722,7 @@
private int mEllipsizedWidth;
private TextUtils.TruncateAt mEllipsizeAt;
private int mBreakStrategy;
+ private int mHyphenationFrequency;
private PackedIntVector mInts;
private PackedObjectVector<Directions> mObjects;
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 60de02a..f176240 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -71,6 +71,35 @@
*/
public static final int BREAK_STRATEGY_BALANCED = 2;
+ /** @hide */
+ @IntDef({HYPHENATION_FREQUENCY_NORMAL, HYPHENATION_FREQUENCY_FULL,
+ HYPHENATION_FREQUENCY_NONE})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface HyphenationFrequency {}
+
+ /**
+ * Value for hyphenation frequency indicating no automatic hyphenation. Useful
+ * for backward compatibility, and for cases where the automatic hyphenation algorithm results
+ * in incorrect hyphenation. Mid-word breaks may still happen when a word is wider than the
+ * layout and there is otherwise no valid break. Soft hyphens are ignored and will not be used
+ * as suggestions for potential line breaks.
+ */
+ public static final int HYPHENATION_FREQUENCY_NONE = 0;
+
+ /**
+ * Value for hyphenation frequency indicating a light amount of automatic hyphenation, which
+ * is a conservative default. Useful for informal cases, such as short sentences or chat
+ * messages.
+ */
+ public static final int HYPHENATION_FREQUENCY_NORMAL = 1;
+
+ /**
+ * Value for hyphenation frequency indicating the full amount of automatic hyphenation, typical
+ * in typography. Useful for running text and where it's important to put the maximum amount of
+ * text in a screen with limited space.
+ */
+ public static final int HYPHENATION_FREQUENCY_FULL = 2;
+
private static final ParagraphStyle[] NO_PARA_SPANS =
ArrayUtils.emptyArray(ParagraphStyle.class);
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 59c7c6d..d6d046b 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -92,6 +92,7 @@
b.mEllipsize = null;
b.mMaxLines = Integer.MAX_VALUE;
b.mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
+ b.mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
b.mMeasuredText = MeasuredText.obtain();
return b;
@@ -276,6 +277,19 @@
}
/**
+ * Set hyphenation frequency, to control the amount of automatic hyphenation used. The
+ * default is {@link Layout#HYPHENATION_FREQUENCY_NONE}.
+ *
+ * @param hyphenationFrequency hyphenation frequency for the paragraph
+ * @return this builder, useful for chaining
+ * @see android.widget.TextView#setHyphenationFrequency
+ */
+ public Builder setHyphenationFrequency(@HyphenationFrequency int hyphenationFrequency) {
+ mHyphenationFrequency = hyphenationFrequency;
+ return this;
+ }
+
+ /**
* Set indents. Arguments are arrays holding an indent amount, one per line, measured in
* pixels. For lines past the last element in the array, the last element repeats.
*
@@ -302,7 +316,8 @@
* the native code is as follows.
*
* For each paragraph, do a nSetupParagraph, which sets paragraph text, line width, tab
- * stops, break strategy (and possibly other parameters in the future).
+ * stops, break strategy, and hyphenation frequency (and possibly other parameters in the
+ * future).
*
* Then, for each run within the paragraph:
* - setLocale (this must be done at least for the first run, optional afterwards)
@@ -377,6 +392,7 @@
TextUtils.TruncateAt mEllipsize;
int mMaxLines;
int mBreakStrategy;
+ int mHyphenationFrequency;
Paint.FontMetricsInt mFontMetricsInt = new Paint.FontMetricsInt();
@@ -644,7 +660,7 @@
nSetupParagraph(b.mNativePtr, chs, paraEnd - paraStart,
firstWidth, firstWidthLineCount, restWidth,
- variableTabStops, TAB_INCREMENT, b.mBreakStrategy);
+ variableTabStops, TAB_INCREMENT, b.mBreakStrategy, b.mHyphenationFrequency);
// measurement has to be done before performing line breaking
// but we don't want to recompute fontmetrics or span ranges the
@@ -1153,7 +1169,7 @@
// Set up paragraph text and settings; done as one big method to minimize jni crossings
private static native void nSetupParagraph(long nativePtr, char[] text, int length,
float firstWidth, int firstWidthLineCount, float restWidth,
- int[] variableTabStops, int defaultTabStop, int breakStrategy);
+ int[] variableTabStops, int defaultTabStop, int breakStrategy, int hyphenationFrequency);
private static native float nAddStyleRun(long nativePtr, long nativePaint,
long nativeTypeface, int start, int end, boolean isRtl);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 68c49cd..a989392 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -238,6 +238,7 @@
* @attr ref android.R.styleable#TextView_letterSpacing
* @attr ref android.R.styleable#TextView_fontFeatureSettings
* @attr ref android.R.styleable#TextView_breakStrategy
+ * @attr ref android.R.styleable#TextView_hyphenationFrequency
* @attr ref android.R.styleable#TextView_leftIndents
* @attr ref android.R.styleable#TextView_rightIndents
*/
@@ -555,6 +556,7 @@
private float mSpacingAdd = 0.0f;
private int mBreakStrategy;
+ private int mHyphenationFrequency;
private int[] mLeftIndents;
private int[] mRightIndents;
@@ -696,6 +698,7 @@
float letterSpacing = 0;
String fontFeatureSettings = null;
mBreakStrategy = Layout.BREAK_STRATEGY_SIMPLE;
+ mHyphenationFrequency = Layout.HYPHENATION_FREQUENCY_NONE;
final Resources.Theme theme = context.getTheme();
@@ -1154,6 +1157,10 @@
mBreakStrategy = a.getInt(attr, Layout.BREAK_STRATEGY_SIMPLE);
break;
+ case com.android.internal.R.styleable.TextView_hyphenationFrequency:
+ mHyphenationFrequency = a.getInt(attr, Layout.HYPHENATION_FREQUENCY_NONE);
+ break;
+
case com.android.internal.R.styleable.TextView_leftIndents:
TypedArray margins = res.obtainTypedArray(a.getResourceId(attr, View.NO_ID));
mLeftIndents = parseDimensionArray(margins);
@@ -3050,6 +3057,33 @@
}
/**
+ * Sets the hyphenation frequency. The default value for both TextView and EditText, which is set
+ * from the theme, is {@link Layout#HYPHENATION_FREQUENCY_NORMAL}.
+ *
+ * @attr ref android.R.styleable#TextView_hyphenationFrequency
+ * @see #getHyphenationFrequency()
+ */
+ public void setHyphenationFrequency(@Layout.HyphenationFrequency int hyphenationFrequency) {
+ mHyphenationFrequency = hyphenationFrequency;
+ if (mLayout != null) {
+ nullLayouts();
+ requestLayout();
+ invalidate();
+ }
+ }
+
+ /**
+ * @return the currently set hyphenation frequency.
+ *
+ * @attr ref android.R.styleable#TextView_hyphenationFrequency
+ * @see #setHyphenationFrequency(int)
+ */
+ @Layout.HyphenationFrequency
+ public int getHyphenationFrequency() {
+ return mHyphenationFrequency;
+ }
+
+ /**
* Set indents. Arguments are arrays holding an indent amount, one per line, measured in
* pixels. For lines past the last element in the array, the last element repeats.
*
@@ -6637,7 +6671,8 @@
.setTextDir(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
- .setBreakStrategy(mBreakStrategy);
+ .setBreakStrategy(mBreakStrategy)
+ .setHyphenationFrequency(mHyphenationFrequency);
if (mLeftIndents != null || mRightIndents != null) {
builder.setIndents(mLeftIndents, mRightIndents);
}
@@ -6678,7 +6713,8 @@
Layout result = null;
if (mText instanceof Spannable) {
result = new DynamicLayout(mText, mTransformed, mTextPaint, wantWidth,
- alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad, mBreakStrategy,
+ alignment, mTextDir, mSpacingMult, mSpacingAdd, mIncludePad,
+ mBreakStrategy, mHyphenationFrequency,
getKeyListener() == null ? effectiveEllipsize : null, ellipsisWidth);
} else {
if (boring == UNKNOWN_BORING) {
@@ -6726,7 +6762,8 @@
.setTextDir(mTextDir)
.setLineSpacing(mSpacingAdd, mSpacingMult)
.setIncludePad(mIncludePad)
- .setBreakStrategy(mBreakStrategy);
+ .setBreakStrategy(mBreakStrategy)
+ .setHyphenationFrequency(mHyphenationFrequency);
if (mLeftIndents != null || mRightIndents != null) {
builder.setIndents(mLeftIndents, mRightIndents);
}
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index 5e73ef2..90e4bb6 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -48,10 +48,11 @@
static jclass gLineBreaks_class;
static JLineBreaksID gLineBreaks_fieldID;
-// set text and set a number of parameters for creating a layout (width, tabstops, strategy)
+// set text and set a number of parameters for creating a layout (width, tabstops, strategy,
+// hyphenFrequency)
static void nSetupParagraph(JNIEnv* env, jclass, jlong nativePtr, jcharArray text, jint length,
jfloat firstWidth, jint firstWidthLineLimit, jfloat restWidth,
- jintArray variableTabStops, jint defaultTabStop, jint strategy) {
+ jintArray variableTabStops, jint defaultTabStop, jint strategy, jint hyphenFrequency) {
LineBreaker* b = reinterpret_cast<LineBreaker*>(nativePtr);
b->resize(length);
env->GetCharArrayRegion(text, 0, length, b->buffer());
@@ -64,6 +65,7 @@
b->setTabStops(stops.get(), stops.size(), defaultTabStop);
}
b->setStrategy(static_cast<BreakStrategy>(strategy));
+ b->setHyphenationFrequency(static_cast<HyphenationFrequency>(hyphenFrequency));
}
static void recycleCopy(JNIEnv* env, jobject recycle, jintArray recycleBreaks,
@@ -177,7 +179,7 @@
{"nFinishBuilder", "(J)V", (void*) nFinishBuilder},
{"nLoadHyphenator", "(Ljava/lang/String;)J", (void*) nLoadHyphenator},
{"nSetLocale", "(JLjava/lang/String;J)V", (void*) nSetLocale},
- {"nSetupParagraph", "(J[CIFIF[III)V", (void*) nSetupParagraph},
+ {"nSetupParagraph", "(J[CIFIF[IIII)V", (void*) nSetupParagraph},
{"nSetIndents", "(J[I)V", (void*) nSetIndents},
{"nAddStyleRun", "(JJJIIZ)F", (void*) nAddStyleRun},
{"nAddMeasuredRun", "(JII[F)V", (void*) nAddMeasuredRun},
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 0b96d22..726401c 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -4369,6 +4369,17 @@
<!-- Line breaking stratgegy balances line lengths. -->
<enum name="balanced" value="2" />
</attr>
+ <!-- Frequency of automatic hyphenation. -->
+ <attr name="hyphenationFrequency">
+ <!-- No hyphenation. -->
+ <enum name="none" value="0" />
+ <!-- Less frequent hyphenation, useful for informal use cases, such
+ as chat messages. -->
+ <enum name="normal" value="1" />
+ <!-- Standard amount of hyphenation, useful for running text and for
+ screens with limited space for text. -->
+ <enum name="full" value="2" />
+ </attr>
<!-- Array of indents, one dimension value per line, left side. -->
<attr name="leftIndents" format="reference" />
<!-- Array of indents, one dimension value per line, right side. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e403a16..b60a333 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2688,4 +2688,5 @@
<public type="attr" name="stylusButtonPressable" />
<public type="attr" name="supportsLaunchVoiceAssistFromKeyguard" />
<public type="attr" name="scrollIndicators" />
+ <public type="attr" name="hyphenationFrequency" />
</resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 3c3d286..4c02d79 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -498,6 +498,7 @@
<item name="textEditSuggestionItemLayout">?attr/textEditSuggestionItemLayout</item>
<item name="textCursorDrawable">?attr/textCursorDrawable</item>
<item name="breakStrategy">high_quality</item>
+ <item name="hyphenationFrequency">normal</item>
</style>
<style name="Widget.CheckedTextView">
@@ -529,6 +530,7 @@
<item name="textColor">?attr/editTextColor</item>
<item name="gravity">center_vertical</item>
<item name="breakStrategy">simple</item>
+ <item name="hyphenationFrequency">normal</item>
</style>
<style name="Widget.ExpandableListView" parent="Widget.ListView">