FileDocCategorySizeDatePackage
InputMethodUtils.javaAPI DocAndroid 5.1 API58872Thu Mar 12 22:22:10 GMT 2015com.android.internal.inputmethod

InputMethodUtils

public class InputMethodUtils extends Object
InputMethodManagerUtils contains some static methods that provides IME informations. This methods are supposed to be used in both the framework and the Settings application.

Fields Summary
public static final boolean
DEBUG
public static final int
NOT_A_SUBTYPE_ID
public static final String
SUBTYPE_MODE_ANY
public static final String
SUBTYPE_MODE_KEYBOARD
public static final String
SUBTYPE_MODE_VOICE
private static final String
TAG
private static final Locale
ENGLISH_LOCALE
private static final String
NOT_A_SUBTYPE_ID_STR
private static final String
TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE
private static final String
TAG_ASCII_CAPABLE
private static final Locale[]
SEARCH_ORDER_OF_FALLBACK_LOCALES
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")}.
Constructors Summary
private InputMethodUtils()


      
        // This utility class is not publicly instantiable.
    
Methods Summary
public static booleancanAddToLastInputMethod(android.view.inputmethod.InputMethodSubtype subtype)

        if (subtype == null) return true;
        return !subtype.isAuxiliary();
    
public static booleancheckIfPackageBelongsToUid(android.app.AppOpsManager appOpsManager, int uid, java.lang.String packageName)
Returns true if a package name belongs to a UID.

This is a simple wrapper of {@link AppOpsManager#checkPackage(int, String)}.

param
appOpsManager the {@link AppOpsManager} object to be used for the validation.
param
uid the UID to be validated.
param
packageName the package name.
return
{@code true} if the package name belongs to the UID.

        try {
            appOpsManager.checkPackage(uid, packageName);
            return true;
        } catch (SecurityException e) {
            return false;
        }
    
public static booleancontainsSubtypeOf(android.view.inputmethod.InputMethodInfo imi, java.util.Locale locale, boolean checkCountry, java.lang.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) {
                // TODO: Use {@link Locale#toLanguageTag()} and
                // {@link Locale#forLanguageTag(languageTag)} instead.
                if (!TextUtils.equals(subtype.getLocale(), locale.toString())) {
                    continue;
                }
            } else {
                final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
                        subtype.getLocale()));
                if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
                    continue;
                }
            }
            if (mode == SUBTYPE_MODE_ANY || TextUtils.isEmpty(mode) ||
                    mode.equalsIgnoreCase(subtype.getMode())) {
                return true;
            }
        }
        return false;
    
public static booleancontainsSubtypeOf(android.view.inputmethod.InputMethodInfo imi, java.lang.String language, java.lang.String mode)

