Add LocaleList support to Paint and TextView.
This keeps the existing single-locale APIs working (and adds
parameter annotations to them), while adding an API for setting and
getting the whole locale list. At the moment, the implementation
ignores the actual data in the locale list except for its primary
locale.
Also add a method to LocaleList to return the system's default locale
list. (Currently a one-member list just containing the system
default locale.)
Change-Id: Icea9d164ddae51f50dd71e18b5d91c96f233b8b8
diff --git a/api/current.txt b/api/current.txt
index b296672..b60bf1f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11588,6 +11588,7 @@
method public void getTextBounds(java.lang.String, int, int, android.graphics.Rect);
method public void getTextBounds(char[], int, int, android.graphics.Rect);
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
method public float getTextScaleX();
@@ -11643,6 +11644,7 @@
method public void setSubpixelText(boolean);
method public void setTextAlign(android.graphics.Paint.Align);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSkewX(float);
@@ -34207,6 +34209,7 @@
ctor public LocaleList(java.util.Locale[]);
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getPrimary();
method public boolean isEmpty();
@@ -41719,6 +41722,7 @@
method public java.lang.CharSequence getText();
method public final android.content.res.ColorStateList getTextColors();
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public float getTextScaleX();
method public float getTextSize();
method public int getTotalPaddingBottom();
@@ -41831,6 +41835,7 @@
method public final void setTextKeepState(java.lang.CharSequence);
method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSize(int, float);
diff --git a/api/system-current.txt b/api/system-current.txt
index 7cc66cf..a0a5918 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -11925,6 +11925,7 @@
method public void getTextBounds(java.lang.String, int, int, android.graphics.Rect);
method public void getTextBounds(char[], int, int, android.graphics.Rect);
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public void getTextPath(char[], int, int, float, float, android.graphics.Path);
method public void getTextPath(java.lang.String, int, int, float, float, android.graphics.Path);
method public float getTextScaleX();
@@ -11980,6 +11981,7 @@
method public void setSubpixelText(boolean);
method public void setTextAlign(android.graphics.Paint.Align);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSkewX(float);
@@ -36501,6 +36503,7 @@
ctor public LocaleList(java.util.Locale[]);
method public static android.util.LocaleList forLanguageTags(java.lang.String);
method public java.util.Locale get(int);
+ method public static android.util.LocaleList getDefault();
method public static android.util.LocaleList getEmptyLocaleList();
method public java.util.Locale getPrimary();
method public boolean isEmpty();
@@ -44327,6 +44330,7 @@
method public java.lang.CharSequence getText();
method public final android.content.res.ColorStateList getTextColors();
method public java.util.Locale getTextLocale();
+ method public android.util.LocaleList getTextLocales();
method public float getTextScaleX();
method public float getTextSize();
method public int getTotalPaddingBottom();
@@ -44439,6 +44443,7 @@
method public final void setTextKeepState(java.lang.CharSequence);
method public final void setTextKeepState(java.lang.CharSequence, android.widget.TextView.BufferType);
method public void setTextLocale(java.util.Locale);
+ method public void setTextLocales(android.util.LocaleList);
method public void setTextScaleX(float);
method public void setTextSize(float);
method public void setTextSize(int, float);
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index afae9ac..379651e 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -16,7 +16,11 @@
package android.util;
+import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Size;
+
+import com.android.internal.annotations.GuardedBy;
import java.util.HashSet;
import java.util.Locale;
@@ -164,4 +168,22 @@
return new LocaleList(localeArray);
}
}
+
+ private final static Object sLock = new Object();
+
+ @GuardedBy("sLock")
+ private static LocaleList sDefaultLocaleList;
+
+ // TODO: fix this to return the default system locale list once we have that
+ @NonNull @Size(min=1)
+ public static LocaleList getDefault() {
+ Locale defaultLocale = Locale.getDefault();
+ synchronized (sLock) {
+ if (sDefaultLocaleList == null || sDefaultLocaleList.size() != 1
+ || !defaultLocale.equals(sDefaultLocaleList.getPrimary())) {
+ sDefaultLocaleList = new LocaleList(defaultLocale);
+ }
+ }
+ return sDefaultLocaleList;
+ }
}
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7a64377..61402ab 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -21,6 +21,7 @@
import android.annotation.DrawableRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.Size;
import android.annotation.StringRes;
import android.annotation.StyleRes;
import android.annotation.XmlRes;
@@ -103,6 +104,7 @@
import android.text.style.UpdateAppearance;
import android.text.util.Linkify;
import android.util.AttributeSet;
+import android.util.LocaleList;
import android.util.Log;
import android.util.TypedValue;
import android.view.AccessibilityIterators.TextSegmentIterator;
@@ -553,7 +555,7 @@
private final TextPaint mTextPaint;
private boolean mUserSetTextScaleX;
private Layout mLayout;
- private boolean mLocaleChanged = false;
+ private boolean mLocalesChanged = false;
@ViewDebug.ExportedProperty(category = "text")
private int mGravity = Gravity.TOP | Gravity.START;
@@ -2817,32 +2819,58 @@
}
/**
- * Get the default {@link Locale} of the text in this TextView.
- * @return the default {@link Locale} of the text in this TextView.
+ * Get the default primary {@link Locale} of the text in this TextView. This will always be
+ * the first member of {@link #getTextLocales()}.
+ * @return the default primary {@link Locale} of the text in this TextView.
*/
+ @NonNull
public Locale getTextLocale() {
return mTextPaint.getTextLocale();
}
/**
- * Set the default {@link Locale} of the text in this TextView to the given value. This value
- * is used to choose appropriate typefaces for ambiguous characters. Typically used for CJK
- * locales to disambiguate Hanzi/Kanji/Hanja characters.
+ * Get the default {@link LocaleList} of the text in this TextView.
+ * @return the default {@link LocaleList} of the text in this TextView.
+ */
+ @NonNull @Size(min=1)
+ public LocaleList getTextLocales() {
+ return mTextPaint.getTextLocales();
+ }
+
+ /**
+ * Set the default {@link LocaleList} of the text in this TextView to a one-member list
+ * containing just the given value.
*
* @param locale the {@link Locale} for drawing text, must not be null.
*
- * @see Paint#setTextLocale
+ * @see #setTextLocales
*/
- public void setTextLocale(Locale locale) {
- mLocaleChanged = true;
+ public void setTextLocale(@NonNull Locale locale) {
+ mLocalesChanged = true;
mTextPaint.setTextLocale(locale);
}
+ /**
+ * Set the default {@link LocaleList} of the text in this TextView to the given value.
+ *
+ * This value is used to choose appropriate typefaces for ambiguous characters (typically used
+ * for CJK locales to disambiguate Hanzi/Kanji/Hanja characters). It also affects
+ * other aspects of text display, including line breaking.
+ *
+ * @param locales the {@link LocaleList} for drawing text, must not be null or empty.
+ *
+ * @see Paint#setTextLocales
+ */
+ public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+ mLocalesChanged = true;
+ mTextPaint.setTextLocales(locales);
+ }
+
@Override
protected void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
- if (!mLocaleChanged) {
- mTextPaint.setTextLocale(Locale.getDefault());
+ if (!mLocalesChanged) {
+ mTextPaint.setTextLocales(LocaleList.getDefault());
}
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index c5d68bd..ce35b87 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -17,10 +17,13 @@
package android.graphics;
import android.annotation.ColorInt;
+import android.annotation.NonNull;
+import android.annotation.Size;
import android.text.GraphicsOperations;
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
+import android.util.LocaleList;
import java.util.Locale;
@@ -50,7 +53,7 @@
private float mCompatScaling;
private float mInvCompatScaling;
- private Locale mLocale;
+ private LocaleList mLocales;
private String mFontFeatureSettings;
/**
@@ -434,7 +437,7 @@
// setHinting(DisplayMetrics.DENSITY_DEVICE >= DisplayMetrics.DENSITY_TV
// ? HINTING_OFF : HINTING_ON);
mCompatScaling = mInvCompatScaling = 1;
- setTextLocale(Locale.getDefault());
+ setTextLocales(LocaleList.getDefault());
}
/**
@@ -474,7 +477,7 @@
mInvCompatScaling = 1;
mBidiFlags = BIDI_DEFAULT_LTR;
- setTextLocale(Locale.getDefault());
+ setTextLocales(LocaleList.getDefault());
setElegantTextHeight(false);
mFontFeatureSettings = null;
}
@@ -512,7 +515,7 @@
mInvCompatScaling = paint.mInvCompatScaling;
mBidiFlags = paint.mBidiFlags;
- mLocale = paint.mLocale;
+ mLocales = paint.mLocales;
mFontFeatureSettings = paint.mFontFeatureSettings;
}
@@ -1174,47 +1177,80 @@
}
/**
- * Get the text Locale.
+ * Get the text's primary Locale. Note that this is not all of the locale-related information
+ * Paint has. Use {@link #getTextLocales()} to get the complete list.
*
- * @return the paint's Locale used for drawing text, never null.
+ * @return the paint's primary Locale used for drawing text, never null.
*/
+ @NonNull
public Locale getTextLocale() {
- return mLocale;
+ return mLocales.getPrimary();
}
/**
- * Set the text locale.
+ * Get the text locale list.
*
- * The text locale affects how the text is drawn for some languages.
+ * @return the paint's LocaleList used for drawing text, never null or empty.
+ */
+ @NonNull @Size(min=1)
+ public LocaleList getTextLocales() {
+ return mLocales;
+ }
+
+ /**
+ * Set the text locale list to a one-member list consisting of just the locale.
*
- * For example, if the locale is {@link Locale#CHINESE} or {@link Locale#CHINA},
+ * See {@link #setTextLocales(LocaleList)} for how the locale list affects
+ * the way the text is drawn for some languages.
+ *
+ * @param locale the paint's locale value for drawing text, must not be null.
+ */
+ public void setTextLocale(@NonNull Locale locale) {
+ if (locale == null) {
+ throw new IllegalArgumentException("locale cannot be null");
+ }
+ if (mLocales != null && mLocales.size() == 1 && locale.equals(mLocales.getPrimary())) {
+ return;
+ }
+ mLocales = new LocaleList(locale);
+ native_setTextLocale(mNativePaint, locale.toString());
+ }
+
+ /**
+ * Set the text locale list.
+ *
+ * The text locale list affects how the text is drawn for some languages.
+ *
+ * For example, if the locale list contains {@link Locale#CHINESE} or {@link Locale#CHINA},
* then the text renderer will prefer to draw text using a Chinese font. Likewise,
- * if the locale is {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
- * renderer will prefer to draw text using a Japanese font.
+ * if the locale list contains {@link Locale#JAPANESE} or {@link Locale#JAPAN}, then the text
+ * renderer will prefer to draw text using a Japanese font. If the locale list contains both,
+ * the order those locales appear in the list is considered for deciding the font.
*
* This distinction is important because Chinese and Japanese text both use many
* of the same Unicode code points but their appearance is subtly different for
* each language.
*
- * By default, the text locale is initialized to the system locale (as returned
- * by {@link Locale#getDefault}). This assumes that the text to be rendered will
- * most likely be in the user's preferred language.
+ * By default, the text locale list is initialized to a one-member list just containing the
+ * system locale (as returned by {@link LocaleList#getDefault()}). This assumes that the text to
+ * be rendered will most likely be in the user's preferred language.
*
- * If the actual language of the text is known, then it can be provided to the
- * text renderer using this method. The text renderer may attempt to guess the
+ * If the actual language or languages of the text is/are known, then they can be provided to
+ * the text renderer using this method. The text renderer may attempt to guess the
* language script based on the contents of the text to be drawn independent of
- * the text locale here. Specifying the text locale just helps it do a better
- * job in certain ambiguous cases
+ * the text locale here. Specifying the text locales just helps it do a better
+ * job in certain ambiguous cases.
*
- * @param locale the paint's locale value for drawing text, must not be null.
+ * @param locales the paint's locale list for drawing text, must not be null or empty.
*/
- public void setTextLocale(Locale locale) {
- if (locale == null) {
- throw new IllegalArgumentException("locale cannot be null");
+ public void setTextLocales(@NonNull @Size(min=1) LocaleList locales) {
+ if (locales == null || locales.isEmpty()) {
+ throw new IllegalArgumentException("locales cannot be null or empty");
}
- if (locale.equals(mLocale)) return;
- mLocale = locale;
- native_setTextLocale(mNativePaint, locale.toString());
+ if (locales.equals(mLocales)) return;
+ mLocales = locales;
+ // TODO: Pass the whole LocaleList to native code
+ native_setTextLocale(mNativePaint, locales.getPrimary().toString());
}
/**