diff options
| author | 2016-02-24 18:27:04 -0800 | |
|---|---|---|
| committer | 2016-02-24 18:27:04 -0800 | |
| commit | e985c240e3feb62ea38d5b4e386be083ca0f215b (patch) | |
| tree | a59eb463da3c29d7e8c01168d328a2faa8604a70 | |
| parent | 102ff0726dad764df741e41766d78fcfb829184a (diff) | |
Use LocaleList for implicitly enabled subtypes.
There are two major changes in this CL:
1. Now IMMS resets its internal state whenever the system locale list
is changed, rather than just checking the primary system locale.
2. For software keyboard subtypes,
InputMethodUtils#getImplicitlyApplicableSubtypesLocked() now takes
the entire system locale list into account when determining what
subtypes should be enabled by default when the user does not
explicitly enable one or more subtypes.
Bug: 27129703
Change-Id: Iaf179d60c12b9a98b4f097e2449471c4184e049b
3 files changed, 97 insertions, 45 deletions
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java index 62e149afab7f..4e48e45d018e 100644 --- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java +++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java @@ -32,6 +32,7 @@ import android.text.TextUtils; import android.text.TextUtils.SimpleStringSplitter; import android.util.ArrayMap; import android.util.ArraySet; +import android.util.LocaleList; import android.util.Pair; import android.util.Printer; import android.util.Slog; @@ -486,18 +487,29 @@ public class InputMethodUtils { return NOT_A_SUBTYPE_ID; } + private static final LocaleUtils.LocaleExtractor<InputMethodSubtype> sSubtypeToLocale = + new LocaleUtils.LocaleExtractor<InputMethodSubtype>() { + @Override + public Locale get(InputMethodSubtype source) { + return source != null ? source.getLocaleObject() : null; + } + }; + @VisibleForTesting public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked( Resources res, InputMethodInfo imi) { final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi); - final String systemLocale = res.getConfiguration().locale.toString(); + final LocaleList systemLocales = res.getConfiguration().getLocales(); + final String systemLocale = systemLocales.get(0).toString(); if (TextUtils.isEmpty(systemLocale)) return new ArrayList<>(); - final String systemLanguage = res.getConfiguration().locale.getLanguage(); + final int numSubtypes = subtypes.size(); + + // Handle overridesImplicitlyEnabledSubtype mechanism. + final String systemLanguage = systemLocales.get(0).getLanguage(); final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new HashMap<>(); - final int N = subtypes.size(); - for (int i = 0; i < N; ++i) { + for (int i = 0; i < numSubtypes; ++i) { // scan overriding implicitly enabled subtypes. - InputMethodSubtype subtype = subtypes.get(i); + final InputMethodSubtype subtype = subtypes.get(i); if (subtype.overridesImplicitlyEnabledSubtype()) { final String mode = subtype.getMode(); if (!applicableModeAndSubtypesMap.containsKey(mode)) { @@ -508,42 +520,46 @@ public class InputMethodUtils { if (applicableModeAndSubtypesMap.size() > 0) { return new ArrayList<>(applicableModeAndSubtypesMap.values()); } - for (int i = 0; i < N; ++i) { + + final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>(); + for (int i = 0; i < numSubtypes; ++i) { final InputMethodSubtype subtype = subtypes.get(i); - final String locale = subtype.getLocale(); - final String mode = subtype.getMode(); - final String language = getLanguageFromLocaleString(locale); - // When system locale starts with subtype's locale, that subtype will be applicable - // for system locale. We need to make sure the languages are the same, to prevent - // locales like "fil" (Filipino) being matched by "fi" (Finnish). - // - // For instance, it's clearly applicable for cases like system locale = en_US and - // subtype = en, but it is not necessarily considered applicable for cases like system - // locale = en and subtype = en_US. - // - // We just call systemLocale.startsWith(locale) in this function because there is no - // need to find applicable subtypes aggressively unlike - // findLastResortApplicableSubtypeLocked. - // - // TODO: This check is broken. It won't take scripts into account and doesn't - // account for the mandatory conversions performed by Locale#toString. - if (language.equals(systemLanguage) && systemLocale.startsWith(locale)) { - final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode); - // If more applicable subtypes are contained, skip. - if (applicableSubtype != null) { - if (systemLocale.equals(applicableSubtype.getLocale())) continue; - if (!systemLocale.equals(locale)) continue; + if (TextUtils.equals(SUBTYPE_MODE_KEYBOARD, subtype.getMode())) { + keyboardSubtypes.add(subtype); + } else { + final Locale locale = subtype.getLocaleObject(); + final String mode = subtype.getMode(); + // TODO: Take secondary system locales into consideration. + if (locale != null && locale.equals(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); } - applicableModeAndSubtypesMap.put(mode, subtype); } } - final InputMethodSubtype keyboardSubtype - = applicableModeAndSubtypesMap.get(SUBTYPE_MODE_KEYBOARD); - final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>( - applicableModeAndSubtypesMap.values()); - if (keyboardSubtype != null && !keyboardSubtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) { - for (int i = 0; i < N; ++i) { - final InputMethodSubtype subtype = subtypes.get(i); + + final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>(); + LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales, + applicableSubtypes); + + boolean hasAsciiCapableKeyboard = false; + final int numApplicationSubtypes = applicableSubtypes.size(); + for (int i = 0; i < numApplicationSubtypes; ++i) { + final InputMethodSubtype subtype = applicableSubtypes.get(i); + if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) { + hasAsciiCapableKeyboard = true; + break; + } + } + if (!hasAsciiCapableKeyboard) { + final int numKeyboardSubtypes = keyboardSubtypes.size(); + for (int i = 0; i < numKeyboardSubtypes; ++i) { + final InputMethodSubtype subtype = keyboardSubtypes.get(i); final String mode = subtype.getMode(); if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey( TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) { @@ -551,13 +567,16 @@ public class InputMethodUtils { } } } - if (keyboardSubtype == null) { + + if (applicableSubtypes.isEmpty()) { InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked( res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true); if (lastResortKeyboardSubtype != null) { applicableSubtypes.add(lastResortKeyboardSubtype); } } + + applicableSubtypes.addAll(applicableModeAndSubtypesMap.values()); return applicableSubtypes; } diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java index 380d3b44d8ea..ac020e48355a 100644 --- a/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java +++ b/core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java @@ -37,6 +37,10 @@ import java.util.List; import java.util.Locale; import java.util.Objects; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.isIn; +import static org.hamcrest.Matchers.not; + public class InputMethodUtilsTest extends InstrumentationTestCase { private static final boolean IS_AUX = true; private static final boolean IS_DEFAULT = true; @@ -187,6 +191,9 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); + final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN", + SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, + IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA", SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE); @@ -433,6 +440,32 @@ public class InputMethodUtilsTest extends InstrumentationTestCase { assertEquals(1, result.size()); verifyEquality(nonAutoId, result.get(0)); } + + // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and the system + // provides multiple locales, we try to enable multiple subtypes. + { + final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>(); + subtypes.add(nonAutoEnUS); + subtypes.add(nonAutoFrCA); + subtypes.add(nonAutoIn); + subtypes.add(nonAutoJa); + subtypes.add(nonAutoFil); + subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype); + subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2); + 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_FR, LOCALE_EN_US, LOCALE_JA_JP), imi); + assertThat(nonAutoFrCA, isIn(result)); + assertThat(nonAutoEnUS, isIn(result)); + assertThat(nonAutoJa, isIn(result)); + assertThat(nonAutoIn, not(isIn(result))); + assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result))); + assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result))); + } } @SmallTest diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java index 5ba8bd555237..63c9822d82c8 100644 --- a/services/core/java/com/android/server/InputMethodManagerService.java +++ b/services/core/java/com/android/server/InputMethodManagerService.java @@ -95,6 +95,7 @@ import android.util.ArrayMap; import android.util.ArraySet; import android.util.AtomicFile; import android.util.EventLog; +import android.util.LocaleList; import android.util.LruCache; import android.util.Pair; import android.util.PrintWriterPrinter; @@ -135,7 +136,6 @@ import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; -import java.util.Locale; /** * This class provides a system service that manages input methods. @@ -446,7 +446,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub private View mSwitchingDialogTitleView; private InputMethodInfo[] mIms; private int[] mSubtypeIds; - private Locale mLastSystemLocale; + private LocaleList mLastSystemLocales; private boolean mShowImeWithHardKeyboard; private boolean mAccessibilityRequestingNoSoftKeyboard; private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor(); @@ -949,15 +949,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub // not system ready return; } - final Locale newLocale = mRes.getConfiguration().locale; + final LocaleList newLocales = mRes.getConfiguration().getLocales(); if (!updateOnlyWhenLocaleChanged - || (newLocale != null && !newLocale.equals(mLastSystemLocale))) { + || (newLocales != null && !newLocales.equals(mLastSystemLocales))) { if (!updateOnlyWhenLocaleChanged) { hideCurrentInputLocked(0, null); resetCurrentMethodAndClient(InputMethodClient.UNBIND_REASON_RESET_IME); } if (DEBUG) { - Slog.i(TAG, "Locale has been changed to " + newLocale); + Slog.i(TAG, "LocaleList has been changed to " + newLocales); } buildInputMethodListLocked(resetDefaultEnabledIme); if (!updateOnlyWhenLocaleChanged) { @@ -972,7 +972,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub resetDefaultImeLocked(mContext); } updateFromSettingsLocked(true); - mLastSystemLocale = newLocale; + mLastSystemLocales = newLocales; if (!updateOnlyWhenLocaleChanged) { try { startInputInnerLocked(); @@ -1079,7 +1079,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mSettings.getEnabledInputMethodListLocked(), mSettings.getCurrentUserId(), mContext.getBasePackageName()); } - mLastSystemLocale = mRes.getConfiguration().locale; + mLastSystemLocales = mRes.getConfiguration().getLocales(); try { startInputInnerLocked(); } catch (RuntimeException e) { |