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;
32a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaokaimport com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
33e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils;
34a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaokaimport com.android.inputmethod.latin.utils.SubtypeLocaleUtils;
356fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
366fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport java.util.Collections;
37ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalardimport java.util.HashMap;
386fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport java.util.List;
396fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
406fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka/**
416fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * Enrichment class for InputMethodManager to simplify interaction and add functionality.
426fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka */
436fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokapublic final class RichInputMethodManager {
446fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private static final String TAG = RichInputMethodManager.class.getSimpleName();
456fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
466fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private RichInputMethodManager() {
476fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // This utility class is not publicly instantiable.
486fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
496fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
506fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private static final RichInputMethodManager sInstance = new RichInputMethodManager();
516fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
526fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private InputMethodManagerCompatWrapper mImmWrapper;
536fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private InputMethodInfo mInputMethodInfoOfThisIme;
54ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    final HashMap<InputMethodInfo, List<InputMethodSubtype>>
55ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            mSubtypeListCacheWithImplicitlySelectedSubtypes = CollectionUtils.newHashMap();
56ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    final HashMap<InputMethodInfo, List<InputMethodSubtype>>
57ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            mSubtypeListCacheWithoutImplicitlySelectedSubtypes = CollectionUtils.newHashMap();
586fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
5985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static final int INDEX_NOT_FOUND = -1;
6085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
616fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public static RichInputMethodManager getInstance() {
626fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        sInstance.checkInitialized();
636fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return sInstance;
646fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
656fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
66f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka    public static void init(final Context context) {
67f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka        final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
6885e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        sInstance.initInternal(context, prefs);
6985e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka    }
7085e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka
7185e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka    private boolean isInitialized() {
7285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        return mImmWrapper != null;
736fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
746fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
756fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private void checkInitialized() {
7685e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        if (!isInitialized()) {
776fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            throw new RuntimeException(TAG + " is used before initialization");
786fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
796fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
806fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
8185e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka    private void initInternal(final Context context, final SharedPreferences prefs) {
8285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        if (isInitialized()) {
8385e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka            return;
8485e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        }
856fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        mImmWrapper = new InputMethodManagerCompatWrapper(context);
866fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        mInputMethodInfoOfThisIme = getInputMethodInfoOfThisIme(context);
8785e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka
8885e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        // Initialize additional subtypes.
89a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka        SubtypeLocaleUtils.init(context);
90d3b0ecec22cda883150851dced32c1eda2910a66Tadashi G. Takaoka        final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes(
9185e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka                prefs, context.getResources());
9285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        final InputMethodSubtype[] additionalSubtypes =
93a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka                AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefAdditionalSubtypes);
9485e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka        setAdditionalInputMethodSubtypes(additionalSubtypes);
956fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
966fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
976fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodManager getInputMethodManager() {
986fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        checkInitialized();
996fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return mImmWrapper.mImm;
1006fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
1016fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
1026fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private InputMethodInfo getInputMethodInfoOfThisIme(final Context context) {
1036fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final String packageName = context.getPackageName();
1046fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (final InputMethodInfo imi : mImmWrapper.mImm.getInputMethodList()) {
1056fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (imi.getPackageName().equals(packageName)) {
1066fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                return imi;
1076fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
1086fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
1096fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        throw new RuntimeException("Input method id for " + packageName + " not found.");
1106fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
1116fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
112b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka    public List<InputMethodSubtype> getMyEnabledInputMethodSubtypeList(
113b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka            boolean allowsImplicitlySelectedSubtypes) {
114ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        return getEnabledInputMethodSubtypeList(mInputMethodInfoOfThisIme,
115ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                allowsImplicitlySelectedSubtypes);
116b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka    }
117b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka
1186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) {
11985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme)) {
12085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return true;
12185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
12285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        // Was not able to call {@link InputMethodManager#switchToNextInputMethodIBinder,boolean)}
12385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        // because the current device is running ICS or previous and lacks the API.
12485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (switchToNextInputSubtypeInThisIme(token, onlyCurrentIme)) {
12585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return true;
12685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
12785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return switchToNextInputMethodAndSubtype(token);
12885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
12985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
13085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private boolean switchToNextInputSubtypeInThisIme(final IBinder token,
13185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final boolean onlyCurrentIme) {
13285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodManager imm = mImmWrapper.mImm;
13385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype();
134b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka        final List<InputMethodSubtype> enabledSubtypes = getMyEnabledInputMethodSubtypeList(
135b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka                true /* allowsImplicitlySelectedSubtypes */);
13685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int currentIndex = getSubtypeIndexInList(currentSubtype, enabledSubtypes);
13785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (currentIndex == INDEX_NOT_FOUND) {
13885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            Log.w(TAG, "Can't find current subtype in enabled subtypes: subtype="
139a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka                    + SubtypeLocaleUtils.getSubtypeNameForLogging(currentSubtype));
1406fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            return false;
1416fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
14285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int nextIndex = (currentIndex + 1) % enabledSubtypes.size();
14385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (nextIndex <= currentIndex && !onlyCurrentIme) {
14485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            // The current subtype is the last or only enabled one and it needs to switch to
14585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            // next IME.
14685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return false;
14785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
14885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodSubtype nextSubtype = enabledSubtypes.get(nextIndex);
14985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        setInputMethodAndSubtype(token, nextSubtype);
15085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return true;
15185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
15285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
15385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private boolean switchToNextInputMethodAndSubtype(final IBinder token) {
15485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodManager imm = mImmWrapper.mImm;
15585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList();
15685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int currentIndex = getImiIndexInList(mInputMethodInfoOfThisIme, enabledImis);
15785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (currentIndex == INDEX_NOT_FOUND) {
15885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            Log.w(TAG, "Can't find current IME in enabled IMEs: IME package="
15985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                    + mInputMethodInfoOfThisIme.getPackageName());
16085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return false;
16185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
16285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis);
163ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final List<InputMethodSubtype> enabledSubtypes = getEnabledInputMethodSubtypeList(nextImi,
164ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                true /* allowsImplicitlySelectedSubtypes */);
16585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (enabledSubtypes.isEmpty()) {
16685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            // The next IME has no subtype.
16785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            imm.setInputMethod(token, nextImi.getId());
16885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return true;
16985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
17085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final InputMethodSubtype firstSubtype = enabledSubtypes.get(0);
17185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        imm.setInputMethodAndSubtype(token, nextImi.getId(), firstSubtype);
17285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return true;
17385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
17485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
17585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static int getImiIndexInList(final InputMethodInfo inputMethodInfo,
17685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final List<InputMethodInfo> imiList) {
17785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imiList.size();
17885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
17985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodInfo imi = imiList.get(index);
18085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            if (imi.equals(inputMethodInfo)) {
18185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return index;
18285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            }
18385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
18485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return INDEX_NOT_FOUND;
18585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
18685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
18785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    // This method mimics {@link InputMethodManager#switchToNextInputMethod(IBinder,boolean)}.
18885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static InputMethodInfo getNextNonAuxiliaryIme(final int currentIndex,
18985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final List<InputMethodInfo> imiList) {
19085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imiList.size();
19185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int i = 1; i < count; i++) {
19285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final int nextIndex = (currentIndex + i) % count;
19385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodInfo nextImi = imiList.get(nextIndex);
19485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            if (!isAuxiliaryIme(nextImi)) {
19585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return nextImi;
19685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            }
19785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
19885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return imiList.get(currentIndex);
19985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
20085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
20185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    // Copied from {@link InputMethodInfo}. See how auxiliary of IME is determined.
20285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static boolean isAuxiliaryIme(final InputMethodInfo imi) {
20385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imi.getSubtypeCount();
20485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        if (count == 0) {
20585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            return false;
20685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
20785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
20885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodSubtype subtype = imi.getSubtypeAt(index);
20985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            if (!subtype.isAuxiliary()) {
21085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return false;
21185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            }
21285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        }
2136fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return true;
2146fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2156fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodInfo getInputMethodInfoOfThisIme() {
2176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return mInputMethodInfoOfThisIme;
2186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2196fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public String getInputMethodIdOfThisIme() {
2216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return mInputMethodInfoOfThisIme.getId();
2226fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2236fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
22476d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) {
22576d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        return checkIfSubtypeBelongsToImeAndEnabled(mInputMethodInfoOfThisIme, subtype);
22676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    }
22776d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka
22876d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled(
22976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            final InputMethodSubtype subtype) {
23076d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype);
23176d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(
232b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka                subtype, getMyEnabledInputMethodSubtypeList(
233b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka                        false /* allowsImplicitlySelectedSubtypes */));
23476d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka        return subtypeEnabled && !subtypeExplicitlyEnabled;
2356fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2366fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2376fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean checkIfSubtypeBelongsToImeAndEnabled(final InputMethodInfo imi,
23876d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            final InputMethodSubtype subtype) {
239ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        return checkIfSubtypeBelongsToList(subtype, getEnabledInputMethodSubtypeList(imi,
240ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                true /* allowsImplicitlySelectedSubtypes */));
24176d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    }
24276d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka
24376d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype,
24476d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            final List<InputMethodSubtype> subtypes) {
24585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND;
24685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
24785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
24885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static int getSubtypeIndexInList(final InputMethodSubtype subtype,
24985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final List<InputMethodSubtype> subtypes) {
25085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = subtypes.size();
25185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
25285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodSubtype ims = subtypes.get(index);
25376d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            if (ims.equals(subtype)) {
25485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return index;
2556fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
2566fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
25785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return INDEX_NOT_FOUND;
2586fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2596fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
26076d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka    public boolean checkIfSubtypeBelongsToThisIme(final InputMethodSubtype subtype) {
26185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return getSubtypeIndexInIme(subtype, mInputMethodInfoOfThisIme) != INDEX_NOT_FOUND;
26285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    }
26385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka
26485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka    private static int getSubtypeIndexInIme(final InputMethodSubtype subtype,
26585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodInfo imi) {
26685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        final int count = imi.getSubtypeCount();
26785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        for (int index = 0; index < count; index++) {
26885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka            final InputMethodSubtype ims = imi.getSubtypeAt(index);
26976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka            if (ims.equals(subtype)) {
27085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka                return index;
2716fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
2726fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
27385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka        return INDEX_NOT_FOUND;
2746fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2756fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2766fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodSubtype getCurrentInputMethodSubtype(
2776fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final InputMethodSubtype defaultSubtype) {
2786fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final InputMethodSubtype currentSubtype = mImmWrapper.mImm.getCurrentInputMethodSubtype();
2796fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return (currentSubtype != null) ? currentSubtype : defaultSubtype;
2806fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2816fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2826fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) {
2836fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final List<InputMethodInfo> enabledImis = mImmWrapper.mImm.getEnabledInputMethodList();
2846fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis);
2856fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2866fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2876fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public boolean hasMultipleEnabledSubtypesInThisIme(
2886fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final boolean shouldIncludeAuxiliarySubtypes) {
2896fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final List<InputMethodInfo> imiList = Collections.singletonList(mInputMethodInfoOfThisIme);
2906fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList);
2916fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
2926fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2936fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    private boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes,
2946fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final List<InputMethodInfo> imiList) {
2956fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // Number of the filtered IMEs
2966fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        int filteredImisCount = 0;
2976fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
2986fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (InputMethodInfo imi : imiList) {
2996fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // We can return true immediately after we find two or more filtered IMEs.
3006fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (filteredImisCount > 1) return true;
301ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList(imi, true);
3026fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // IMEs that have no subtypes should be counted.
3036fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (subtypes.isEmpty()) {
3046fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                ++filteredImisCount;
3056fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                continue;
3066fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3076fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3086fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            int auxCount = 0;
3096fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            for (InputMethodSubtype subtype : subtypes) {
3106fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                if (subtype.isAuxiliary()) {
3116fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                    ++auxCount;
3126fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                }
3136fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3146fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final int nonAuxCount = subtypes.size() - auxCount;
3156fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // IMEs that have one or more non-auxiliary subtypes should be counted.
3176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary
3186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            // subtypes should be counted as well.
3196fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) {
3206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                ++filteredImisCount;
3216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                continue;
3226fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3236fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
3246fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3256fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        if (filteredImisCount > 1) {
3266fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            return true;
3276fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
328b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka        final List<InputMethodSubtype> subtypes = getMyEnabledInputMethodSubtypeList(true);
3296fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        int keyboardCount = 0;
3306fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's
3316fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // both explicitly and implicitly enabled input method subtype.
3326fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        // (The current IME should be LatinIME.)
3336fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (InputMethodSubtype subtype : subtypes) {
3346fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (KEYBOARD_MODE.equals(subtype.getMode())) {
3356fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                ++keyboardCount;
3366fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3376fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
3386fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return keyboardCount > 1;
3396fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
3406fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3416fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString,
3426fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final String keyboardLayoutSetName) {
3436fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final InputMethodInfo myImi = mInputMethodInfoOfThisIme;
3446fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        final int count = myImi.getSubtypeCount();
3456fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        for (int i = 0; i < count; i++) {
3466fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            final InputMethodSubtype subtype = myImi.getSubtypeAt(i);
347a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka            final String layoutName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype);
3486fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            if (localeString.equals(subtype.getLocale())
3496fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                    && keyboardLayoutSetName.equals(layoutName)) {
3506fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                return subtype;
3516fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka            }
3526fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        }
3536fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        return null;
3546fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
3556fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka
3561931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka    public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) {
3571931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka        mImmWrapper.mImm.setInputMethodAndSubtype(
3581931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka                token, mInputMethodInfoOfThisIme.getId(), subtype);
3591931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka    }
3601931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka
3616fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) {
3626fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka        mImmWrapper.mImm.setAdditionalInputMethodSubtypes(
3636fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka                mInputMethodInfoOfThisIme.getId(), subtypes);
364ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        // Clear the cache so that we go read the subtypes again next time.
365ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        clearSubtypeCaches();
366ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    }
367ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard
368ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    private List<InputMethodSubtype> getEnabledInputMethodSubtypeList(final InputMethodInfo imi,
369ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard            final boolean allowsImplicitlySelectedSubtypes) {
370ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final HashMap<InputMethodInfo, List<InputMethodSubtype>> cache =
371ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                allowsImplicitlySelectedSubtypes
372ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                ? mSubtypeListCacheWithImplicitlySelectedSubtypes
373ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                : mSubtypeListCacheWithoutImplicitlySelectedSubtypes;
374ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final List<InputMethodSubtype> cachedList = cache.get(imi);
375ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        if (null != cachedList) return cachedList;
376ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        final List<InputMethodSubtype> result = mImmWrapper.mImm.getEnabledInputMethodSubtypeList(
377ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard                imi, allowsImplicitlySelectedSubtypes);
378ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        cache.put(imi, result);
379ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        return result;
380ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    }
381ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard
382ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard    public void clearSubtypeCaches() {
383ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        mSubtypeListCacheWithImplicitlySelectedSubtypes.clear();
384ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard        mSubtypeListCacheWithoutImplicitlySelectedSubtypes.clear();
3856fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka    }
3866fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka}
387