Loading core/java/android/view/inputmethod/InputMethodSubtype.java +2 −2 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; import com.android.internal.inputmethod.InputMethodUtils; import com.android.internal.inputmethod.LocaleUtils; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -384,7 +384,7 @@ public final class InputMethodSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag); } else { mCachedLocaleObj = InputMethodUtils.constructLocaleFromString(mSubtypeLocale); mCachedLocaleObj = LocaleUtils.constructLocaleFromString(mSubtypeLocale); } return mCachedLocaleObj; } Loading core/java/android/view/textservice/SpellCheckerSubtype.java +2 −2 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; import com.android.internal.inputmethod.InputMethodUtils; import com.android.internal.inputmethod.LocaleUtils; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -228,7 +228,7 @@ public final class SpellCheckerSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { return Locale.forLanguageTag(mSubtypeLanguageTag); } return InputMethodUtils.constructLocaleFromString(mSubtypeLocale); return LocaleUtils.constructLocaleFromString(mSubtypeLocale); } /** Loading core/java/com/android/internal/inputmethod/InputMethodUtils.java +0 −153 Original line number Diff line number Diff line Loading @@ -334,32 +334,6 @@ public class InputMethodUtils { return getDefaultEnabledImes(context, imis, false /* onlyMinimum */); } public static Locale constructLocaleFromString(String localeStr) { if (TextUtils.isEmpty(localeStr)) { return null; } // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. String[] localeParams = localeStr.split("_", 3); if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { // Convert a locale whose language is "tl" to one whose language is "fil". // For example, "tl_PH" will get converted to "fil_PH". // Versions of Android earlier than Lollipop did not support three letter language // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). // On Lollipop and above, the current three letter version must be used. localeParams[0] = "fil"; } // The length of localeStr is guaranteed to always return a 1 <= value <= 3 // because localeStr is not empty. if (localeParams.length == 1) { return new Locale(localeParams[0]); } else if (localeParams.length == 2) { return new Locale(localeParams[0], localeParams[1]); } else if (localeParams.length == 3) { return new Locale(localeParams[0], localeParams[1], localeParams[2]); } return null; } public static boolean containsSubtypeOf(final InputMethodInfo imi, @Nullable final Locale locale, final boolean checkCountry, final String mode) { if (locale == null) { Loading Loading @@ -1320,133 +1294,7 @@ public class InputMethodUtils { } } // For spell checker service manager. // TODO: Should we have TextServicesUtils.java? private static final Locale LOCALE_EN_US = new Locale("en", "US"); private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); /** * Returns a list of {@link Locale} in the order of appropriateness for the default spell * checker service. * * <p>If the system language is English, and the region is also explicitly specified in the * system locale, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * <p>If the system language is English, but no region is specified in the system locale, * the following fallback order will be applied.</p> * <ul> * <li>("en")</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * </ul> * * <p>If the system language is not English, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region) (if exists)</li> * <li>(system-locale-language) (if exists)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * @param systemLocale the current system locale to be taken into consideration. * @return a list of {@link Locale}. The first one is considered to be most appropriate. */ @VisibleForTesting public static ArrayList<Locale> getSuitableLocalesForSpellChecker( @Nullable final Locale systemLocale) { final Locale systemLocaleLanguageCountryVariant; final Locale systemLocaleLanguageCountry; final Locale systemLocaleLanguage; if (systemLocale != null) { final String language = systemLocale.getLanguage(); final boolean hasLanguage = !TextUtils.isEmpty(language); final String country = systemLocale.getCountry(); final boolean hasCountry = !TextUtils.isEmpty(country); final String variant = systemLocale.getVariant(); final boolean hasVariant = !TextUtils.isEmpty(variant); if (hasLanguage && hasCountry && hasVariant) { systemLocaleLanguageCountryVariant = new Locale(language, country, variant); } else { systemLocaleLanguageCountryVariant = null; } if (hasLanguage && hasCountry) { systemLocaleLanguageCountry = new Locale(language, country); } else { systemLocaleLanguageCountry = null; } if (hasLanguage) { systemLocaleLanguage = new Locale(language); } else { systemLocaleLanguage = null; } } else { systemLocaleLanguageCountryVariant = null; systemLocaleLanguageCountry = null; systemLocaleLanguage = null; } final ArrayList<Locale> locales = new ArrayList<>(); if (systemLocaleLanguageCountryVariant != null) { locales.add(systemLocaleLanguageCountryVariant); } if (Locale.ENGLISH.equals(systemLocaleLanguage)) { if (systemLocaleLanguageCountry != null) { // If the system language is English, and the region is also explicitly specified, // following fallback order will be applied. // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (!LOCALE_EN_US.equals(systemLocaleLanguageCountry)) { locales.add(LOCALE_EN_US); } if (!LOCALE_EN_GB.equals(systemLocaleLanguageCountry)) { locales.add(LOCALE_EN_GB); } locales.add(Locale.ENGLISH); } else { // If the system language is English, but no region is specified, following // fallback order will be applied. // - en // - en_US // - en_GB locales.add(Locale.ENGLISH); locales.add(LOCALE_EN_US); locales.add(LOCALE_EN_GB); } } else { // If the system language is not English, the fallback order will be // - systemLocaleLanguageCountry [if non-null] // - systemLocaleLanguage [if non-null] // - en_US // - en_GB // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (systemLocaleLanguage != null) { locales.add(systemLocaleLanguage); } locales.add(LOCALE_EN_US); locales.add(LOCALE_EN_GB); locales.add(Locale.ENGLISH); } return locales; } public static boolean isSoftInputModeStateVisibleAllowed( int targetSdkVersion, int controlFlags) { if (targetSdkVersion < Build.VERSION_CODES.P) { Loading @@ -1461,5 +1309,4 @@ public class InputMethodUtils { } return true; } } core/java/com/android/internal/inputmethod/LocaleUtils.java +149 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.internal.inputmethod; import com.android.internal.annotations.VisibleForTesting; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -25,6 +23,8 @@ import android.icu.util.ULocale; import android.os.LocaleList; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; Loading Loading @@ -208,4 +208,151 @@ public final class LocaleUtils { dest.add(sources.get(entry.mIndex)); } } public static Locale constructLocaleFromString(String localeStr) { if (TextUtils.isEmpty(localeStr)) { return null; } // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. String[] localeParams = localeStr.split("_", 3); if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { // Convert a locale whose language is "tl" to one whose language is "fil". // For example, "tl_PH" will get converted to "fil_PH". // Versions of Android earlier than Lollipop did not support three letter language // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). // On Lollipop and above, the current three letter version must be used. localeParams[0] = "fil"; } // The length of localeStr is guaranteed to always return a 1 <= value <= 3 // because localeStr is not empty. if (localeParams.length == 1) { return new Locale(localeParams[0]); } else if (localeParams.length == 2) { return new Locale(localeParams[0], localeParams[1]); } else if (localeParams.length == 3) { return new Locale(localeParams[0], localeParams[1], localeParams[2]); } return null; } /** * Returns a list of {@link Locale} in the order of appropriateness for the default spell * checker service. * * <p>If the system language is English, and the region is also explicitly specified in the * system locale, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * <p>If the system language is English, but no region is specified in the system locale, * the following fallback order will be applied.</p> * <ul> * <li>("en")</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * </ul> * * <p>If the system language is not English, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region) (if exists)</li> * <li>(system-locale-language) (if exists)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * @param systemLocale the current system locale to be taken into consideration. * @return a list of {@link Locale}. The first one is considered to be most appropriate. */ public static ArrayList<Locale> getSuitableLocalesForSpellChecker( @Nullable final Locale systemLocale) { final Locale systemLocaleLanguageCountryVariant; final Locale systemLocaleLanguageCountry; final Locale systemLocaleLanguage; if (systemLocale != null) { final String language = systemLocale.getLanguage(); final boolean hasLanguage = !TextUtils.isEmpty(language); final String country = systemLocale.getCountry(); final boolean hasCountry = !TextUtils.isEmpty(country); final String variant = systemLocale.getVariant(); final boolean hasVariant = !TextUtils.isEmpty(variant); if (hasLanguage && hasCountry && hasVariant) { systemLocaleLanguageCountryVariant = new Locale(language, country, variant); } else { systemLocaleLanguageCountryVariant = null; } if (hasLanguage && hasCountry) { systemLocaleLanguageCountry = new Locale(language, country); } else { systemLocaleLanguageCountry = null; } if (hasLanguage) { systemLocaleLanguage = new Locale(language); } else { systemLocaleLanguage = null; } } else { systemLocaleLanguageCountryVariant = null; systemLocaleLanguageCountry = null; systemLocaleLanguage = null; } final ArrayList<Locale> locales = new ArrayList<>(); if (systemLocaleLanguageCountryVariant != null) { locales.add(systemLocaleLanguageCountryVariant); } if (Locale.ENGLISH.equals(systemLocaleLanguage)) { if (systemLocaleLanguageCountry != null) { // If the system language is English, and the region is also explicitly specified, // following fallback order will be applied. // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (!Locale.US.equals(systemLocaleLanguageCountry)) { locales.add(Locale.US); } if (!Locale.UK.equals(systemLocaleLanguageCountry)) { locales.add(Locale.UK); } locales.add(Locale.ENGLISH); } else { // If the system language is English, but no region is specified, following // fallback order will be applied. // - en // - en_US // - en_GB locales.add(Locale.ENGLISH); locales.add(Locale.US); locales.add(Locale.UK); } } else { // If the system language is not English, the fallback order will be // - systemLocaleLanguageCountry [if non-null] // - systemLocaleLanguage [if non-null] // - en_US // - en_GB // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (systemLocaleLanguage != null) { locales.add(systemLocaleLanguage); } locales.add(Locale.US); locales.add(Locale.UK); locales.add(Locale.ENGLISH); } return locales; } } core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +0 −120 Original line number Diff line number Diff line Loading @@ -71,15 +71,11 @@ public class InputMethodUtilsTest { private static final Locale LOCALE_FR = new Locale("fr"); private static final Locale LOCALE_FR_CA = new Locale("fr", "CA"); private static final Locale LOCALE_HI = new Locale("hi"); private static final Locale LOCALE_JA = new Locale("ja"); private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN"); private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW"); private static final Locale LOCALE_IN = new Locale("in"); private static final Locale LOCALE_ID = new Locale("id"); private static final Locale LOCALE_TH = new Locale("ht"); private static final Locale LOCALE_TH_TH = new Locale("ht", "TH"); private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH"); private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; private static final String SUBTYPE_MODE_VOICE = "voice"; private static final String SUBTYPE_MODE_HANDWRITING = "handwriting"; Loading Loading @@ -1086,122 +1082,6 @@ public class InputMethodUtilsTest { return preinstalledImes; } @Test public void testGetSuitableLocalesForSpellChecker() throws Exception { { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US); assertEquals(3, locales.size()); assertEquals(LOCALE_EN_US, locales.get(0)); assertEquals(LOCALE_EN_GB, locales.get(1)); assertEquals(LOCALE_EN, locales.get(2)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB); assertEquals(3, locales.size()); assertEquals(LOCALE_EN_GB, locales.get(0)); assertEquals(LOCALE_EN_US, locales.get(1)); assertEquals(LOCALE_EN, locales.get(2)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN); assertEquals(3, locales.size()); assertEquals(LOCALE_EN, locales.get(0)); assertEquals(LOCALE_EN_US, locales.get(1)); assertEquals(LOCALE_EN_GB, locales.get(2)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN); assertEquals(4, locales.size()); assertEquals(LOCALE_EN_IN, locales.get(0)); assertEquals(LOCALE_EN_US, locales.get(1)); assertEquals(LOCALE_EN_GB, locales.get(2)); assertEquals(LOCALE_EN, locales.get(3)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP); assertEquals(5, locales.size()); assertEquals(LOCALE_JA_JP, locales.get(0)); assertEquals(LOCALE_JA, locales.get(1)); assertEquals(LOCALE_EN_US, locales.get(2)); assertEquals(LOCALE_EN_GB, locales.get(3)); assertEquals(Locale.ENGLISH, locales.get(4)); } // Test 3-letter language code. { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH); assertEquals(5, locales.size()); assertEquals(LOCALE_FIL_PH, locales.get(0)); assertEquals(LOCALE_FIL, locales.get(1)); assertEquals(LOCALE_EN_US, locales.get(2)); assertEquals(LOCALE_EN_GB, locales.get(3)); assertEquals(Locale.ENGLISH, locales.get(4)); } // Test variant. { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH); assertEquals(6, locales.size()); assertEquals(LOCALE_TH_TH_TH, locales.get(0)); assertEquals(LOCALE_TH_TH, locales.get(1)); assertEquals(LOCALE_TH, locales.get(2)); assertEquals(LOCALE_EN_US, locales.get(3)); assertEquals(LOCALE_EN_GB, locales.get(4)); assertEquals(Locale.ENGLISH, locales.get(5)); } // Test Locale extension. { final Locale localeWithoutVariant = LOCALE_JA_JP; final Locale localeWithVariant = new Locale.Builder() .setLocale(LOCALE_JA_JP) .setExtension('x', "android") .build(); assertFalse(localeWithoutVariant.equals(localeWithVariant)); final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant); assertEquals(5, locales.size()); assertEquals(LOCALE_JA_JP, locales.get(0)); assertEquals(LOCALE_JA, locales.get(1)); assertEquals(LOCALE_EN_US, locales.get(2)); assertEquals(LOCALE_EN_GB, locales.get(3)); assertEquals(Locale.ENGLISH, locales.get(4)); } } @Test public void testConstructLocaleFromString() throws Exception { assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en")); assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US")); assertEquals(new Locale("en", "US", "POSIX"), InputMethodUtils.constructLocaleFromString("en_US_POSIX")); // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not // support three letter language codes, and used "tl" (Tagalog) as the language string for // "fil" (Filipino). assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl")); assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH")); assertEquals(new Locale("fil", "PH", "POSIX"), InputMethodUtils.constructLocaleFromString("tl_PH_POSIX")); // So far rejecting an invalid/unexpected locale string is out of the scope of this method. assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a")); assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c")); assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US")); } @Test public void testIsSoftInputModeStateVisibleAllowed() { // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always Loading Loading
core/java/android/view/inputmethod/InputMethodSubtype.java +2 −2 Original line number Diff line number Diff line Loading @@ -28,7 +28,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; import com.android.internal.inputmethod.InputMethodUtils; import com.android.internal.inputmethod.LocaleUtils; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -384,7 +384,7 @@ public final class InputMethodSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { mCachedLocaleObj = Locale.forLanguageTag(mSubtypeLanguageTag); } else { mCachedLocaleObj = InputMethodUtils.constructLocaleFromString(mSubtypeLocale); mCachedLocaleObj = LocaleUtils.constructLocaleFromString(mSubtypeLocale); } return mCachedLocaleObj; } Loading
core/java/android/view/textservice/SpellCheckerSubtype.java +2 −2 Original line number Diff line number Diff line Loading @@ -25,7 +25,7 @@ import android.os.Parcelable; import android.text.TextUtils; import android.util.Slog; import com.android.internal.inputmethod.InputMethodUtils; import com.android.internal.inputmethod.LocaleUtils; import java.util.ArrayList; import java.util.Arrays; Loading Loading @@ -228,7 +228,7 @@ public final class SpellCheckerSubtype implements Parcelable { if (!TextUtils.isEmpty(mSubtypeLanguageTag)) { return Locale.forLanguageTag(mSubtypeLanguageTag); } return InputMethodUtils.constructLocaleFromString(mSubtypeLocale); return LocaleUtils.constructLocaleFromString(mSubtypeLocale); } /** Loading
core/java/com/android/internal/inputmethod/InputMethodUtils.java +0 −153 Original line number Diff line number Diff line Loading @@ -334,32 +334,6 @@ public class InputMethodUtils { return getDefaultEnabledImes(context, imis, false /* onlyMinimum */); } public static Locale constructLocaleFromString(String localeStr) { if (TextUtils.isEmpty(localeStr)) { return null; } // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. String[] localeParams = localeStr.split("_", 3); if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { // Convert a locale whose language is "tl" to one whose language is "fil". // For example, "tl_PH" will get converted to "fil_PH". // Versions of Android earlier than Lollipop did not support three letter language // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). // On Lollipop and above, the current three letter version must be used. localeParams[0] = "fil"; } // The length of localeStr is guaranteed to always return a 1 <= value <= 3 // because localeStr is not empty. if (localeParams.length == 1) { return new Locale(localeParams[0]); } else if (localeParams.length == 2) { return new Locale(localeParams[0], localeParams[1]); } else if (localeParams.length == 3) { return new Locale(localeParams[0], localeParams[1], localeParams[2]); } return null; } public static boolean containsSubtypeOf(final InputMethodInfo imi, @Nullable final Locale locale, final boolean checkCountry, final String mode) { if (locale == null) { Loading Loading @@ -1320,133 +1294,7 @@ public class InputMethodUtils { } } // For spell checker service manager. // TODO: Should we have TextServicesUtils.java? private static final Locale LOCALE_EN_US = new Locale("en", "US"); private static final Locale LOCALE_EN_GB = new Locale("en", "GB"); /** * Returns a list of {@link Locale} in the order of appropriateness for the default spell * checker service. * * <p>If the system language is English, and the region is also explicitly specified in the * system locale, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * <p>If the system language is English, but no region is specified in the system locale, * the following fallback order will be applied.</p> * <ul> * <li>("en")</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * </ul> * * <p>If the system language is not English, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region) (if exists)</li> * <li>(system-locale-language) (if exists)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * @param systemLocale the current system locale to be taken into consideration. * @return a list of {@link Locale}. The first one is considered to be most appropriate. */ @VisibleForTesting public static ArrayList<Locale> getSuitableLocalesForSpellChecker( @Nullable final Locale systemLocale) { final Locale systemLocaleLanguageCountryVariant; final Locale systemLocaleLanguageCountry; final Locale systemLocaleLanguage; if (systemLocale != null) { final String language = systemLocale.getLanguage(); final boolean hasLanguage = !TextUtils.isEmpty(language); final String country = systemLocale.getCountry(); final boolean hasCountry = !TextUtils.isEmpty(country); final String variant = systemLocale.getVariant(); final boolean hasVariant = !TextUtils.isEmpty(variant); if (hasLanguage && hasCountry && hasVariant) { systemLocaleLanguageCountryVariant = new Locale(language, country, variant); } else { systemLocaleLanguageCountryVariant = null; } if (hasLanguage && hasCountry) { systemLocaleLanguageCountry = new Locale(language, country); } else { systemLocaleLanguageCountry = null; } if (hasLanguage) { systemLocaleLanguage = new Locale(language); } else { systemLocaleLanguage = null; } } else { systemLocaleLanguageCountryVariant = null; systemLocaleLanguageCountry = null; systemLocaleLanguage = null; } final ArrayList<Locale> locales = new ArrayList<>(); if (systemLocaleLanguageCountryVariant != null) { locales.add(systemLocaleLanguageCountryVariant); } if (Locale.ENGLISH.equals(systemLocaleLanguage)) { if (systemLocaleLanguageCountry != null) { // If the system language is English, and the region is also explicitly specified, // following fallback order will be applied. // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (!LOCALE_EN_US.equals(systemLocaleLanguageCountry)) { locales.add(LOCALE_EN_US); } if (!LOCALE_EN_GB.equals(systemLocaleLanguageCountry)) { locales.add(LOCALE_EN_GB); } locales.add(Locale.ENGLISH); } else { // If the system language is English, but no region is specified, following // fallback order will be applied. // - en // - en_US // - en_GB locales.add(Locale.ENGLISH); locales.add(LOCALE_EN_US); locales.add(LOCALE_EN_GB); } } else { // If the system language is not English, the fallback order will be // - systemLocaleLanguageCountry [if non-null] // - systemLocaleLanguage [if non-null] // - en_US // - en_GB // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (systemLocaleLanguage != null) { locales.add(systemLocaleLanguage); } locales.add(LOCALE_EN_US); locales.add(LOCALE_EN_GB); locales.add(Locale.ENGLISH); } return locales; } public static boolean isSoftInputModeStateVisibleAllowed( int targetSdkVersion, int controlFlags) { if (targetSdkVersion < Build.VERSION_CODES.P) { Loading @@ -1461,5 +1309,4 @@ public class InputMethodUtils { } return true; } }
core/java/com/android/internal/inputmethod/LocaleUtils.java +149 −2 Original line number Diff line number Diff line Loading @@ -16,8 +16,6 @@ package com.android.internal.inputmethod; import com.android.internal.annotations.VisibleForTesting; import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; Loading @@ -25,6 +23,8 @@ import android.icu.util.ULocale; import android.os.LocaleList; import android.text.TextUtils; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; Loading Loading @@ -208,4 +208,151 @@ public final class LocaleUtils { dest.add(sources.get(entry.mIndex)); } } public static Locale constructLocaleFromString(String localeStr) { if (TextUtils.isEmpty(localeStr)) { return null; } // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}. String[] localeParams = localeStr.split("_", 3); if (localeParams.length >= 1 && "tl".equals(localeParams[0])) { // Convert a locale whose language is "tl" to one whose language is "fil". // For example, "tl_PH" will get converted to "fil_PH". // Versions of Android earlier than Lollipop did not support three letter language // codes, and used "tl" (Tagalog) as the language string for "fil" (Filipino). // On Lollipop and above, the current three letter version must be used. localeParams[0] = "fil"; } // The length of localeStr is guaranteed to always return a 1 <= value <= 3 // because localeStr is not empty. if (localeParams.length == 1) { return new Locale(localeParams[0]); } else if (localeParams.length == 2) { return new Locale(localeParams[0], localeParams[1]); } else if (localeParams.length == 3) { return new Locale(localeParams[0], localeParams[1], localeParams[2]); } return null; } /** * Returns a list of {@link Locale} in the order of appropriateness for the default spell * checker service. * * <p>If the system language is English, and the region is also explicitly specified in the * system locale, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * <p>If the system language is English, but no region is specified in the system locale, * the following fallback order will be applied.</p> * <ul> * <li>("en")</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * </ul> * * <p>If the system language is not English, the following fallback order will be applied.</p> * <ul> * <li>(system-locale-language, system-locale-region, system-locale-variant) (if exists)</li> * <li>(system-locale-language, system-locale-region) (if exists)</li> * <li>(system-locale-language) (if exists)</li> * <li>("en", "US")</li> * <li>("en", "GB")</li> * <li>("en")</li> * </ul> * * @param systemLocale the current system locale to be taken into consideration. * @return a list of {@link Locale}. The first one is considered to be most appropriate. */ public static ArrayList<Locale> getSuitableLocalesForSpellChecker( @Nullable final Locale systemLocale) { final Locale systemLocaleLanguageCountryVariant; final Locale systemLocaleLanguageCountry; final Locale systemLocaleLanguage; if (systemLocale != null) { final String language = systemLocale.getLanguage(); final boolean hasLanguage = !TextUtils.isEmpty(language); final String country = systemLocale.getCountry(); final boolean hasCountry = !TextUtils.isEmpty(country); final String variant = systemLocale.getVariant(); final boolean hasVariant = !TextUtils.isEmpty(variant); if (hasLanguage && hasCountry && hasVariant) { systemLocaleLanguageCountryVariant = new Locale(language, country, variant); } else { systemLocaleLanguageCountryVariant = null; } if (hasLanguage && hasCountry) { systemLocaleLanguageCountry = new Locale(language, country); } else { systemLocaleLanguageCountry = null; } if (hasLanguage) { systemLocaleLanguage = new Locale(language); } else { systemLocaleLanguage = null; } } else { systemLocaleLanguageCountryVariant = null; systemLocaleLanguageCountry = null; systemLocaleLanguage = null; } final ArrayList<Locale> locales = new ArrayList<>(); if (systemLocaleLanguageCountryVariant != null) { locales.add(systemLocaleLanguageCountryVariant); } if (Locale.ENGLISH.equals(systemLocaleLanguage)) { if (systemLocaleLanguageCountry != null) { // If the system language is English, and the region is also explicitly specified, // following fallback order will be applied. // - systemLocaleLanguageCountry [if systemLocaleLanguageCountry is non-null] // - en_US [if systemLocaleLanguageCountry is non-null and not en_US] // - en_GB [if systemLocaleLanguageCountry is non-null and not en_GB] // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (!Locale.US.equals(systemLocaleLanguageCountry)) { locales.add(Locale.US); } if (!Locale.UK.equals(systemLocaleLanguageCountry)) { locales.add(Locale.UK); } locales.add(Locale.ENGLISH); } else { // If the system language is English, but no region is specified, following // fallback order will be applied. // - en // - en_US // - en_GB locales.add(Locale.ENGLISH); locales.add(Locale.US); locales.add(Locale.UK); } } else { // If the system language is not English, the fallback order will be // - systemLocaleLanguageCountry [if non-null] // - systemLocaleLanguage [if non-null] // - en_US // - en_GB // - en if (systemLocaleLanguageCountry != null) { locales.add(systemLocaleLanguageCountry); } if (systemLocaleLanguage != null) { locales.add(systemLocaleLanguage); } locales.add(Locale.US); locales.add(Locale.UK); locales.add(Locale.ENGLISH); } return locales; } }
core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +0 −120 Original line number Diff line number Diff line Loading @@ -71,15 +71,11 @@ public class InputMethodUtilsTest { private static final Locale LOCALE_FR = new Locale("fr"); private static final Locale LOCALE_FR_CA = new Locale("fr", "CA"); private static final Locale LOCALE_HI = new Locale("hi"); private static final Locale LOCALE_JA = new Locale("ja"); private static final Locale LOCALE_JA_JP = new Locale("ja", "JP"); private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN"); private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW"); private static final Locale LOCALE_IN = new Locale("in"); private static final Locale LOCALE_ID = new Locale("id"); private static final Locale LOCALE_TH = new Locale("ht"); private static final Locale LOCALE_TH_TH = new Locale("ht", "TH"); private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH"); private static final String SUBTYPE_MODE_KEYBOARD = "keyboard"; private static final String SUBTYPE_MODE_VOICE = "voice"; private static final String SUBTYPE_MODE_HANDWRITING = "handwriting"; Loading Loading @@ -1086,122 +1082,6 @@ public class InputMethodUtilsTest { return preinstalledImes; } @Test public void testGetSuitableLocalesForSpellChecker() throws Exception { { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_US); assertEquals(3, locales.size()); assertEquals(LOCALE_EN_US, locales.get(0)); assertEquals(LOCALE_EN_GB, locales.get(1)); assertEquals(LOCALE_EN, locales.get(2)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_GB); assertEquals(3, locales.size()); assertEquals(LOCALE_EN_GB, locales.get(0)); assertEquals(LOCALE_EN_US, locales.get(1)); assertEquals(LOCALE_EN, locales.get(2)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN); assertEquals(3, locales.size()); assertEquals(LOCALE_EN, locales.get(0)); assertEquals(LOCALE_EN_US, locales.get(1)); assertEquals(LOCALE_EN_GB, locales.get(2)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_EN_IN); assertEquals(4, locales.size()); assertEquals(LOCALE_EN_IN, locales.get(0)); assertEquals(LOCALE_EN_US, locales.get(1)); assertEquals(LOCALE_EN_GB, locales.get(2)); assertEquals(LOCALE_EN, locales.get(3)); } { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_JA_JP); assertEquals(5, locales.size()); assertEquals(LOCALE_JA_JP, locales.get(0)); assertEquals(LOCALE_JA, locales.get(1)); assertEquals(LOCALE_EN_US, locales.get(2)); assertEquals(LOCALE_EN_GB, locales.get(3)); assertEquals(Locale.ENGLISH, locales.get(4)); } // Test 3-letter language code. { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_FIL_PH); assertEquals(5, locales.size()); assertEquals(LOCALE_FIL_PH, locales.get(0)); assertEquals(LOCALE_FIL, locales.get(1)); assertEquals(LOCALE_EN_US, locales.get(2)); assertEquals(LOCALE_EN_GB, locales.get(3)); assertEquals(Locale.ENGLISH, locales.get(4)); } // Test variant. { final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(LOCALE_TH_TH_TH); assertEquals(6, locales.size()); assertEquals(LOCALE_TH_TH_TH, locales.get(0)); assertEquals(LOCALE_TH_TH, locales.get(1)); assertEquals(LOCALE_TH, locales.get(2)); assertEquals(LOCALE_EN_US, locales.get(3)); assertEquals(LOCALE_EN_GB, locales.get(4)); assertEquals(Locale.ENGLISH, locales.get(5)); } // Test Locale extension. { final Locale localeWithoutVariant = LOCALE_JA_JP; final Locale localeWithVariant = new Locale.Builder() .setLocale(LOCALE_JA_JP) .setExtension('x', "android") .build(); assertFalse(localeWithoutVariant.equals(localeWithVariant)); final ArrayList<Locale> locales = InputMethodUtils.getSuitableLocalesForSpellChecker(localeWithVariant); assertEquals(5, locales.size()); assertEquals(LOCALE_JA_JP, locales.get(0)); assertEquals(LOCALE_JA, locales.get(1)); assertEquals(LOCALE_EN_US, locales.get(2)); assertEquals(LOCALE_EN_GB, locales.get(3)); assertEquals(Locale.ENGLISH, locales.get(4)); } } @Test public void testConstructLocaleFromString() throws Exception { assertEquals(new Locale("en"), InputMethodUtils.constructLocaleFromString("en")); assertEquals(new Locale("en", "US"), InputMethodUtils.constructLocaleFromString("en_US")); assertEquals(new Locale("en", "US", "POSIX"), InputMethodUtils.constructLocaleFromString("en_US_POSIX")); // Special rewrite rule for "tl" for versions of Android earlier than Lollipop that did not // support three letter language codes, and used "tl" (Tagalog) as the language string for // "fil" (Filipino). assertEquals(new Locale("fil"), InputMethodUtils.constructLocaleFromString("tl")); assertEquals(new Locale("fil", "PH"), InputMethodUtils.constructLocaleFromString("tl_PH")); assertEquals(new Locale("fil", "PH", "POSIX"), InputMethodUtils.constructLocaleFromString("tl_PH_POSIX")); // So far rejecting an invalid/unexpected locale string is out of the scope of this method. assertEquals(new Locale("a"), InputMethodUtils.constructLocaleFromString("a")); assertEquals(new Locale("a b c"), InputMethodUtils.constructLocaleFromString("a b c")); assertEquals(new Locale("en-US"), InputMethodUtils.constructLocaleFromString("en-US")); } @Test public void testIsSoftInputModeStateVisibleAllowed() { // On pre-P devices, SOFT_INPUT_STATE_VISIBLE/SOFT_INPUT_STATE_ALWAYS_VISIBLE are always Loading