summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author TreeHugger Robot <treehugger-gerrit@google.com> 2022-06-25 00:33:56 +0000
committer Android (Google) Code Review <android-gerrit@google.com> 2022-06-25 00:33:56 +0000
commit6cd679b4bf52be9c55c108e52a9f632dd1a7bf1b (patch)
treeeaeb8a7a7b02c3cb3856c723ebdcb8a9aa09e01f
parent708b4613cd736261523cb2527e36ff4f0479916d (diff)
parent9d69235a562780654fe3a8a7fd702c1babbaeb42 (diff)
Merge changes I0d7d2373,I7ebea2d6
* changes: Move some InputMethodUtils methods to SubtypeUtils Introduce InputMethodInfoUtils and SubTypeUtils
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java332
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java53
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodMenuController.java2
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java4
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java568
-rw-r--r--services/core/java/com/android/server/inputmethod/LocaleUtils.java23
-rw-r--r--services/core/java/com/android/server/inputmethod/SubtypeUtils.java297
-rw-r--r--services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java132
8 files changed, 753 insertions, 658 deletions
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java
new file mode 100644
index 000000000000..68753ab909b3
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/InputMethodInfoUtils.java
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import static com.android.server.inputmethod.SubtypeUtils.SUBTYPE_MODE_ANY;
+import static com.android.server.inputmethod.SubtypeUtils.SUBTYPE_MODE_KEYBOARD;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * This class provides utility methods to generate or filter {@link InputMethodInfo} for
+ * {@link InputMethodManagerService}.
+ *
+ * <p>This class is intentionally package-private. Utility methods here are tightly coupled with
+ * implementation details in {@link InputMethodManagerService}. Hence this class is not suitable
+ * for other components to directly use.</p>
+ */
+final class InputMethodInfoUtils {
+ private static final String TAG = "InputMethodInfoUtils";
+
+ /**
+ * Used in {@link #getFallbackLocaleForDefaultIme(ArrayList, Context)} to find the fallback IMEs
+ * that are mainly used until the system becomes ready. Note that {@link Locale} in this array
+ * is checked with {@link Locale#equals(Object)}, which means that {@code Locale.ENGLISH}
+ * doesn't automatically match {@code Locale("en", "IN")}.
+ */
+ private static final Locale[] SEARCH_ORDER_OF_FALLBACK_LOCALES = {
+ Locale.ENGLISH, // "en"
+ Locale.US, // "en_US"
+ Locale.UK, // "en_GB"
+ };
+ private static final Locale ENGLISH_LOCALE = new Locale("en");
+
+ private static final class InputMethodListBuilder {
+ // Note: We use LinkedHashSet instead of android.util.ArraySet because the enumeration
+ // order can have non-trivial effect in the call sites.
+ @NonNull
+ private final LinkedHashSet<InputMethodInfo> mInputMethodSet = new LinkedHashSet<>();
+
+ InputMethodListBuilder fillImes(ArrayList<InputMethodInfo> imis, Context context,
+ boolean checkDefaultAttribute, @Nullable Locale locale, boolean checkCountry,
+ String requiredSubtypeMode) {
+ for (int i = 0; i < imis.size(); ++i) {
+ final InputMethodInfo imi = imis.get(i);
+ if (isSystemImeThatHasSubtypeOf(imi, context,
+ checkDefaultAttribute, locale, checkCountry, requiredSubtypeMode)) {
+ mInputMethodSet.add(imi);
+ }
+ }
+ return this;
+ }
+
+ // TODO: The behavior of InputMethodSubtype#overridesImplicitlyEnabledSubtype() should be
+ // documented more clearly.
+ InputMethodListBuilder fillAuxiliaryImes(ArrayList<InputMethodInfo> imis, Context context) {
+ // If one or more auxiliary input methods are available, OK to stop populating the list.
+ for (final InputMethodInfo imi : mInputMethodSet) {
+ if (imi.isAuxiliaryIme()) {
+ return this;
+ }
+ }
+ boolean added = false;
+ for (int i = 0; i < imis.size(); ++i) {
+ final InputMethodInfo imi = imis.get(i);
+ if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
+ true /* checkDefaultAttribute */)) {
+ mInputMethodSet.add(imi);
+ added = true;
+ }
+ }
+ if (added) {
+ return this;
+ }
+ for (int i = 0; i < imis.size(); ++i) {
+ final InputMethodInfo imi = imis.get(i);
+ if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
+ false /* checkDefaultAttribute */)) {
+ mInputMethodSet.add(imi);
+ }
+ }
+ return this;
+
+ }
+
+ public boolean isEmpty() {
+ return mInputMethodSet.isEmpty();
+ }
+
+ @NonNull
+ public ArrayList<InputMethodInfo> build() {
+ return new ArrayList<>(mInputMethodSet);
+ }
+ }
+
+ private static InputMethodListBuilder getMinimumKeyboardSetWithSystemLocale(
+ ArrayList<InputMethodInfo> imis, Context context, @Nullable Locale systemLocale,
+ @Nullable Locale fallbackLocale) {
+ // Once the system becomes ready, we pick up at least one keyboard in the following order.
+ // Secondary users fall into this category in general.
+ // 1. checkDefaultAttribute: true, locale: systemLocale, checkCountry: true
+ // 2. checkDefaultAttribute: true, locale: systemLocale, checkCountry: false
+ // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
+ // 4. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
+ // 5. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
+ // 6. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: false
+ // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
+
+ final InputMethodListBuilder builder = new InputMethodListBuilder();
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
+ if (!builder.isEmpty()) {
+ return builder;
+ }
+ Slog.w(TAG, "No software keyboard is found. imis=" + Arrays.toString(imis.toArray())
+ + " systemLocale=" + systemLocale + " fallbackLocale=" + fallbackLocale);
+ return builder;
+ }
+
+ static ArrayList<InputMethodInfo> getDefaultEnabledImes(
+ Context context, ArrayList<InputMethodInfo> imis, boolean onlyMinimum) {
+ final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
+ // We will primarily rely on the system locale, but also keep relying on the fallback locale
+ // as a last resort.
+ // Also pick up suitable IMEs regardless of the software keyboard support (e.g. Voice IMEs),
+ // then pick up suitable auxiliary IMEs when necessary (e.g. Voice IMEs with "automatic"
+ // subtype)
+ final Locale systemLocale = LocaleUtils.getSystemLocaleFromContext(context);
+ final InputMethodListBuilder builder =
+ getMinimumKeyboardSetWithSystemLocale(imis, context, systemLocale, fallbackLocale);
+ if (!onlyMinimum) {
+ builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
+ true /* checkCountry */, SUBTYPE_MODE_ANY)
+ .fillAuxiliaryImes(imis, context);
+ }
+ return builder.build();
+ }
+
+ static ArrayList<InputMethodInfo> getDefaultEnabledImes(
+ Context context, ArrayList<InputMethodInfo> imis) {
+ return getDefaultEnabledImes(context, imis, false /* onlyMinimum */);
+ }
+
+ /**
+ * Chooses an eligible system voice IME from the given IMEs.
+ *
+ * @param methodMap Map from the IME ID to {@link InputMethodInfo}.
+ * @param systemSpeechRecognizerPackageName System speech recognizer configured by the system
+ * config.
+ * @param currentDefaultVoiceImeId IME ID currently set to
+ * {@link Settings.Secure#DEFAULT_VOICE_INPUT_METHOD}
+ * @return {@link InputMethodInfo} that is found in {@code methodMap} and most suitable for
+ * the system voice IME.
+ */
+ @Nullable
+ static InputMethodInfo chooseSystemVoiceIme(
+ @NonNull ArrayMap<String, InputMethodInfo> methodMap,
+ @Nullable String systemSpeechRecognizerPackageName,
+ @Nullable String currentDefaultVoiceImeId) {
+ if (TextUtils.isEmpty(systemSpeechRecognizerPackageName)) {
+ return null;
+ }
+ final InputMethodInfo defaultVoiceIme = methodMap.get(currentDefaultVoiceImeId);
+ // If the config matches the package of the setting, use the current one.
+ if (defaultVoiceIme != null && defaultVoiceIme.isSystem()
+ && defaultVoiceIme.getPackageName().equals(systemSpeechRecognizerPackageName)) {
+ return defaultVoiceIme;
+ }
+ InputMethodInfo firstMatchingIme = null;
+ final int methodCount = methodMap.size();
+ for (int i = 0; i < methodCount; ++i) {
+ final InputMethodInfo imi = methodMap.valueAt(i);
+ if (!imi.isSystem()) {
+ continue;
+ }
+ if (!TextUtils.equals(imi.getPackageName(), systemSpeechRecognizerPackageName)) {
+ continue;
+ }
+ if (firstMatchingIme != null) {
+ Slog.e(TAG, "At most one InputMethodService can be published in "
+ + "systemSpeechRecognizer: " + systemSpeechRecognizerPackageName
+ + ". Ignoring all of them.");
+ return null;
+ }
+ firstMatchingIme = imi;
+ }
+ return firstMatchingIme;
+ }
+
+ static InputMethodInfo getMostApplicableDefaultIME(List<InputMethodInfo> enabledImes) {
+ if (enabledImes == null || enabledImes.isEmpty()) {
+ return null;
+ }
+ // We'd prefer to fall back on a system IME, since that is safer.
+ int i = enabledImes.size();
+ int firstFoundSystemIme = -1;
+ while (i > 0) {
+ i--;
+ final InputMethodInfo imi = enabledImes.get(i);
+ if (imi.isAuxiliaryIme()) {
+ continue;
+ }
+ if (imi.isSystem() && SubtypeUtils.containsSubtypeOf(imi, ENGLISH_LOCALE,
+ false /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
+ return imi;
+ }
+ if (firstFoundSystemIme < 0 && imi.isSystem()) {
+ firstFoundSystemIme = i;
+ }
+ }
+ return enabledImes.get(Math.max(firstFoundSystemIme, 0));
+ }
+
+ private static boolean isSystemAuxilialyImeThatHasAutomaticSubtype(InputMethodInfo imi,
+ Context context, boolean checkDefaultAttribute) {
+ if (!imi.isSystem()) {
+ return false;
+ }
+ if (checkDefaultAttribute && !imi.isDefault(context)) {
+ return false;
+ }
+ if (!imi.isAuxiliaryIme()) {
+ return false;
+ }
+ final int subtypeCount = imi.getSubtypeCount();
+ for (int i = 0; i < subtypeCount; ++i) {
+ final InputMethodSubtype s = imi.getSubtypeAt(i);
+ if (s.overridesImplicitlyEnabledSubtype()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Nullable
+ private static Locale getFallbackLocaleForDefaultIme(ArrayList<InputMethodInfo> imis,
+ Context context) {
+ // At first, find the fallback locale from the IMEs that are declared as "default" in the
+ // current locale. Note that IME developers can declare an IME as "default" only for
+ // some particular locales but "not default" for other locales.
+ for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
+ for (int i = 0; i < imis.size(); ++i) {
+ if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
+ true /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SubtypeUtils.SUBTYPE_MODE_KEYBOARD)) {
+ return fallbackLocale;
+ }
+ }
+ }
+ // If no fallback locale is found in the above condition, find fallback locales regardless
+ // of the "default" attribute as a last resort.
+ for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
+ for (int i = 0; i < imis.size(); ++i) {
+ if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
+ false /* checkDefaultAttribute */, fallbackLocale,
+ true /* checkCountry */, SubtypeUtils.SUBTYPE_MODE_KEYBOARD)) {
+ return fallbackLocale;
+ }
+ }
+ }
+ Slog.w(TAG, "Found no fallback locale. imis=" + Arrays.toString(imis.toArray()));
+ return null;
+ }
+
+ private static boolean isSystemImeThatHasSubtypeOf(InputMethodInfo imi, Context context,
+ boolean checkDefaultAttribute, @Nullable Locale requiredLocale, boolean checkCountry,
+ String requiredSubtypeMode) {
+ if (!imi.isSystem()) {
+ return false;
+ }
+ if (checkDefaultAttribute && !imi.isDefault(context)) {
+ return false;
+ }
+ if (!SubtypeUtils.containsSubtypeOf(imi, requiredLocale, checkCountry,
+ requiredSubtypeMode)) {
+ return false;
+ }
+ return true;
+ }
+}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index fa6a608d9d31..5a8190a833e3 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -1787,7 +1787,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (selectedMethodId != null && !mMethodMap.get(selectedMethodId).isSystem()) {
return;
}
- final List<InputMethodInfo> suitableImes = InputMethodUtils.getDefaultEnabledImes(
+ final List<InputMethodInfo> suitableImes = InputMethodInfoUtils.getDefaultEnabledImes(
context, mSettings.getEnabledInputMethodListLocked());
if (suitableImes.isEmpty()) {
Slog.i(TAG, "No default found");
@@ -4049,7 +4049,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
}
if (subtype != null) {
setInputMethodWithSubtypeIdLocked(token, id,
- InputMethodUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
+ SubtypeUtils.getSubtypeIdFromHashCode(mMethodMap.get(id),
subtype.hashCode()));
} else {
setInputMethod(token, id);
@@ -4093,7 +4093,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
// defined, there is no need to switch to the last IME.
if (!imiIdIsSame || lastSubtypeHash != currentSubtypeHash) {
targetLastImiId = lastIme.first;
- subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
+ subtypeId = SubtypeUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
}
}
@@ -4112,13 +4112,13 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final InputMethodInfo imi = enabled.get(i);
if (imi.getSubtypeCount() > 0 && imi.isSystem()) {
InputMethodSubtype keyboardSubtype =
- InputMethodUtils.findLastResortApplicableSubtypeLocked(mRes,
- InputMethodUtils.getSubtypes(imi),
- InputMethodUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
+ SubtypeUtils.findLastResortApplicableSubtypeLocked(mRes,
+ SubtypeUtils.getSubtypes(imi),
+ SubtypeUtils.SUBTYPE_MODE_KEYBOARD, locale, true);
if (keyboardSubtype != null) {
targetLastImiId = imi.getId();
- subtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
- imi, keyboardSubtype.hashCode());
+ subtypeId = SubtypeUtils.getSubtypeIdFromHashCode(imi,
+ keyboardSubtype.hashCode());
if(keyboardSubtype.getLocale().equals(locale)) {
break;
}
@@ -4188,8 +4188,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (lastImi == null) return null;
try {
final int lastSubtypeHash = Integer.parseInt(lastIme.second);
- final int lastSubtypeId =
- InputMethodUtils.getSubtypeIdFromHashCode(lastImi, lastSubtypeHash);
+ final int lastSubtypeId = SubtypeUtils.getSubtypeIdFromHashCode(lastImi,
+ lastSubtypeHash);
if (lastSubtypeId < 0 || lastSubtypeId >= lastImi.getSubtypeCount()) {
return null;
}
@@ -4868,7 +4868,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
@GuardedBy("ImfLock.class")
private boolean chooseNewDefaultIMELocked() {
- final InputMethodInfo imi = InputMethodUtils.getMostApplicableDefaultIME(
+ final InputMethodInfo imi = InputMethodInfoUtils.getMostApplicableDefaultIME(
mSettings.getEnabledInputMethodListLocked());
if (imi != null) {
if (DEBUG) {
@@ -5011,7 +5011,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (resetDefaultEnabledIme || reenableMinimumNonAuxSystemImes) {
final ArrayList<InputMethodInfo> defaultEnabledIme =
- InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList,
+ InputMethodInfoUtils.getDefaultEnabledImes(mContext, mMethodList,
reenableMinimumNonAuxSystemImes);
final int N = defaultEnabledIme.size();
for (int i = 0; i < N; ++i) {
@@ -5067,7 +5067,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
final String systemSpeechRecognizer =
mContext.getString(com.android.internal.R.string.config_systemSpeechRecognizer);
final String currentDefaultVoiceImeId = mSettings.getDefaultVoiceInputMethod();
- final InputMethodInfo newSystemVoiceIme = InputMethodUtils.chooseSystemVoiceIme(
+ final InputMethodInfo newSystemVoiceIme = InputMethodInfoUtils.chooseSystemVoiceIme(
mMethodMap, systemSpeechRecognizer, currentDefaultVoiceImeId);
if (newSystemVoiceIme == null) {
if (DEBUG) {
@@ -5193,8 +5193,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
String subtypeHashCode = mSettings.getLastSubtypeForInputMethodLocked(newDefaultIme);
if (subtypeHashCode != null) {
try {
- lastSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
- imi, Integer.parseInt(subtypeHashCode));
+ lastSubtypeId = SubtypeUtils.getSubtypeIdFromHashCode(imi,
+ Integer.parseInt(subtypeHashCode));
} catch (NumberFormatException e) {
Slog.w(TAG, "HashCode for subtype looks broken: " + subtypeHashCode, e);
}
@@ -5229,7 +5229,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
return null;
}
if (!subtypeIsSelected || mCurrentSubtype == null
- || !InputMethodUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
+ || !SubtypeUtils.isValidSubtypeId(imi, mCurrentSubtype.hashCode())) {
int subtypeId = mSettings.getSelectedInputMethodSubtypeId(selectedMethodId);
if (subtypeId == NOT_A_SUBTYPE_ID) {
// If there are no selected subtypes, the framework will try to find
@@ -5242,17 +5242,16 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) {
mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0);
} else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) {
- mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
+ mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtypeLocked(
mRes, explicitlyOrImplicitlyEnabledSubtypes,
- InputMethodUtils.SUBTYPE_MODE_KEYBOARD, null, true);
+ SubtypeUtils.SUBTYPE_MODE_KEYBOARD, null, true);
if (mCurrentSubtype == null) {
- mCurrentSubtype = InputMethodUtils.findLastResortApplicableSubtypeLocked(
- mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null,
- true);
+ mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtypeLocked(
+ mRes, explicitlyOrImplicitlyEnabledSubtypes, null, null, true);
}
}
} else {
- mCurrentSubtype = InputMethodUtils.getSubtypes(imi).get(subtypeId);
+ mCurrentSubtype = SubtypeUtils.getSubtypes(imi).get(subtypeId);
}
}
return mCurrentSubtype;
@@ -6169,8 +6168,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
setInputMethodEnabledLocked(inputMethodInfo.getId(), false);
}
// Re-enable with default enabled IMEs.
- for (InputMethodInfo imi :
- InputMethodUtils.getDefaultEnabledImes(mContext, mMethodList)) {
+ for (InputMethodInfo imi : InputMethodInfoUtils.getDefaultEnabledImes(
+ mContext, mMethodList)) {
setInputMethodEnabledLocked(imi.getId(), true);
}
updateInputMethodsFromSettingsLocked(true /* enabledMayChange */);
@@ -6191,8 +6190,10 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub
mContext.getResources(), mContext.getContentResolver(), methodMap,
userId, false);
- nextEnabledImes = InputMethodUtils.getDefaultEnabledImes(mContext, methodList);
- nextIme = InputMethodUtils.getMostApplicableDefaultIME(nextEnabledImes).getId();
+ nextEnabledImes = InputMethodInfoUtils.getDefaultEnabledImes(mContext,
+ methodList);
+ nextIme = InputMethodInfoUtils.getMostApplicableDefaultIME(
+ nextEnabledImes).getId();
// Reset enabled IMEs.
settings.putEnabledInputMethodsStr("");
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
index c255fe14c03e..11e6923aa75a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodMenuController.java
@@ -105,7 +105,7 @@ final class InputMethodMenuController {
if (currentSubtype != null) {
final String curMethodId = mService.getSelectedMethodIdLocked();
final InputMethodInfo currentImi = mMethodMap.get(curMethodId);
- lastInputMethodSubtypeId = InputMethodUtils.getSubtypeIdFromHashCode(
+ lastInputMethodSubtypeId = SubtypeUtils.getSubtypeIdFromHashCode(
currentImi, currentSubtype.hashCode());
}
}
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
index f8894c64304d..a64322625797 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodSubtypeSwitchingController.java
@@ -241,8 +241,8 @@ final class InputMethodSubtypeSwitchingController {
}
private static int calculateSubtypeId(InputMethodInfo imi, InputMethodSubtype subtype) {
- return subtype != null ? InputMethodUtils.getSubtypeIdFromHashCode(imi,
- subtype.hashCode()) : NOT_A_SUBTYPE_ID;
+ return subtype != null ? SubtypeUtils.getSubtypeIdFromHashCode(imi, subtype.hashCode())
+ : NOT_A_SUBTYPE_ID;
}
private static class StaticRotationList {
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 2d1a22e7552d..70132670e68e 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -27,7 +27,6 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.os.Build;
-import android.os.LocaleList;
import android.os.UserHandle;
import android.provider.Settings;
import android.text.TextUtils;
@@ -40,8 +39,6 @@ import android.view.inputmethod.InputMethodInfo;
import android.view.inputmethod.InputMethodSubtype;
import android.view.textservice.SpellCheckerInfo;
-import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.inputmethod.StartInputFlags;
import com.android.server.LocalServices;
import com.android.server.pm.UserManagerInternal;
@@ -50,9 +47,7 @@ import com.android.server.textservices.TextServicesManagerInternal;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Locale;
import java.util.function.Predicate;
/**
@@ -66,40 +61,13 @@ import java.util.function.Predicate;
final class InputMethodUtils {
public static final boolean DEBUG = false;
static final int NOT_A_SUBTYPE_ID = -1;
- private static final String SUBTYPE_MODE_ANY = null;
- static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
private static final String TAG = "InputMethodUtils";
- private static final Locale ENGLISH_LOCALE = new Locale("en");
private static final String NOT_A_SUBTYPE_ID_STR = String.valueOf(NOT_A_SUBTYPE_ID);
- private static final String TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
- "EnabledWhenDefaultIsNotAsciiCapable";
// The string for enabled input method is saved as follows:
// example: ("ime0;subtype0;subtype1;subtype2:ime1:ime2;subtype0")
private static final char INPUT_METHOD_SEPARATOR = ':';
private static final char INPUT_METHOD_SUBTYPE_SEPARATOR = ';';
- /**
- * Used in {@link #getFallbackLocaleForDefaultIme(ArrayList, Context)} to find the fallback IMEs
- * that are mainly used until the system becomes ready. Note that {@link Locale} in this array
- * is checked with {@link Locale#equals(Object)}, which means that {@code Locale.ENGLISH}
- * doesn't automatically match {@code Locale("en", "IN")}.
- */
- private static final Locale[] SEARCH_ORDER_OF_FALLBACK_LOCALES = {
- Locale.ENGLISH, // "en"
- Locale.US, // "en_US"
- Locale.UK, // "en_GB"
- };
-
- // A temporary workaround for the performance concerns in
- // #getImplicitlyApplicableSubtypesLocked(Resources, InputMethodInfo).
- // TODO: Optimize all the critical paths including this one.
- private static final Object sCacheLock = new Object();
- @GuardedBy("sCacheLock")
- private static LocaleList sCachedSystemLocales;
- @GuardedBy("sCacheLock")
- private static InputMethodInfo sCachedInputMethodInfo;
- @GuardedBy("sCacheLock")
- private static ArrayList<InputMethodSubtype> sCachedResult;
private InputMethodUtils() {
// This utility class is not publicly instantiable.
@@ -130,533 +98,6 @@ final class InputMethodUtils {
}
// ----------------------------------------------------------------------
- private static boolean isSystemImeThatHasSubtypeOf(InputMethodInfo imi, Context context,
- boolean checkDefaultAttribute, @Nullable Locale requiredLocale, boolean checkCountry,
- String requiredSubtypeMode) {
- if (!imi.isSystem()) {
- return false;
- }
- if (checkDefaultAttribute && !imi.isDefault(context)) {
- return false;
- }
- if (!containsSubtypeOf(imi, requiredLocale, checkCountry, requiredSubtypeMode)) {
- return false;
- }
- return true;
- }
-
- @Nullable
- private static Locale getFallbackLocaleForDefaultIme(ArrayList<InputMethodInfo> imis,
- Context context) {
- // At first, find the fallback locale from the IMEs that are declared as "default" in the
- // current locale. Note that IME developers can declare an IME as "default" only for
- // some particular locales but "not default" for other locales.
- for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
- for (int i = 0; i < imis.size(); ++i) {
- if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
- true /* checkDefaultAttribute */, fallbackLocale,
- true /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
- return fallbackLocale;
- }
- }
- }
- // If no fallback locale is found in the above condition, find fallback locales regardless
- // of the "default" attribute as a last resort.
- for (final Locale fallbackLocale : SEARCH_ORDER_OF_FALLBACK_LOCALES) {
- for (int i = 0; i < imis.size(); ++i) {
- if (isSystemImeThatHasSubtypeOf(imis.get(i), context,
- false /* checkDefaultAttribute */, fallbackLocale,
- true /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
- return fallbackLocale;
- }
- }
- }
- Slog.w(TAG, "Found no fallback locale. imis=" + Arrays.toString(imis.toArray()));
- return null;
- }
-
- private static boolean isSystemAuxilialyImeThatHasAutomaticSubtype(InputMethodInfo imi,
- Context context, boolean checkDefaultAttribute) {
- if (!imi.isSystem()) {
- return false;
- }
- if (checkDefaultAttribute && !imi.isDefault(context)) {
- return false;
- }
- if (!imi.isAuxiliaryIme()) {
- return false;
- }
- final int subtypeCount = imi.getSubtypeCount();
- for (int i = 0; i < subtypeCount; ++i) {
- final InputMethodSubtype s = imi.getSubtypeAt(i);
- if (s.overridesImplicitlyEnabledSubtype()) {
- return true;
- }
- }
- return false;
- }
-
- private static Locale getSystemLocaleFromContext(Context context) {
- try {
- return context.getResources().getConfiguration().locale;
- } catch (Resources.NotFoundException ex) {
- return null;
- }
- }
-
- private static final class InputMethodListBuilder {
- // Note: We use LinkedHashSet instead of android.util.ArraySet because the enumeration
- // order can have non-trivial effect in the call sites.
- @NonNull
- private final LinkedHashSet<InputMethodInfo> mInputMethodSet = new LinkedHashSet<>();
-
- InputMethodListBuilder fillImes(ArrayList<InputMethodInfo> imis, Context context,
- boolean checkDefaultAttribute, @Nullable Locale locale, boolean checkCountry,
- String requiredSubtypeMode) {
- for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (isSystemImeThatHasSubtypeOf(imi, context, checkDefaultAttribute, locale,
- checkCountry, requiredSubtypeMode)) {
- mInputMethodSet.add(imi);
- }
- }
- return this;
- }
-
- // TODO: The behavior of InputMethodSubtype#overridesImplicitlyEnabledSubtype() should be
- // documented more clearly.
- InputMethodListBuilder fillAuxiliaryImes(ArrayList<InputMethodInfo> imis, Context context) {
- // If one or more auxiliary input methods are available, OK to stop populating the list.
- for (final InputMethodInfo imi : mInputMethodSet) {
- if (imi.isAuxiliaryIme()) {
- return this;
- }
- }
- boolean added = false;
- for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
- true /* checkDefaultAttribute */)) {
- mInputMethodSet.add(imi);
- added = true;
- }
- }
- if (added) {
- return this;
- }
- for (int i = 0; i < imis.size(); ++i) {
- final InputMethodInfo imi = imis.get(i);
- if (isSystemAuxilialyImeThatHasAutomaticSubtype(imi, context,
- false /* checkDefaultAttribute */)) {
- mInputMethodSet.add(imi);
- }
- }
- return this;
- }
-
- public boolean isEmpty() {
- return mInputMethodSet.isEmpty();
- }
-
- @NonNull
- public ArrayList<InputMethodInfo> build() {
- return new ArrayList<>(mInputMethodSet);
- }
- }
-
- private static InputMethodListBuilder getMinimumKeyboardSetWithSystemLocale(
- ArrayList<InputMethodInfo> imis, Context context, @Nullable Locale systemLocale,
- @Nullable Locale fallbackLocale) {
- // Once the system becomes ready, we pick up at least one keyboard in the following order.
- // Secondary users fall into this category in general.
- // 1. checkDefaultAttribute: true, locale: systemLocale, checkCountry: true
- // 2. checkDefaultAttribute: true, locale: systemLocale, checkCountry: false
- // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
- // 4. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
- // 5. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
- // 6. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: false
- // TODO: We should check isAsciiCapable instead of relying on fallbackLocale.
-
- final InputMethodListBuilder builder = new InputMethodListBuilder();
- builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
- true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
- false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
- true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
- false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
- true /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- builder.fillImes(imis, context, false /* checkDefaultAttribute */, fallbackLocale,
- false /* checkCountry */, SUBTYPE_MODE_KEYBOARD);
- if (!builder.isEmpty()) {
- return builder;
- }
- Slog.w(TAG, "No software keyboard is found. imis=" + Arrays.toString(imis.toArray())
- + " systemLocale=" + systemLocale + " fallbackLocale=" + fallbackLocale);
- return builder;
- }
-
- static ArrayList<InputMethodInfo> getDefaultEnabledImes(
- Context context, ArrayList<InputMethodInfo> imis, boolean onlyMinimum) {
- final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
- // We will primarily rely on the system locale, but also keep relying on the fallback locale
- // as a last resort.
- // Also pick up suitable IMEs regardless of the software keyboard support (e.g. Voice IMEs),
- // then pick up suitable auxiliary IMEs when necessary (e.g. Voice IMEs with "automatic"
- // subtype)
- final Locale systemLocale = getSystemLocaleFromContext(context);
- final InputMethodListBuilder builder =
- getMinimumKeyboardSetWithSystemLocale(imis, context, systemLocale, fallbackLocale);
- if (!onlyMinimum) {
- builder.fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
- true /* checkCountry */, SUBTYPE_MODE_ANY)
- .fillAuxiliaryImes(imis, context);
- }
- return builder.build();
- }
-
- static ArrayList<InputMethodInfo> getDefaultEnabledImes(
- Context context, ArrayList<InputMethodInfo> imis) {
- return getDefaultEnabledImes(context, imis, false /* onlyMinimum */);
- }
-
- /**
- * Chooses an eligible system voice IME from the given IMEs.
- *
- * @param methodMap Map from the IME ID to {@link InputMethodInfo}.
- * @param systemSpeechRecognizerPackageName System speech recognizer configured by the system
- * config.
- * @param currentDefaultVoiceImeId IME ID currently set to
- * {@link Settings.Secure#DEFAULT_VOICE_INPUT_METHOD}
- * @return {@link InputMethodInfo} that is found in {@code methodMap} and most suitable for
- * the system voice IME.
- */
- @Nullable
- static InputMethodInfo chooseSystemVoiceIme(
- @NonNull ArrayMap<String, InputMethodInfo> methodMap,
- @Nullable String systemSpeechRecognizerPackageName,
- @Nullable String currentDefaultVoiceImeId) {
- if (TextUtils.isEmpty(systemSpeechRecognizerPackageName)) {
- return null;
- }
- final InputMethodInfo defaultVoiceIme = methodMap.get(currentDefaultVoiceImeId);
- // If the config matches the package of the setting, use the current one.
- if (defaultVoiceIme != null && defaultVoiceIme.isSystem()
- && defaultVoiceIme.getPackageName().equals(systemSpeechRecognizerPackageName)) {
- return defaultVoiceIme;
- }
- InputMethodInfo firstMatchingIme = null;
- final int methodCount = methodMap.size();
- for (int i = 0; i < methodCount; ++i) {
- final InputMethodInfo imi = methodMap.valueAt(i);
- if (!imi.isSystem()) {
- continue;
- }
- if (!TextUtils.equals(imi.getPackageName(), systemSpeechRecognizerPackageName)) {
- continue;
- }
- if (firstMatchingIme != null) {
- Slog.e(TAG, "At most one InputMethodService can be published in "
- + "systemSpeechRecognizer: " + systemSpeechRecognizerPackageName
- + ". Ignoring all of them.");
- return null;
- }
- firstMatchingIme = imi;
- }
- return firstMatchingIme;
- }
-
- static boolean containsSubtypeOf(InputMethodInfo imi, @Nullable Locale locale,
- boolean checkCountry, String mode) {
- if (locale == null) {
- return false;
- }
- final int N = imi.getSubtypeCount();
- for (int i = 0; i < N; ++i) {
- final InputMethodSubtype subtype = imi.getSubtypeAt(i);
- if (checkCountry) {
- final Locale subtypeLocale = subtype.getLocaleObject();
- if (subtypeLocale == null ||
- !TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage()) ||
- !TextUtils.equals(subtypeLocale.getCountry(), locale.getCountry())) {
- continue;
- }
- } else {
- final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
- subtype.getLocale()));
- if (!TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage())) {
- continue;
- }
- }
- if (mode == SUBTYPE_MODE_ANY || TextUtils.isEmpty(mode) ||
- mode.equalsIgnoreCase(subtype.getMode())) {
- return true;
- }
- }
- return false;
- }
-
- static ArrayList<InputMethodSubtype> getSubtypes(InputMethodInfo imi) {
- ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
- final int subtypeCount = imi.getSubtypeCount();
- for (int i = 0; i < subtypeCount; ++i) {
- subtypes.add(imi.getSubtypeAt(i));
- }
- return subtypes;
- }
-
- static InputMethodInfo getMostApplicableDefaultIME(List<InputMethodInfo> enabledImes) {
- if (enabledImes == null || enabledImes.isEmpty()) {
- return null;
- }
- // We'd prefer to fall back on a system IME, since that is safer.
- int i = enabledImes.size();
- int firstFoundSystemIme = -1;
- while (i > 0) {
- i--;
- final InputMethodInfo imi = enabledImes.get(i);
- if (imi.isAuxiliaryIme()) {
- continue;
- }
- if (imi.isSystem() && containsSubtypeOf(
- imi, ENGLISH_LOCALE, false /* checkCountry */, SUBTYPE_MODE_KEYBOARD)) {
- return imi;
- }
- if (firstFoundSystemIme < 0 && imi.isSystem()) {
- firstFoundSystemIme = i;
- }
- }
- return enabledImes.get(Math.max(firstFoundSystemIme, 0));
- }
-
- static boolean isValidSubtypeId(InputMethodInfo imi, int subtypeHashCode) {
- return getSubtypeIdFromHashCode(imi, subtypeHashCode) != NOT_A_SUBTYPE_ID;
- }
-
- static int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) {
- if (imi != null) {
- final int subtypeCount = imi.getSubtypeCount();
- for (int i = 0; i < subtypeCount; ++i) {
- InputMethodSubtype ims = imi.getSubtypeAt(i);
- if (subtypeHashCode == ims.hashCode()) {
- return i;
- }
- }
- }
- 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
- static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
- Resources res, InputMethodInfo imi) {
- final LocaleList systemLocales = res.getConfiguration().getLocales();
-
- synchronized (sCacheLock) {
- // We intentionally do not use InputMethodInfo#equals(InputMethodInfo) here because
- // it does not check if subtypes are also identical.
- if (systemLocales.equals(sCachedSystemLocales) && sCachedInputMethodInfo == imi) {
- return new ArrayList<>(sCachedResult);
- }
- }
-
- // Note: Only resource info in "res" is used in getImplicitlyApplicableSubtypesLockedImpl().
- // TODO: Refactor getImplicitlyApplicableSubtypesLockedImpl() so that it can receive
- // LocaleList rather than Resource.
- final ArrayList<InputMethodSubtype> result =
- getImplicitlyApplicableSubtypesLockedImpl(res, imi);
- synchronized (sCacheLock) {
- // Both LocaleList and InputMethodInfo are immutable. No need to copy them here.
- sCachedSystemLocales = systemLocales;
- sCachedInputMethodInfo = imi;
- sCachedResult = new ArrayList<>(result);
- }
- return result;
- }
-
- private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLockedImpl(
- Resources res, InputMethodInfo imi) {
- final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
- final LocaleList systemLocales = res.getConfiguration().getLocales();
- final String systemLocale = systemLocales.get(0).toString();
- if (TextUtils.isEmpty(systemLocale)) return new ArrayList<>();
- final int numSubtypes = subtypes.size();
-
- // Handle overridesImplicitlyEnabledSubtype mechanism.
- final ArrayMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new ArrayMap<>();
- for (int i = 0; i < numSubtypes; ++i) {
- // scan overriding implicitly enabled subtypes.
- final InputMethodSubtype subtype = subtypes.get(i);
- if (subtype.overridesImplicitlyEnabledSubtype()) {
- final String mode = subtype.getMode();
- if (!applicableModeAndSubtypesMap.containsKey(mode)) {
- applicableModeAndSubtypesMap.put(mode, subtype);
- }
- }
- }
- if (applicableModeAndSubtypesMap.size() > 0) {
- return new ArrayList<>(applicableModeAndSubtypesMap.values());
- }
-
- final ArrayMap<String, ArrayList<InputMethodSubtype>> nonKeyboardSubtypesMap =
- new ArrayMap<>();
- final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>();
-
- for (int i = 0; i < numSubtypes; ++i) {
- final InputMethodSubtype subtype = subtypes.get(i);
- final String mode = subtype.getMode();
- if (SUBTYPE_MODE_KEYBOARD.equals(mode)) {
- keyboardSubtypes.add(subtype);
- } else {
- if (!nonKeyboardSubtypesMap.containsKey(mode)) {
- nonKeyboardSubtypesMap.put(mode, new ArrayList<>());
- }
- nonKeyboardSubtypesMap.get(mode).add(subtype);
- }
- }
-
- final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>();
- LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales,
- applicableSubtypes);
-
- if (!applicableSubtypes.isEmpty()) {
- boolean hasAsciiCapableKeyboard = false;
- final int numApplicationSubtypes = applicableSubtypes.size();
- for (int i = 0; i < numApplicationSubtypes; ++i) {
- final InputMethodSubtype subtype = applicableSubtypes.get(i);
- if (subtype.isAsciiCapable()) {
- 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)) {
- applicableSubtypes.add(subtype);
- }
- }
- }
- }
-
- if (applicableSubtypes.isEmpty()) {
- InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
- res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
- if (lastResortKeyboardSubtype != null) {
- applicableSubtypes.add(lastResortKeyboardSubtype);
- }
- }
-
- // 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;
- }
-
- /**
- * Returns the language component of a given locale string.
- * TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(String)}
- */
- private static String getLanguageFromLocaleString(String locale) {
- final int idx = locale.indexOf('_');
- if (idx < 0) {
- return locale;
- } else {
- return locale.substring(0, idx);
- }
- }
-
- /**
- * If there are no selected subtypes, tries finding the most applicable one according to the
- * given locale.
- * @param subtypes this function will search the most applicable subtype in subtypes
- * @param mode subtypes will be filtered by mode
- * @param locale subtypes will be filtered by locale
- * @param canIgnoreLocaleAsLastResort if this function can't find the most applicable subtype,
- * it will return the first subtype matched with mode
- * @return the most applicable subtypeId
- */
- static InputMethodSubtype findLastResortApplicableSubtypeLocked(
- Resources res, List<InputMethodSubtype> subtypes, String mode, String locale,
- boolean canIgnoreLocaleAsLastResort) {
- if (subtypes == null || subtypes.size() == 0) {
- return null;
- }
- if (TextUtils.isEmpty(locale)) {
- locale = res.getConfiguration().locale.toString();
- }
- final String language = getLanguageFromLocaleString(locale);
- boolean partialMatchFound = false;
- InputMethodSubtype applicableSubtype = null;
- InputMethodSubtype firstMatchedModeSubtype = null;
- final int N = subtypes.size();
- for (int i = 0; i < N; ++i) {
- InputMethodSubtype subtype = subtypes.get(i);
- final String subtypeLocale = subtype.getLocale();
- final String subtypeLanguage = getLanguageFromLocaleString(subtypeLocale);
- // An applicable subtype should match "mode". If mode is null, mode will be ignored,
- // and all subtypes with all modes can be candidates.
- if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
- if (firstMatchedModeSubtype == null) {
- firstMatchedModeSubtype = subtype;
- }
- if (locale.equals(subtypeLocale)) {
- // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
- applicableSubtype = subtype;
- break;
- } else if (!partialMatchFound && language.equals(subtypeLanguage)) {
- // Partial match (e.g. system locale is "en_US" and subtype locale is "en")
- applicableSubtype = subtype;
- partialMatchFound = true;
- }
- }
- }
-
- if (applicableSubtype == null && canIgnoreLocaleAsLastResort) {
- return firstMatchedModeSubtype;
- }
-
- // The first subtype applicable to the system locale will be defined as the most applicable
- // subtype.
- if (DEBUG) {
- if (applicableSubtype != null) {
- Slog.d(TAG, "Applicable InputMethodSubtype was found: "
- + applicableSubtype.getMode() + "," + applicableSubtype.getLocale());
- }
- }
- return applicableSubtype;
- }
-
static boolean canAddToLastInputMethod(InputMethodSubtype subtype) {
if (subtype == null) return true;
return !subtype.isAuxiliary();
@@ -790,6 +231,7 @@ final class InputMethodUtils {
/**
* Utility class for putting and getting settings for InputMethod
* TODO: Move all putters and getters of settings to this class.
+ * TODO(b/235661780): Make the setting supports multi-users.
*/
public static class InputMethodSettings {
private final TextUtils.SimpleStringSplitter mInputMethodSplitter =
@@ -967,7 +409,7 @@ final class InputMethodUtils {
List<InputMethodSubtype> enabledSubtypes =
getEnabledInputMethodSubtypeListLocked(imi);
if (allowsImplicitlySelectedSubtypes && enabledSubtypes.isEmpty()) {
- enabledSubtypes = InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ enabledSubtypes = SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
context.getResources(), imi);
}
return InputMethodSubtype.sort(context, 0, imi, enabledSubtypes);
@@ -1198,7 +640,7 @@ final class InputMethodUtils {
// are enabled implicitly, so needs to treat them to be enabled.
if (imi != null && imi.getSubtypeCount() > 0) {
List<InputMethodSubtype> implicitlySelectedSubtypes =
- getImplicitlyApplicableSubtypesLocked(mRes, imi);
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(mRes, imi);
if (implicitlySelectedSubtypes != null) {
final int N = implicitlySelectedSubtypes.size();
for (int i = 0; i < N; ++i) {
@@ -1216,7 +658,7 @@ final class InputMethodUtils {
try {
final int hashCode = Integer.parseInt(subtypeHashCode);
// Check whether the subtype id is valid or not
- if (isValidSubtypeId(imi, hashCode)) {
+ if (SubtypeUtils.isValidSubtypeId(imi, hashCode)) {
return s;
} else {
return NOT_A_SUBTYPE_ID_STR;
@@ -1336,7 +778,7 @@ final class InputMethodUtils {
return NOT_A_SUBTYPE_ID;
}
final int subtypeHashCode = getSelectedInputMethodSubtypeHashCode();
- return getSubtypeIdFromHashCode(imi, subtypeHashCode);
+ return SubtypeUtils.getSubtypeIdFromHashCode(imi, subtypeHashCode);
}
void saveCurrentInputMethodAndSubtypeToHistory(String curMethodId,
diff --git a/services/core/java/com/android/server/inputmethod/LocaleUtils.java b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
index 7a6853a25e5b..3d02b3af6bc1 100644
--- a/services/core/java/com/android/server/inputmethod/LocaleUtils.java
+++ b/services/core/java/com/android/server/inputmethod/LocaleUtils.java
@@ -19,6 +19,8 @@ package com.android.server.inputmethod;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
import android.icu.util.ULocale;
import android.os.LocaleList;
import android.text.TextUtils;
@@ -207,4 +209,25 @@ final class LocaleUtils {
dest.add(sources.get(entry.mIndex));
}
}
+
+ /**
+ * Returns the language component of a given locale string.
+ * TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(String)}
+ */
+ static String getLanguageFromLocaleString(String locale) {
+ final int idx = locale.indexOf('_');
+ if (idx < 0) {
+ return locale;
+ } else {
+ return locale.substring(0, idx);
+ }
+ }
+
+ static Locale getSystemLocaleFromContext(Context context) {
+ try {
+ return context.getResources().getConfiguration().locale;
+ } catch (Resources.NotFoundException ex) {
+ return null;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/inputmethod/SubtypeUtils.java b/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
new file mode 100644
index 000000000000..eb85dd011288
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/SubtypeUtils.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.inputmethod;
+
+import android.annotation.Nullable;
+import android.content.res.Resources;
+import android.os.LocaleList;
+import android.text.TextUtils;
+import android.util.ArrayMap;
+import android.util.Slog;
+import android.view.inputmethod.InputMethodInfo;
+import android.view.inputmethod.InputMethodSubtype;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+/**
+ * This class provides utility methods to handle and manage {@link InputMethodSubtype} for
+ * {@link InputMethodManagerService}.
+ *
+ * <p>This class is intentionally package-private. Utility methods here are tightly coupled with
+ * implementation details in {@link InputMethodManagerService}. Hence this class is not suitable
+ * for other components to directly use.</p>
+ */
+final class SubtypeUtils {
+ private static final String TAG = "SubtypeUtils";
+ public static final boolean DEBUG = false;
+
+ static final String SUBTYPE_MODE_ANY = null;
+ static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
+
+ static final int NOT_A_SUBTYPE_ID = -1;
+ private static final String TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
+ "EnabledWhenDefaultIsNotAsciiCapable";
+
+ // A temporary workaround for the performance concerns in
+ // #getImplicitlyApplicableSubtypesLocked(Resources, InputMethodInfo).
+ // TODO: Optimize all the critical paths including this one.
+ // TODO(b/235661780): Make the cache supports multi-users.
+ private static final Object sCacheLock = new Object();
+ @GuardedBy("sCacheLock")
+ private static LocaleList sCachedSystemLocales;
+ @GuardedBy("sCacheLock")
+ private static InputMethodInfo sCachedInputMethodInfo;
+ @GuardedBy("sCacheLock")
+ private static ArrayList<InputMethodSubtype> sCachedResult;
+
+ static boolean containsSubtypeOf(InputMethodInfo imi, @Nullable Locale locale,
+ boolean checkCountry, String mode) {
+ if (locale == null) {
+ return false;
+ }
+ final int N = imi.getSubtypeCount();
+ for (int i = 0; i < N; ++i) {
+ final InputMethodSubtype subtype = imi.getSubtypeAt(i);
+ if (checkCountry) {
+ final Locale subtypeLocale = subtype.getLocaleObject();
+ if (subtypeLocale == null ||
+ !TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage()) ||
+ !TextUtils.equals(subtypeLocale.getCountry(), locale.getCountry())) {
+ continue;
+ }
+ } else {
+ final Locale subtypeLocale = new Locale(LocaleUtils.getLanguageFromLocaleString(
+ subtype.getLocale()));
+ if (!TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage())) {
+ continue;
+ }
+ }
+ if (mode == SUBTYPE_MODE_ANY || TextUtils.isEmpty(mode) ||
+ mode.equalsIgnoreCase(subtype.getMode())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static ArrayList<InputMethodSubtype> getSubtypes(InputMethodInfo imi) {
+ ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+ final int subtypeCount = imi.getSubtypeCount();
+ for (int i = 0; i < subtypeCount; ++i) {
+ subtypes.add(imi.getSubtypeAt(i));
+ }
+ return subtypes;
+ }
+
+ static boolean isValidSubtypeId(InputMethodInfo imi, int subtypeHashCode) {
+ return getSubtypeIdFromHashCode(imi, subtypeHashCode) != NOT_A_SUBTYPE_ID;
+ }
+
+ static int getSubtypeIdFromHashCode(InputMethodInfo imi, int subtypeHashCode) {
+ if (imi != null) {
+ final int subtypeCount = imi.getSubtypeCount();
+ for (int i = 0; i < subtypeCount; ++i) {
+ InputMethodSubtype ims = imi.getSubtypeAt(i);
+ if (subtypeHashCode == ims.hashCode()) {
+ return i;
+ }
+ }
+ }
+ return NOT_A_SUBTYPE_ID;
+ }
+
+ private static final LocaleUtils.LocaleExtractor<InputMethodSubtype> sSubtypeToLocale =
+ source -> source != null ? source.getLocaleObject() : null;
+
+ @VisibleForTesting
+ static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
+ Resources res, InputMethodInfo imi) {
+ final LocaleList systemLocales = res.getConfiguration().getLocales();
+
+ synchronized (sCacheLock) {
+ // We intentionally do not use InputMethodInfo#equals(InputMethodInfo) here because
+ // it does not check if subtypes are also identical.
+ if (systemLocales.equals(sCachedSystemLocales) && sCachedInputMethodInfo == imi) {
+ return new ArrayList<>(sCachedResult);
+ }
+ }
+
+ // Note: Only resource info in "res" is used in getImplicitlyApplicableSubtypesLockedImpl().
+ // TODO: Refactor getImplicitlyApplicableSubtypesLockedImpl() so that it can receive
+ // LocaleList rather than Resource.
+ final ArrayList<InputMethodSubtype> result =
+ getImplicitlyApplicableSubtypesLockedImpl(res, imi);
+ synchronized (sCacheLock) {
+ // Both LocaleList and InputMethodInfo are immutable. No need to copy them here.
+ sCachedSystemLocales = systemLocales;
+ sCachedInputMethodInfo = imi;
+ sCachedResult = new ArrayList<>(result);
+ }
+ return result;
+ }
+
+ private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLockedImpl(
+ Resources res, InputMethodInfo imi) {
+ final List<InputMethodSubtype> subtypes = getSubtypes(imi);
+ final LocaleList systemLocales = res.getConfiguration().getLocales();
+ final String systemLocale = systemLocales.get(0).toString();
+ if (TextUtils.isEmpty(systemLocale)) return new ArrayList<>();
+ final int numSubtypes = subtypes.size();
+
+ // Handle overridesImplicitlyEnabledSubtype mechanism.
+ final ArrayMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new ArrayMap<>();
+ for (int i = 0; i < numSubtypes; ++i) {
+ // scan overriding implicitly enabled subtypes.
+ final InputMethodSubtype subtype = subtypes.get(i);
+ if (subtype.overridesImplicitlyEnabledSubtype()) {
+ final String mode = subtype.getMode();
+ if (!applicableModeAndSubtypesMap.containsKey(mode)) {
+ applicableModeAndSubtypesMap.put(mode, subtype);
+ }
+ }
+ }
+ if (applicableModeAndSubtypesMap.size() > 0) {
+ return new ArrayList<>(applicableModeAndSubtypesMap.values());
+ }
+
+ final ArrayMap<String, ArrayList<InputMethodSubtype>> nonKeyboardSubtypesMap =
+ new ArrayMap<>();
+ final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>();
+
+ for (int i = 0; i < numSubtypes; ++i) {
+ final InputMethodSubtype subtype = subtypes.get(i);
+ final String mode = subtype.getMode();
+ if (SUBTYPE_MODE_KEYBOARD.equals(mode)) {
+ keyboardSubtypes.add(subtype);
+ } else {
+ if (!nonKeyboardSubtypesMap.containsKey(mode)) {
+ nonKeyboardSubtypesMap.put(mode, new ArrayList<>());
+ }
+ nonKeyboardSubtypesMap.get(mode).add(subtype);
+ }
+ }
+
+ final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>();
+ LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales,
+ applicableSubtypes);
+
+ if (!applicableSubtypes.isEmpty()) {
+ boolean hasAsciiCapableKeyboard = false;
+ final int numApplicationSubtypes = applicableSubtypes.size();
+ for (int i = 0; i < numApplicationSubtypes; ++i) {
+ final InputMethodSubtype subtype = applicableSubtypes.get(i);
+ if (subtype.isAsciiCapable()) {
+ 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)) {
+ applicableSubtypes.add(subtype);
+ }
+ }
+ }
+ }
+
+ if (applicableSubtypes.isEmpty()) {
+ InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
+ res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
+ if (lastResortKeyboardSubtype != null) {
+ applicableSubtypes.add(lastResortKeyboardSubtype);
+ }
+ }
+
+ // 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;
+ }
+
+ /**
+ * If there are no selected subtypes, tries finding the most applicable one according to the
+ * given locale.
+ * @param subtypes this function will search the most applicable subtype in subtypes
+ * @param mode subtypes will be filtered by mode
+ * @param locale subtypes will be filtered by locale
+ * @param canIgnoreLocaleAsLastResort if this function can't find the most applicable subtype,
+ * it will return the first subtype matched with mode
+ * @return the most applicable subtypeId
+ */
+ static InputMethodSubtype findLastResortApplicableSubtypeLocked(
+ Resources res, List<InputMethodSubtype> subtypes, String mode, String locale,
+ boolean canIgnoreLocaleAsLastResort) {
+ if (subtypes == null || subtypes.size() == 0) {
+ return null;
+ }
+ if (TextUtils.isEmpty(locale)) {
+ locale = res.getConfiguration().locale.toString();
+ }
+ final String language = LocaleUtils.getLanguageFromLocaleString(locale);
+ boolean partialMatchFound = false;
+ InputMethodSubtype applicableSubtype = null;
+ InputMethodSubtype firstMatchedModeSubtype = null;
+ final int N = subtypes.size();
+ for (int i = 0; i < N; ++i) {
+ InputMethodSubtype subtype = subtypes.get(i);
+ final String subtypeLocale = subtype.getLocale();
+ final String subtypeLanguage = LocaleUtils.getLanguageFromLocaleString(subtypeLocale);
+ // An applicable subtype should match "mode". If mode is null, mode will be ignored,
+ // and all subtypes with all modes can be candidates.
+ if (mode == null || subtypes.get(i).getMode().equalsIgnoreCase(mode)) {
+ if (firstMatchedModeSubtype == null) {
+ firstMatchedModeSubtype = subtype;
+ }
+ if (locale.equals(subtypeLocale)) {
+ // Exact match (e.g. system locale is "en_US" and subtype locale is "en_US")
+ applicableSubtype = subtype;
+ break;
+ } else if (!partialMatchFound && language.equals(subtypeLanguage)) {
+ // Partial match (e.g. system locale is "en_US" and subtype locale is "en")
+ applicableSubtype = subtype;
+ partialMatchFound = true;
+ }
+ }
+ }
+
+ if (applicableSubtype == null && canIgnoreLocaleAsLastResort) {
+ return firstMatchedModeSubtype;
+ }
+
+ // The first subtype applicable to the system locale will be defined as the most applicable
+ // subtype.
+ if (DEBUG) {
+ if (applicableSubtype != null) {
+ Slog.d(TAG, "Applicable InputMethodSubtype was found: "
+ + applicableSubtype.getMode() + "," + applicableSubtype.getLocale());
+ }
+ }
+ return applicableSubtype;
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
index 6f1268e5de24..cc6f2cc5ba3e 100644
--- a/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/inputmethod/InputMethodUtilsTest.java
@@ -275,7 +275,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_EN_US), imi);
assertEquals(1, result.size());
verifyEquality(autoSubtype, result.get(0));
@@ -299,7 +299,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_EN_US), imi);
assertEquals(2, result.size());
verifyEquality(nonAutoEnUS, result.get(0));
@@ -323,7 +323,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_EN_GB), imi);
assertEquals(2, result.size());
verifyEquality(nonAutoEnGB, result.get(0));
@@ -348,7 +348,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_FR), imi);
assertEquals(2, result.size());
verifyEquality(nonAutoFrCA, result.get(0));
@@ -369,7 +369,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_FR_CA), imi);
assertEquals(2, result.size());
verifyEquality(nonAutoFrCA, result.get(0));
@@ -391,7 +391,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_JA_JP), imi);
assertEquals(3, result.size());
verifyEquality(nonAutoJa, result.get(0));
@@ -413,7 +413,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_JA_JP), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoHi, result.get(0));
@@ -430,7 +430,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_JA_JP), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoEnUS, result.get(0));
@@ -447,7 +447,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_JA_JP), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoEnUS, result.get(0));
@@ -469,7 +469,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(Locale.forLanguageTag("sr-Latn-RS")), imi);
assertEquals(2, result.size());
assertThat(nonAutoSrLatn, is(in(result)));
@@ -489,7 +489,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(Locale.forLanguageTag("sr-Cyrl-RS")), imi);
assertEquals(2, result.size());
assertThat(nonAutoSrCyrl, is(in(result)));
@@ -515,7 +515,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(
Locale.forLanguageTag("sr-Latn-RS-x-android"),
Locale.forLanguageTag("ja-JP"),
@@ -542,7 +542,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_FIL_PH), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoFil, result.get(0));
@@ -560,7 +560,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_FI), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoJa, result.get(0));
@@ -576,7 +576,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_IN), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoIn, result.get(0));
@@ -590,7 +590,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_ID), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoIn, result.get(0));
@@ -604,7 +604,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_IN), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoId, result.get(0));
@@ -618,7 +618,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_ID), imi);
assertEquals(1, result.size());
verifyEquality(nonAutoId, result.get(0));
@@ -640,7 +640,7 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
final ArrayList<InputMethodSubtype> result =
- InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+ SubtypeUtils.getImplicitlyApplicableSubtypesLocked(
getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
assertThat(nonAutoFrCA, is(in(result)));
assertThat(nonAutoEnUS, is(in(result)));
@@ -680,26 +680,26 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
SUBTYPE_MODE_VOICE));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
SUBTYPE_MODE_VOICE));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
SUBTYPE_MODE_ANY));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
SUBTYPE_MODE_ANY));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
}
@@ -711,22 +711,22 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin",
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
}
@@ -738,22 +738,22 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin",
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+ assertFalse(SubtypeUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
}
@@ -766,13 +766,13 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin",
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
}
@@ -785,13 +785,13 @@ public class InputMethodUtilsTest {
"com.android.apps.inputmethod.latin",
"com.android.apps.inputmethod.latin", "FakeLatinIme", !IS_AUX, IS_DEFAULT,
subtypes);
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
- assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+ assertTrue(SubtypeUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
SUBTYPE_MODE_KEYBOARD));
}
}
@@ -805,19 +805,19 @@ public class InputMethodUtilsTest {
{
final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
methodMap.put(systemIme.getId(), systemIme);
- assertNull(InputMethodUtils.chooseSystemVoiceIme(methodMap, null, ""));
+ assertNull(InputMethodInfoUtils.chooseSystemVoiceIme(methodMap, null, ""));
}
// Returns null when the config value is empty.
{
final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
methodMap.put(systemIme.getId(), systemIme);
- assertNull(InputMethodUtils.chooseSystemVoiceIme(methodMap, "", ""));
+ assertNull(InputMethodInfoUtils.chooseSystemVoiceIme(methodMap, "", ""));
}
// Returns null when the configured package doesn't have an IME.
{
- assertNull(InputMethodUtils.chooseSystemVoiceIme(new ArrayMap<>(),
+ assertNull(InputMethodInfoUtils.chooseSystemVoiceIme(new ArrayMap<>(),
systemIme.getPackageName(), ""));
}
@@ -825,7 +825,7 @@ public class InputMethodUtilsTest {
{
final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
methodMap.put(systemIme.getId(), systemIme);
- assertEquals(systemIme, InputMethodUtils.chooseSystemVoiceIme(methodMap,
+ assertEquals(systemIme, InputMethodInfoUtils.chooseSystemVoiceIme(methodMap,
systemIme.getPackageName(), null));
}
@@ -833,13 +833,13 @@ public class InputMethodUtilsTest {
{
final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
methodMap.put(systemIme.getId(), systemIme);
- assertEquals(systemIme, InputMethodUtils.chooseSystemVoiceIme(methodMap,
+ assertEquals(systemIme, InputMethodInfoUtils.chooseSystemVoiceIme(methodMap,
systemIme.getPackageName(), ""));
}
// Returns null when the current default isn't found.
{
- assertNull(InputMethodUtils.chooseSystemVoiceIme(new ArrayMap<>(),
+ assertNull(InputMethodInfoUtils.chooseSystemVoiceIme(new ArrayMap<>(),
systemIme.getPackageName(), systemIme.getId()));
}
@@ -850,8 +850,8 @@ public class InputMethodUtilsTest {
final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
methodMap.put(systemIme.getId(), systemIme);
methodMap.put(secondIme.getId(), secondIme);
- assertNull(InputMethodUtils.chooseSystemVoiceIme(methodMap, systemIme.getPackageName(),
- ""));
+ assertNull(InputMethodInfoUtils.chooseSystemVoiceIme(methodMap,
+ systemIme.getPackageName(), ""));
}
// Returns the current one when the current default and config point to the same package.
@@ -861,7 +861,7 @@ public class InputMethodUtilsTest {
final ArrayMap<String, InputMethodInfo> methodMap = new ArrayMap<>();
methodMap.put(systemIme.getId(), systemIme);
methodMap.put(secondIme.getId(), secondIme);
- assertEquals(systemIme, InputMethodUtils.chooseSystemVoiceIme(methodMap,
+ assertEquals(systemIme, InputMethodInfoUtils.chooseSystemVoiceIme(methodMap,
systemIme.getPackageName(), systemIme.getId()));
}
@@ -871,7 +871,7 @@ public class InputMethodUtilsTest {
final InputMethodInfo nonSystemIme = createFakeInputMethodInfo("NonSystemIme",
"fake.voice0", false /* isSystem */);
methodMap.put(nonSystemIme.getId(), nonSystemIme);
- assertNull(InputMethodUtils.chooseSystemVoiceIme(methodMap,
+ assertNull(InputMethodInfoUtils.chooseSystemVoiceIme(methodMap,
nonSystemIme.getPackageName(), nonSystemIme.getId()));
}
@@ -882,7 +882,7 @@ public class InputMethodUtilsTest {
"FakeDefaultAutoVoiceIme", "fake.voice0", false /* isSystem */);
methodMap.put(systemIme.getId(), systemIme);
methodMap.put(nonSystemIme.getId(), nonSystemIme);
- assertNull(InputMethodUtils.chooseSystemVoiceIme(methodMap,
+ assertNull(InputMethodInfoUtils.chooseSystemVoiceIme(methodMap,
nonSystemIme.getPackageName(), ""));
}
}
@@ -891,7 +891,7 @@ public class InputMethodUtilsTest {
final Locale systemLocale, String... expectedImeNames) {
final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
final String[] actualImeNames = getPackageNames(
- InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes));
+ InputMethodInfoUtils.getDefaultEnabledImes(context, preinstalledImes));
assertEquals(expectedImeNames.length, actualImeNames.length);
for (int i = 0; i < expectedImeNames.length; ++i) {
assertEquals(expectedImeNames[i], actualImeNames[i]);
@@ -902,7 +902,7 @@ public class InputMethodUtilsTest {
final Locale systemLocale, String... expectedImeNames) {
final Context context = createTargetContextWithLocales(new LocaleList(systemLocale));
final String[] actualImeNames = getPackageNames(
- InputMethodUtils.getDefaultEnabledImes(context, preinstalledImes,
+ InputMethodInfoUtils.getDefaultEnabledImes(context, preinstalledImes,
true /* onlyMinimum */));
assertEquals(expectedImeNames.length, actualImeNames.length);
for (int i = 0; i < expectedImeNames.length; ++i) {