Loading core/java/com/android/internal/inputmethod/InputMethodUtils.java +14 −15 Original line number Diff line number Diff line Loading @@ -505,7 +505,6 @@ public class InputMethodUtils { final int numSubtypes = subtypes.size(); // Handle overridesImplicitlyEnabledSubtype mechanism. final String systemLanguage = systemLocales.get(0).getLanguage(); final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new HashMap<>(); for (int i = 0; i < numSubtypes; ++i) { // scan overriding implicitly enabled subtypes. Loading @@ -521,25 +520,20 @@ public class InputMethodUtils { return new ArrayList<>(applicableModeAndSubtypesMap.values()); } final HashMap<String, ArrayList<InputMethodSubtype>> nonKeyboardSubtypesMap = new HashMap<>(); final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>(); for (int i = 0; i < numSubtypes; ++i) { final InputMethodSubtype subtype = subtypes.get(i); if (TextUtils.equals(SUBTYPE_MODE_KEYBOARD, subtype.getMode())) { final String mode = subtype.getMode(); if (SUBTYPE_MODE_KEYBOARD.equals(mode)) { keyboardSubtypes.add(subtype); } else { final Locale locale = subtype.getLocaleObject(); final String mode = subtype.getMode(); // TODO: Use LocaleUtils#filterByLanguage() instead. if (locale != null && TextUtils.equals(locale.getLanguage(), systemLanguage)) { final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode); // If more applicable subtypes are contained, skip. if (applicableSubtype != null) { if (systemLocale.equals(applicableSubtype.getLocaleObject())) continue; if (!systemLocale.equals(locale)) continue; } applicableModeAndSubtypesMap.put(mode, subtype); if (!nonKeyboardSubtypesMap.containsKey(mode)) { nonKeyboardSubtypesMap.put(mode, new ArrayList<>()); } nonKeyboardSubtypesMap.get(mode).add(subtype); } } Loading Loading @@ -578,7 +572,12 @@ public class InputMethodUtils { } } applicableSubtypes.addAll(applicableModeAndSubtypesMap.values()); // For each non-keyboard mode, extract subtypes with system locales. for (final ArrayList<InputMethodSubtype> subtypeList : nonKeyboardSubtypesMap.values()) { LocaleUtils.filterByLanguage(subtypeList, sSubtypeToLocale, systemLocales, applicableSubtypes); } return applicableSubtypes; } Loading core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +104 −0 Original line number Diff line number Diff line Loading @@ -219,12 +219,28 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype = createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, Loading Loading @@ -430,6 +446,85 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { verifyEquality(nonAutoEnUS, result.get(0)); } // Make sure that both language and script are taken into account to find the best matching // subtype. { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoSrCyrl); subtypes.add(nonAutoSrLatn); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); final InputMethodInfo imi = createDummyInputMethodInfo( "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi); assertEquals(2, result.size()); assertThat(nonAutoSrLatn, isIn(result)); assertThat(nonAutoHandwritingSrLatn, isIn(result)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoSrCyrl); subtypes.add(nonAutoSrLatn); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); final InputMethodInfo imi = createDummyInputMethodInfo( "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi); assertEquals(2, result.size()); assertThat(nonAutoSrCyrl, isIn(result)); assertThat(nonAutoHandwritingSrCyrl, isIn(result)); } // Make sure that secondary locales are taken into account to find the best matching // subtype. { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoEnGB); subtypes.add(nonAutoSrCyrl); subtypes.add(nonAutoSrLatn); subtypes.add(nonAutoFr); subtypes.add(nonAutoFrCA); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); final InputMethodInfo imi = createDummyInputMethodInfo( "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( getResourcesForLocales( Locale.forLanguageTag("sr-Latn-RS-x-android"), Locale.forLanguageTag("ja-JP"), Locale.forLanguageTag("fr-FR"), Locale.forLanguageTag("en-GB"), Locale.forLanguageTag("en-US")), imi); assertEquals(6, result.size()); assertThat(nonAutoEnGB, isIn(result)); assertThat(nonAutoFr, isIn(result)); assertThat(nonAutoSrLatn, isIn(result)); assertThat(nonAutoHandwritingEn, isIn(result)); assertThat(nonAutoHandwritingFr, isIn(result)); assertThat(nonAutoHandwritingSrLatn, isIn(result)); } // Make sure that 3-letter language code can be handled. { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); Loading Loading @@ -778,7 +873,15 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary, overridesImplicitlyEnabledSubtype, isAsciiCapable, isEnabledWhenDefaultIsNotAsciiCapable); } private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String languageTag, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { final StringBuilder subtypeExtraValue = new StringBuilder(); if (isEnabledWhenDefaultIsNotAsciiCapable) { subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR); Loading @@ -796,6 +899,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { .setSubtypeNameResId(0) .setSubtypeIconResId(0) .setSubtypeLocale(locale) .setLanguageTag(languageTag) .setSubtypeMode(mode) .setSubtypeExtraValue(subtypeExtraValue.toString()) .setIsAuxiliary(isAuxiliary) Loading Loading
core/java/com/android/internal/inputmethod/InputMethodUtils.java +14 −15 Original line number Diff line number Diff line Loading @@ -505,7 +505,6 @@ public class InputMethodUtils { final int numSubtypes = subtypes.size(); // Handle overridesImplicitlyEnabledSubtype mechanism. final String systemLanguage = systemLocales.get(0).getLanguage(); final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new HashMap<>(); for (int i = 0; i < numSubtypes; ++i) { // scan overriding implicitly enabled subtypes. Loading @@ -521,25 +520,20 @@ public class InputMethodUtils { return new ArrayList<>(applicableModeAndSubtypesMap.values()); } final HashMap<String, ArrayList<InputMethodSubtype>> nonKeyboardSubtypesMap = new HashMap<>(); final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>(); for (int i = 0; i < numSubtypes; ++i) { final InputMethodSubtype subtype = subtypes.get(i); if (TextUtils.equals(SUBTYPE_MODE_KEYBOARD, subtype.getMode())) { final String mode = subtype.getMode(); if (SUBTYPE_MODE_KEYBOARD.equals(mode)) { keyboardSubtypes.add(subtype); } else { final Locale locale = subtype.getLocaleObject(); final String mode = subtype.getMode(); // TODO: Use LocaleUtils#filterByLanguage() instead. if (locale != null && TextUtils.equals(locale.getLanguage(), systemLanguage)) { final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode); // If more applicable subtypes are contained, skip. if (applicableSubtype != null) { if (systemLocale.equals(applicableSubtype.getLocaleObject())) continue; if (!systemLocale.equals(locale)) continue; } applicableModeAndSubtypesMap.put(mode, subtype); if (!nonKeyboardSubtypesMap.containsKey(mode)) { nonKeyboardSubtypesMap.put(mode, new ArrayList<>()); } nonKeyboardSubtypesMap.get(mode).add(subtype); } } Loading Loading @@ -578,7 +572,12 @@ public class InputMethodUtils { } } applicableSubtypes.addAll(applicableModeAndSubtypesMap.values()); // For each non-keyboard mode, extract subtypes with system locales. for (final ArrayList<InputMethodSubtype> subtypeList : nonKeyboardSubtypesMap.values()) { LocaleUtils.filterByLanguage(subtypeList, sSubtypeToLocale, systemLocales, applicableSubtypes); } return applicableSubtypes; } Loading
core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +104 −0 Original line number Diff line number Diff line Loading @@ -219,12 +219,28 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoSrCyrl = createDummyInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoSrLatn = createDummyInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingFr = createDummyInputMethodSubtype("fr", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingSrCyrl = createDummyInputMethodSubtype("sr", "sr-Cyrl", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoHandwritingSrLatn = createDummyInputMethodSubtype("sr_ZZ", "sr-Latn", SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype = createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE, Loading Loading @@ -430,6 +446,85 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { verifyEquality(nonAutoEnUS, result.get(0)); } // Make sure that both language and script are taken into account to find the best matching // subtype. { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoSrCyrl); subtypes.add(nonAutoSrLatn); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); final InputMethodInfo imi = createDummyInputMethodInfo( "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi); assertEquals(2, result.size()); assertThat(nonAutoSrLatn, isIn(result)); assertThat(nonAutoHandwritingSrLatn, isIn(result)); } { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoSrCyrl); subtypes.add(nonAutoSrLatn); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); final InputMethodInfo imi = createDummyInputMethodInfo( "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi); assertEquals(2, result.size()); assertThat(nonAutoSrCyrl, isIn(result)); assertThat(nonAutoHandwritingSrCyrl, isIn(result)); } // Make sure that secondary locales are taken into account to find the best matching // subtype. { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); subtypes.add(nonAutoEnUS); subtypes.add(nonAutoEnGB); subtypes.add(nonAutoSrCyrl); subtypes.add(nonAutoSrLatn); subtypes.add(nonAutoFr); subtypes.add(nonAutoFrCA); subtypes.add(nonAutoHandwritingEn); subtypes.add(nonAutoHandwritingFr); subtypes.add(nonAutoHandwritingSrCyrl); subtypes.add(nonAutoHandwritingSrLatn); final InputMethodInfo imi = createDummyInputMethodInfo( "com.android.apps.inputmethod.latin", "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT, subtypes); final ArrayList<InputMethodSubtype> result = InputMethodUtils.getImplicitlyApplicableSubtypesLocked( getResourcesForLocales( Locale.forLanguageTag("sr-Latn-RS-x-android"), Locale.forLanguageTag("ja-JP"), Locale.forLanguageTag("fr-FR"), Locale.forLanguageTag("en-GB"), Locale.forLanguageTag("en-US")), imi); assertEquals(6, result.size()); assertThat(nonAutoEnGB, isIn(result)); assertThat(nonAutoFr, isIn(result)); assertThat(nonAutoSrLatn, isIn(result)); assertThat(nonAutoHandwritingEn, isIn(result)); assertThat(nonAutoHandwritingFr, isIn(result)); assertThat(nonAutoHandwritingSrLatn, isIn(result)); } // Make sure that 3-letter language code can be handled. { final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); Loading Loading @@ -778,7 +873,15 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { return createDummyInputMethodSubtype(locale, null /* languageTag */, mode, isAuxiliary, overridesImplicitlyEnabledSubtype, isAsciiCapable, isEnabledWhenDefaultIsNotAsciiCapable); } private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String languageTag, String mode, boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype, boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) { final StringBuilder subtypeExtraValue = new StringBuilder(); if (isEnabledWhenDefaultIsNotAsciiCapable) { subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR); Loading @@ -796,6 +899,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { .setSubtypeNameResId(0) .setSubtypeIconResId(0) .setSubtypeLocale(locale) .setLanguageTag(languageTag) .setSubtypeMode(mode) .setSubtypeExtraValue(subtypeExtraValue.toString()) .setIsAuxiliary(isAuxiliary) Loading