Support all RTL scripts in getLayoutDirectionFromLocale().
Previously, only the languages written in Arabic and Hebrew were
considered right-to-left. Now, ICU is used to return the direction
of the language, which not only support other right-to-left scripts
(such as Thaana), but also has better logic to determine the
direction of the locale and uses caching to improve the speed.
Bug: 22559274
Change-Id: I760be7984a9b35ea77d59ca84a220798e205af36
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index d8f7158..8132dee 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -18,6 +18,7 @@
import android.annotation.Nullable;
import android.content.res.Resources;
+import android.icu.util.ULocale;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemProperties;
@@ -1754,45 +1755,12 @@
* Be careful: this code will need to be updated when vertical scripts will be supported
*/
public static int getLayoutDirectionFromLocale(Locale locale) {
- if (locale != null && !locale.equals(Locale.ROOT)) {
- final String scriptSubtag = ICU.addLikelySubtags(locale).getScript();
- if (scriptSubtag == null) return getLayoutDirectionFromFirstChar(locale);
-
- if (scriptSubtag.equalsIgnoreCase(ARAB_SCRIPT_SUBTAG) ||
- scriptSubtag.equalsIgnoreCase(HEBR_SCRIPT_SUBTAG)) {
- return View.LAYOUT_DIRECTION_RTL;
- }
- }
- // If forcing into RTL layout mode, return RTL as default, else LTR
- return SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false)
- ? View.LAYOUT_DIRECTION_RTL
- : View.LAYOUT_DIRECTION_LTR;
- }
-
- /**
- * Fallback algorithm to detect the locale direction. Rely on the fist char of the
- * localized locale name. This will not work if the localized locale name is in English
- * (this is the case for ICU 4.4 and "Urdu" script)
- *
- * @param locale
- * @return the layout direction. This may be one of:
- * {@link View#LAYOUT_DIRECTION_LTR} or
- * {@link View#LAYOUT_DIRECTION_RTL}.
- *
- * Be careful: this code will need to be updated when vertical scripts will be supported
- *
- * @hide
- */
- private static int getLayoutDirectionFromFirstChar(Locale locale) {
- switch(Character.getDirectionality(locale.getDisplayName(locale).charAt(0))) {
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
- case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
- return View.LAYOUT_DIRECTION_RTL;
-
- case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
- default:
- return View.LAYOUT_DIRECTION_LTR;
- }
+ return ((locale != null && !locale.equals(Locale.ROOT)
+ && ULocale.forLocale(locale).isRightToLeft())
+ // If forcing into RTL layout mode, return RTL as default
+ || SystemProperties.getBoolean(Settings.Global.DEVELOPMENT_FORCE_RTL, false))
+ ? View.LAYOUT_DIRECTION_RTL
+ : View.LAYOUT_DIRECTION_LTR;
}
/**
@@ -1811,7 +1779,4 @@
private static String[] EMPTY_STRING_ARRAY = new String[]{};
private static final char ZWNBS_CHAR = '\uFEFF';
-
- private static String ARAB_SCRIPT_SUBTAG = "Arab";
- private static String HEBR_SCRIPT_SUBTAG = "Hebr";
}
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 5a6ef30..121f02a 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -25,9 +25,11 @@
import android.text.style.StyleSpan;
import android.text.util.Rfc822Token;
import android.text.util.Rfc822Tokenizer;
+import android.view.View;
import java.util.ArrayList;
import java.util.List;
+import java.util.Locale;
import junit.framework.TestCase;
@@ -519,4 +521,46 @@
return 0;
}
}
+
+ @SmallTest
+ public void testGetLayoutDirectionFromLocale() {
+ assertEquals(View.LAYOUT_DIRECTION_LTR, TextUtils.getLayoutDirectionFromLocale(null));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.ROOT));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en")));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en-US")));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az")));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-AZ")));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-Latn")));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("en-EG")));
+ assertEquals(View.LAYOUT_DIRECTION_LTR,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ar-Latn")));
+
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ar")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("fa")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("he")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("iw")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("ur")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("dv")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-Arab")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("az-IR")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("fa-US")));
+ assertEquals(View.LAYOUT_DIRECTION_RTL,
+ TextUtils.getLayoutDirectionFromLocale(Locale.forLanguageTag("tr-Arab")));
+ }
}