deprecated
Use {@link #containsSubtypeOf(InputMethodInfo, Locale, boolean, String)} instead.

        final int N = imi.getSubtypeCount();
        for (int i = 0; i < N; ++i) {
            final InputMethodSubtype subtype = imi.getSubtypeAt(i);
            if (!subtype.getLocale().startsWith(language)) {
                continue;
            }
            if (mode == SUBTYPE_MODE_ANY || TextUtils.isEmpty(mode) ||
                    mode.equalsIgnoreCase(subtype.getMode())) {
                return true;
            }
        }
        return false;
    
public static android.view.inputmethod.InputMethodSubtypefindLastResortApplicableSubtypeLocked(android.content.res.Resources res, java.util.List subtypes, java.lang.String mode, java.lang.String locale, boolean canIgnoreLocaleAsLastResort)
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

        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;
    
public static java.lang.StringgetApiCallStack()

        String apiCallStack = "";
        try {
            throw new RuntimeException();
        } catch (RuntimeException e) {
            final StackTraceElement[] frames = e.getStackTrace();
            for (int j = 1; j < frames.length; ++j) {
                final String tempCallStack = frames[j].toString();
                if (TextUtils.isEmpty(apiCallStack)) {
                    // Overwrite apiCallStack if it's empty
                    apiCallStack = tempCallStack;
                } else if (tempCallStack.indexOf("Transact(") < 0) {
                    // Overwrite apiCallStack if it's not a binder call
                    apiCallStack = tempCallStack;
                } else {
                    break;
                }
            }
        }
        return apiCallStack;
    
public static java.util.ArrayListgetDefaultEnabledImes(android.content.Context context, boolean isSystemReady, java.util.ArrayList imis)

        final Locale fallbackLocale = getFallbackLocaleForDefaultIme(imis, context);
        if (!isSystemReady) {
            // When the system is not ready, the system locale is not stable and reliable. Hence
            // we will pick up IMEs that support software keyboard based on the fallback locale.
            // Also pick up suitable IMEs regardless of the software keyboard support.
            // (e.g. Voice IMEs)
            return getMinimumKeyboardSetWithoutSystemLocale(imis, context, fallbackLocale)
                    .fillImes(imis, context, true /* checkDefaultAttribute */, fallbackLocale,
                            true /* checkCountry */, SUBTYPE_MODE_ANY)
                    .build();
        }

        // When the system is ready, 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);
        return getMinimumKeyboardSetWithSystemLocale(imis, context, systemLocale, fallbackLocale)
                .fillImes(imis, context, true /* checkDefaultAttribute */, systemLocale,
                        true /* checkCountry */, SUBTYPE_MODE_ANY)
                .fillAuxiliaryImes(imis, context)
                .build();
    
public static java.util.LocalegetFallbackLocaleForDefaultIme(java.util.ArrayList imis, android.content.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;
    
public static java.lang.CharSequencegetImeAndSubtypeDisplayName(android.content.Context context, android.view.inputmethod.InputMethodInfo imi, android.view.inputmethod.InputMethodSubtype subtype)

        final CharSequence imiLabel = imi.loadLabel(context.getPackageManager());
        return subtype != null
                ? TextUtils.concat(subtype.getDisplayName(context,
                        imi.getPackageName(), imi.getServiceInfo().applicationInfo),
                                (TextUtils.isEmpty(imiLabel) ?
                                        "" : " - " + imiLabel))
                : imiLabel;
    
private static java.util.ArrayListgetImplicitlyApplicableSubtypesLocked(android.content.res.Resources res, android.view.inputmethod.InputMethodInfo imi)

        final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
        final String systemLocale = res.getConfiguration().locale.toString();
        if (TextUtils.isEmpty(systemLocale)) return new ArrayList<InputMethodSubtype>();
        final String systemLanguage = res.getConfiguration().locale.getLanguage();
        final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap =
                new HashMap<String, InputMethodSubtype>();
        final int N = subtypes.size();
        for (int i = 0; i < N; ++i) {
            // scan overriding implicitly enabled subtypes.
            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<InputMethodSubtype>(applicableModeAndSubtypesMap.values());
        }
        for (int i = 0; i < N; ++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;
                }
                applicableModeAndSubtypesMap.put(mode, subtype);
            }
        }
        final InputMethodSubtype keyboardSubtype
                = applicableModeAndSubtypesMap.get(SUBTYPE_MODE_KEYBOARD);
        final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<InputMethodSubtype>(
                applicableModeAndSubtypesMap.values());
        if (keyboardSubtype != null && !keyboardSubtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
            for (int i = 0; i < N; ++i) {
                final InputMethodSubtype subtype = subtypes.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 (keyboardSubtype == null) {
            InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
                    res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
            if (lastResortKeyboardSubtype != null) {
                applicableSubtypes.add(lastResortKeyboardSubtype);
            }
        }
        return applicableSubtypes;
    
public static java.lang.StringgetLanguageFromLocaleString(java.lang.String locale)
Returns the language component of a given locale string. TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(String)}

        final int idx = locale.indexOf('_");
        if (idx < 0) {
            return locale;
        } else {
            return locale.substring(0, idx);
        }
    
private static com.android.internal.inputmethod.InputMethodUtils$InputMethodListBuildergetMinimumKeyboardSetWithSystemLocale(java.util.ArrayList imis, android.content.Context context, java.util.Locale systemLocale, java.util.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;
    
private static com.android.internal.inputmethod.InputMethodUtils$InputMethodListBuildergetMinimumKeyboardSetWithoutSystemLocale(java.util.ArrayList imis, android.content.Context context, java.util.Locale fallbackLocale)

        // Before the system becomes ready, we pick up at least one keyboard in the following order.
        // The first user (device owner) falls into this category.
        // 1. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: true
        // 2. checkDefaultAttribute: false, locale: fallbackLocale, checkCountry: true
        // 3. checkDefaultAttribute: true, locale: fallbackLocale, checkCountry: false
        // 4. 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 */, fallbackLocale,
                true /* 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, true /* checkDefaultAttribute */, fallbackLocale,
                false /* 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())
                + " fallbackLocale=" + fallbackLocale);
        return builder;
    
public static android.view.inputmethod.InputMethodInfogetMostApplicableDefaultIME(java.util.List 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 (InputMethodUtils.isSystemImeThatHasEnglishKeyboardSubtype(imi)
                    && !imi.isAuxiliaryIme()) {
                return imi;
            }
            if (firstFoundSystemIme < 0 && InputMethodUtils.isSystemIme(imi)
                    && !imi.isAuxiliaryIme()) {
                firstFoundSystemIme = i;
            }
        }
        return enabledImes.get(Math.max(firstFoundSystemIme, 0));
    
public static java.util.ArrayListgetOverridingImplicitlyEnabledSubtypes(android.view.inputmethod.InputMethodInfo imi, java.lang.String mode)

        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
        final int subtypeCount = imi.getSubtypeCount();
        for (int i = 0; i < subtypeCount; ++i) {
            final InputMethodSubtype subtype = imi.getSubtypeAt(i);
            if (subtype.overridesImplicitlyEnabledSubtype() && subtype.getMode().equals(mode)) {
                subtypes.add(subtype);
            }
        }
        return subtypes;
    
public static java.lang.StringgetStackTrace()

        final StringBuilder sb = new StringBuilder();
        try {
            throw new RuntimeException();
        } catch (RuntimeException e) {
            final StackTraceElement[] frames = e.getStackTrace();
            // Start at 1 because the first frame is here and we don't care about it
            for (int j = 1; j < frames.length; ++j) {
                sb.append(frames[j].toString() + "\n");
            }
        }
        return sb.toString();
    
public static intgetSubtypeIdFromHashCode(android.view.inputmethod.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;
    
public static java.util.ArrayListgetSubtypes(android.view.inputmethod.InputMethodInfo imi)

        ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
        final int subtypeCount = imi.getSubtypeCount();
        for (int i = 0; i < subtypeCount; ++i) {
            subtypes.add(imi.getSubtypeAt(i));
        }
        return subtypes;
    
public static java.util.LocalegetSystemLocaleFromContext(android.content.Context context)

        try {
            return context.getResources().getConfiguration().locale;
        } catch (Resources.NotFoundException ex) {
            return null;
        }
    
private static booleanisSystemAuxilialyImeThatHasAutomaticSubtype(android.view.inputmethod.InputMethodInfo imi, android.content.Context context, boolean checkDefaultAttribute)

        if (!isSystemIme(imi)) {
            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;
    
public static booleanisSystemIme(android.view.inputmethod.InputMethodInfo inputMethod)

        return (inputMethod.getServiceInfo().applicationInfo.flags
                & ApplicationInfo.FLAG_SYSTEM) != 0;
    
public static booleanisSystemImeThatHasEnglishKeyboardSubtype(android.view.inputmethod.InputMethodInfo imi)

deprecated
Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean, Locale, boolean, String)} instead.

        if (!isSystemIme(imi)) {
            return false;
        }
        return containsSubtypeOf(imi, ENGLISH_LOCALE.getLanguage(), SUBTYPE_MODE_KEYBOARD);
    
private static booleanisSystemImeThatHasSubtypeOf(android.view.inputmethod.InputMethodInfo imi, android.content.Context context, boolean checkDefaultAttribute, java.util.Locale requiredLocale, boolean checkCountry, java.lang.String requiredSubtypeMode)

        if (!isSystemIme(imi)) {
            return false;
        }
        if (checkDefaultAttribute && !imi.isDefault(context)) {
            return false;
        }
        if (!containsSubtypeOf(imi, requiredLocale, checkCountry, requiredSubtypeMode)) {
            return false;
        }
        return true;
    
public static booleanisValidSubtypeId(android.view.inputmethod.InputMethodInfo imi, int subtypeHashCode)

        return getSubtypeIdFromHashCode(imi, subtypeHashCode) != NOT_A_SUBTYPE_ID;
    
public static booleanisValidSystemDefaultIme(boolean isSystemReady, android.view.inputmethod.InputMethodInfo imi, android.content.Context context)

deprecated
Use {@link #isSystemImeThatHasSubtypeOf(InputMethodInfo, Context, boolean, Locale, boolean, String)} instead.

        if (!isSystemReady) {
            return false;
        }
        if (!isSystemIme(imi)) {
            return false;
        }
        if (imi.getIsDefaultResourceId() != 0) {
            try {
                if (imi.isDefault(context) && containsSubtypeOf(
                        imi, context.getResources().getConfiguration().locale.getLanguage(),
                        SUBTYPE_MODE_ANY)) {
                    return true;
                }
            } catch (Resources.NotFoundException ex) {
            }
        }
        if (imi.getSubtypeCount() == 0) {
            Slog.w(TAG, "Found no subtypes in a system IME: " + imi.getPackageName());
        }
        return false;
    
private static voidsetDisabledUntilUsed(android.content.pm.PackageManager packageManager, java.lang.String packageName)

        final int state = packageManager.getApplicationEnabledSetting(packageName);
        if (state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                || state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {
            if (DEBUG) {
                Slog.d(TAG, "Update state(" + packageName + "): DISABLED_UNTIL_USED");
            }
            packageManager.setApplicationEnabledSetting(packageName,
                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED, 0);
        } else {
            if (DEBUG) {
                Slog.d(TAG, packageName + " is already DISABLED_UNTIL_USED");
            }
        }
    
public static voidsetNonSelectedSystemImesDisabledUntilUsed(android.content.pm.PackageManager packageManager, java.util.List enabledImis)

        if (DEBUG) {
            Slog.d(TAG, "setNonSelectedSystemImesDisabledUntilUsed");
        }
        final String[] systemImesDisabledUntilUsed = Resources.getSystem().getStringArray(
                com.android.internal.R.array.config_disabledUntilUsedPreinstalledImes);
        if (systemImesDisabledUntilUsed == null || systemImesDisabledUntilUsed.length == 0) {
            return;
        }
        // Only the current spell checker should be treated as an enabled one.
        final SpellCheckerInfo currentSpellChecker =
                TextServicesManager.getInstance().getCurrentSpellChecker();
        for (final String packageName : systemImesDisabledUntilUsed) {
            if (DEBUG) {
                Slog.d(TAG, "check " + packageName);
            }
            boolean enabledIme = false;
            for (int j = 0; j < enabledImis.size(); ++j) {
                final InputMethodInfo imi = enabledImis.get(j);
                if (packageName.equals(imi.getPackageName())) {
                    enabledIme = true;
                    break;
                }
            }
            if (enabledIme) {
                // enabled ime. skip
                continue;
            }
            if (currentSpellChecker != null
                    && packageName.equals(currentSpellChecker.getPackageName())) {
                // enabled spell checker. skip
                if (DEBUG) {
                    Slog.d(TAG, packageName + " is the current spell checker. skip");
                }
                continue;
            }
            ApplicationInfo ai = null;
            try {
                ai = packageManager.getApplicationInfo(packageName,
                        PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
            } catch (NameNotFoundException e) {
                Slog.w(TAG, "NameNotFoundException: " + packageName, e);
            }
            if (ai == null) {
                // No app found for packageName
                continue;
            }
            final boolean isSystemPackage = (ai.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
            if (!isSystemPackage) {
                continue;
            }
            setDisabledUntilUsed(packageManager, packageName);
        }