RichInputMethodManager.java revision a7d2fc6befa1b16883200a653fc01deb4d94944d
16fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka/*
26fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * Copyright (C) 2012 The Android Open Source Project
36fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka *
46fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * Licensed under the Apache License, Version 2.0 (the "License");
56fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * you may not use this file except in compliance with the License.
66fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * You may obtain a copy of the License at
76fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka *
86fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka *      http://www.apache.org/licenses/LICENSE-2.0
96fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka *
106fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * Unless required by applicable law or agreed to in writing, software
116fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * distributed under the License is distributed on an "AS IS" BASIS,
126fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * See the License for the specific language governing permissions and
146fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * limitations under the License.
156fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka */
166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokapackage com.android.inputmethod.latin;
186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
196fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport static com.android.inputmethod.latin.Constants.Subtype.KEYBOARD_MODE;
206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.content.Context;
2285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaokaimport android.content.SharedPreferences;
236fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.os.IBinder;
24f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaokaimport android.preference.PreferenceManager;
2585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaokaimport android.util.Log;
266fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.view.inputmethod.InputMethodInfo;
276fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.view.inputmethod.InputMethodManager;
286fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype;
296fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
306fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
31a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.Settings;
32e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils;
336fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
346fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport java.util.Collections;
35ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalardimport java.util.HashMap;
366fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport java.util.List;
376fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
386fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka/**
396fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * Enrichment class for InputMethodManager to simplify interaction and add functionality.
406fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka */
416fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokapublic final class RichInputMethodManager {
426fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private static final String TAG = RichInputMethodManager.class.getSimpleName();
436fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
446fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private RichInputMethodManager() {
456fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // This utility class is not publicly instantiable.
466fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
476fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
486fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private static final RichInputMethodManager sInstance = new RichInputMethodManager();
496fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
506fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private InputMethodManagerCompatWrapper mImmWrapper;
516fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private InputMethodInfo mInputMethodInfoOfThisIme;
52ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    final HashMap<InputMethodInfo, List<InputMethodSubtype>>
53ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            mSubtypeListCacheWithImplicitlySelectedSubtypes = CollectionUtils.newHashMap();
54ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    final HashMap<InputMethodInfo, List<InputMethodSubtype>>
55ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            mSubtypeListCacheWithoutImplicitlySelectedSubtypes = CollectionUtils.newHashMap();
566fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
5785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static final int INDEX_NOT_FOUND = -1;
5885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
596fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public static RichInputMethodManager getInstance() {
606fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        sInstance.checkInitialized();
616fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return sInstance;
626fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
636fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
64f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka    public static void init(final Context context) {
65f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
6685e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        sInstance.initInternal(context, prefs);
6785e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka    }
6885e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka
6985e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka    private boolean isInitialized() {
7085e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        return mImmWrapper != null;
716fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
726fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
736fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private void checkInitialized() {
7485e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        if (!isInitialized()) {
756fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            throw new RuntimeException(TAG + " is used before initialization");
766fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
776fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
786fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
7985e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka    private void initInternal(final Context context, final SharedPreferences prefs) {
8085e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        if (isInitialized()) {
8185e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka            return;
8285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        }
836fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        mImmWrapper = new InputMethodManagerCompatWrapper(context);
846fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        mInputMethodInfoOfThisIme = getInputMethodInfoOfThisIme(context);
8585e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka
8685e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        // Initialize additional subtypes.
8785e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        SubtypeLocale.init(context);
88d3b0ecec22cda883150851dced32c1eda2910a66Tadashi G. Takaoka        final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes(
8985e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka                prefs, context.getResources());
9085e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        final InputMethodSubtype[] additionalSubtypes =
9185e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka                AdditionalSubtype.createAdditionalSubtypesArray(prefAdditionalSubtypes);
9285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        setAdditionalInputMethodSubtypes(additionalSubtypes);
936fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
946fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
956fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodManager getInputMethodManager() {
966fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        checkInitialized();
976fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return mImmWrapper.mImm;
986fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
996fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
1006fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private InputMethodInfo getInputMethodInfoOfThisIme(final Context context) {
1016fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final String packageName = context.getPackageName();
1026fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (final InputMethodInfo imi : mImmWrapper.mImm.getInputMethodList()) {
1036fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (imi.getPackageName().equals(packageName)) {
1046fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                return imi;
1056fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
1066fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
1076fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        throw new RuntimeException("Input method id for " + packageName + " not found.");
1086fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
1096fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
110b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka    public List<InputMethodSubtype> getMyEnabledInputMethodSubtypeList(
111b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka            boolean allowsImplicitlySelectedSubtypes) {
112ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        return getEnabledInputMethodSubtypeList(mInputMethodInfoOfThisIme,
113ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                allowsImplicitlySelectedSubtypes);
114b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka    }
115b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka
1166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
11785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme)) {
11885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return true;
11985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
12085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        // Was not able to call {@link InputMethodManager#switchToNextInputMethodIBinder,boolean)}
12185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        // because the current device is running ICS or previous and lacks the API.
12285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (switchToNextInputSubtypeInThisIme(token, onlyCurrentIme)) {
12385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return true;
12485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
12585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return switchToNextInputMethodAndSubtype(token);
12685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
12785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
12885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private boolean switchToNextInputSubtypeInThisIme(final IBinder token,
12985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final boolean onlyCurrentIme) {
13085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodManager imm = mImmWrapper.mImm;
13185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype();
132b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka        final List<InputMethodSubtype> enabledSubtypes = getMyEnabledInputMethodSubtypeList(
133b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka                true /* allowsImplicitlySelectedSubtypes */);
13485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int currentIndex = getSubtypeIndexInList(currentSubtype, enabledSubtypes);
13585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (currentIndex == INDEX_NOT_FOUND) {
13685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            Log.w(TAG, "Can't find current subtype in enabled subtypes: subtype="
13785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                    + SubtypeLocale.getSubtypeDisplayName(currentSubtype));
1386fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            return false;
1396fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
14085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int nextIndex = (currentIndex + 1) % enabledSubtypes.size();
14185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (nextIndex <= currentIndex && !onlyCurrentIme) {
14285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            // The current subtype is the last or only enabled one and it needs to switch to
14385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            // next IME.
14485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return false;
14585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
14685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodSubtype nextSubtype = enabledSubtypes.get(nextIndex);
14785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        setInputMethodAndSubtype(token, nextSubtype);
14885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return true;
14985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
15085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
15185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private boolean switchToNextInputMethodAndSubtype(final IBinder token) {
15285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodManager imm = mImmWrapper.mImm;
15385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
15485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int currentIndex = getImiIndexInList(mInputMethodInfoOfThisIme, enabledImis);
15585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (currentIndex == INDEX_NOT_FOUND) {
15685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            Log.w(TAG, "Can't find current IME in enabled IMEs: IME package="
15785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                    + mInputMethodInfoOfThisIme.getPackageName());
15885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return false;
15985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
16085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis);
161ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final List<InputMethodSubtype> enabledSubtypes = getEnabledInputMethodSubtypeList(nextImi,
162ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                true /* allowsImplicitlySelectedSubtypes */);
16385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (enabledSubtypes.isEmpty()) {
16485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            // The next IME has no subtype.
16585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            imm.setInputMethod(token, nextImi.getId());
16685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return true;
16785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
16885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodSubtype firstSubtype = enabledSubtypes.get(0);
16985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        imm.setInputMethodAndSubtype(token, nextImi.getId(), firstSubtype);
17085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return true;
17185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
17285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
17385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static int getImiIndexInList(final InputMethodInfo inputMethodInfo,
17485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final List<InputMethodInfo> imiList) {
17585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imiList.size();
17685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
17785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodInfo imi = imiList.get(index);
17885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            if (imi.equals(inputMethodInfo)) {
17985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return index;
18085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            }
18185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
18285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return INDEX_NOT_FOUND;
18385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
18485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
18585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    // This method mimics {@link InputMethodManager#switchToNextInputMethod(IBinder,boolean)}.
18685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static InputMethodInfo getNextNonAuxiliaryIme(final int currentIndex,
18785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final List<InputMethodInfo> imiList) {
18885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imiList.size();
18985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int i = 1; i < count; i++) {
19085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final int nextIndex = (currentIndex + i) % count;
19185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodInfo nextImi = imiList.get(nextIndex);
19285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            if (!isAuxiliaryIme(nextImi)) {
19385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return nextImi;
19485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            }
19585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
19685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return imiList.get(currentIndex);
19785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
19885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
19985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    // Copied from {@link InputMethodInfo}. See how auxiliary of IME is determined.
20085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static boolean isAuxiliaryIme(final InputMethodInfo imi) {
20185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imi.getSubtypeCount();
20285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (count == 0) {
20385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return false;
20485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
20585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
20685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodSubtype subtype = imi.getSubtypeAt(index);
20785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            if (!subtype.isAuxiliary()) {
20885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return false;
20985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            }
21085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
2116fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return true;
2126fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2136fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2146fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodInfo getInputMethodInfoOfThisIme() {
2156fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return mInputMethodInfoOfThisIme;
2166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public String getInputMethodIdOfThisIme() {
2196fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return mInputMethodInfoOfThisIme.getId();
2206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
22276d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
22376d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        return checkIfSubtypeBelongsToImeAndEnabled(mInputMethodInfoOfThisIme, subtype);
22476d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    }
22576d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka
22676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
22776d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            final InputMethodSubtype subtype) {
22876d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
22976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(
230b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka                subtype, getMyEnabledInputMethodSubtypeList(
231b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka                        false /* allowsImplicitlySelectedSubtypes */));
23276d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        return subtypeEnabled && !subtypeExplicitlyEnabled;
2336fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2346fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2356fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean checkIfSubtypeBelongsToImeAndEnabled(final InputMethodInfo imi,
23676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            final InputMethodSubtype subtype) {
237ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        return checkIfSubtypeBelongsToList(subtype, getEnabledInputMethodSubtypeList(imi,
238ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                true /* allowsImplicitlySelectedSubtypes */));
23976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    }
24076d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka
24176d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype,
24276d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            final List<InputMethodSubtype> subtypes) {
24385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND;
24485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
24585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
24685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static int getSubtypeIndexInList(final InputMethodSubtype subtype,
24785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final List<InputMethodSubtype> subtypes) {
24885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = subtypes.size();
24985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
25085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodSubtype ims = subtypes.get(index);
25176d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            if (ims.equals(subtype)) {
25285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return index;
2536fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
2546fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
25585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return INDEX_NOT_FOUND;
2566fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2576fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
25876d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    public boolean checkIfSubtypeBelongsToThisIme(final InputMethodSubtype subtype) {
25985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return getSubtypeIndexInIme(subtype, mInputMethodInfoOfThisIme) != INDEX_NOT_FOUND;
26085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
26185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
26285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static int getSubtypeIndexInIme(final InputMethodSubtype subtype,
26385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodInfo imi) {
26485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imi.getSubtypeCount();
26585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
26685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodSubtype ims = imi.getSubtypeAt(index);
26776d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            if (ims.equals(subtype)) {
26885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return index;
2696fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
2706fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
27185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return INDEX_NOT_FOUND;
2726fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2736fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2746fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodSubtype getCurrentInputMethodSubtype(
2756fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final InputMethodSubtype defaultSubtype) {
2766fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype();
2776fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return (currentSubtype != null) ? currentSubtype : defaultSubtype;
2786fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2796fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2806fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
2816fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final List<InputMethodInfo> enabledImis = mImmWrapper.mImm.getEnabledInputMethodList();
2826fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
2836fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2846fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2856fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean hasMultipleEnabledSubtypesInThisIme(
2866fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final boolean shouldIncludeAuxiliarySubtypes) {
2876fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final List<InputMethodInfo> imiList = Collections.singletonList(mInputMethodInfoOfThisIme);
2886fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList);
2896fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2906fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2916fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes,
2926fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final List<InputMethodInfo> imiList) {
2936fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // Number of the filtered IMEs
2946fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        int filteredImisCount = 0;
2956fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2966fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (InputMethodInfo imi : imiList) {
2976fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // We can return true immediately after we find two or more filtered IMEs.
2986fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (filteredImisCount > 1) return true;
299ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList(imi, true);
3006fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // IMEs that have no subtypes should be counted.
3016fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (subtypes.isEmpty()) {
3026fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                ++filteredImisCount;
3036fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                continue;
3046fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3056fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3066fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            int auxCount = 0;
3076fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            for (InputMethodSubtype subtype : subtypes) {
3086fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                if (subtype.isAuxiliary()) {
3096fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                    ++auxCount;
3106fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                }
3116fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3126fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final int nonAuxCount = subtypes.size() - auxCount;
3136fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3146fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // IMEs that have one or more non-auxiliary subtypes should be counted.
3156fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
3166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // subtypes should be counted as well.
3176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
3186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                ++filteredImisCount;
3196fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                continue;
3206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
3226fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3236fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        if (filteredImisCount > 1) {
3246fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            return true;
3256fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
326b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka        final List<InputMethodSubtype> subtypes = getMyEnabledInputMethodSubtypeList(true);
3276fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        int keyboardCount = 0;
3286fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
3296fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // both explicitly and implicitly enabled input method subtype.
3306fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // (The current IME should be LatinIME.)
3316fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (InputMethodSubtype subtype : subtypes) {
3326fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (KEYBOARD_MODE.equals(subtype.getMode())) {
3336fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                ++keyboardCount;
3346fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3356fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
3366fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return keyboardCount > 1;
3376fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
3386fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3396fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString,
3406fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final String keyboardLayoutSetName) {
3416fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final InputMethodInfo myImi = mInputMethodInfoOfThisIme;
3426fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final int count = myImi.getSubtypeCount();
3436fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
3446fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final InputMethodSubtype subtype = myImi.getSubtypeAt(i);
3456fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final String layoutName = SubtypeLocale.getKeyboardLayoutSetName(subtype);
3466fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (localeString.equals(subtype.getLocale())
3476fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                    && keyboardLayoutSetName.equals(layoutName)) {
3486fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                return subtype;
3496fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3506fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
3516fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return null;
3526fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
3536fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3541931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka    public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) {
3551931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka        mImmWrapper.mImm.setInputMethodAndSubtype(
3561931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                token, mInputMethodInfoOfThisIme.getId(), subtype);
3571931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka    }
3581931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka
3596fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) {
3606fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
3616fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                mInputMethodInfoOfThisIme.getId(), subtypes);
362ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        // Clear the cache so that we go read the subtypes again next time.
363ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        clearSubtypeCaches();
364ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    }
365ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard
366ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    private List<InputMethodSubtype> getEnabledInputMethodSubtypeList(final InputMethodInfo imi,
367ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            final boolean allowsImplicitlySelectedSubtypes) {
368ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final HashMap<InputMethodInfo, List<InputMethodSubtype>> cache =
369ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                allowsImplicitlySelectedSubtypes
370ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                ? mSubtypeListCacheWithImplicitlySelectedSubtypes
371ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                : mSubtypeListCacheWithoutImplicitlySelectedSubtypes;
372ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final List<InputMethodSubtype> cachedList = cache.get(imi);
373ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        if (null != cachedList) return cachedList;
374ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final List<InputMethodSubtype> result = mImmWrapper.mImm.getEnabledInputMethodSubtypeList(
375ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                imi, allowsImplicitlySelectedSubtypes);
376ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        cache.put(imi, result);
377ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        return result;
378ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    }
379ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard
380ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    public void clearSubtypeCaches() {
381ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        mSubtypeListCacheWithImplicitlySelectedSubtypes.clear();
382ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        mSubtypeListCacheWithoutImplicitlySelectedSubtypes.clear();
3836fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
3846fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka}
385