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 199342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport static com.android.inputmethod.latin.common.Constants.Subtype.KEYBOARD_MODE; 206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.content.Context; 2285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaokaimport android.content.SharedPreferences; 238a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaokaimport android.inputmethodservice.InputMethodService; 248a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaokaimport android.os.AsyncTask; 258ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawaimport android.os.Build; 266fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.os.IBinder; 27f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaokaimport android.preference.PreferenceManager; 2885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaokaimport android.util.Log; 296fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.view.inputmethod.InputMethodInfo; 306fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.view.inputmethod.InputMethodManager; 316fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport android.view.inputmethod.InputMethodSubtype; 326fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 337fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaokaimport com.android.inputmethod.annotations.UsedForTesting; 346fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper; 35809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawaimport com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; 36a7d2fc6befa1b16883200a653fc01deb4d94944dKen Wakasaimport com.android.inputmethod.latin.settings.Settings; 37a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaokaimport com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; 3831a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaokaimport com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils; 39a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaokaimport com.android.inputmethod.latin.utils.SubtypeLocaleUtils; 406fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 416fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport java.util.Collections; 42ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalardimport java.util.HashMap; 432a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaokaimport java.util.HashSet; 446fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaokaimport java.util.List; 452a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaokaimport java.util.Locale; 468a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaokaimport java.util.Map; 472a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaokaimport java.util.Set; 486fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 49d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaokaimport javax.annotation.Nonnull; 50b86ca76cea9aedf47a81f9272fb59897de3bbbe7Dan Zivkovicimport javax.annotation.Nullable; 51d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka 526fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka/** 536fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka * Enrichment class for InputMethodManager to simplify interaction and add functionality. 546fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka */ 55698b19ef35d1d865943ec9d9ee05f8f0e66dc3f8Mohammadinamul Sheik// non final for easy mocking. 56698b19ef35d1d865943ec9d9ee05f8f0e66dc3f8Mohammadinamul Sheikpublic class RichInputMethodManager { 576fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private static final String TAG = RichInputMethodManager.class.getSimpleName(); 588a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka private static final boolean DEBUG = false; 596fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 606fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private RichInputMethodManager() { 616fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // This utility class is not publicly instantiable. 626fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 636fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 646fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private static final RichInputMethodManager sInstance = new RichInputMethodManager(); 656fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 66f13487dfbf2b7547b48a5e9123235ee8a1d660c8Jean Chalard private Context mContext; 676fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private InputMethodManagerCompatWrapper mImmWrapper; 68ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka private InputMethodInfoCache mInputMethodInfoCache; 697fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka private RichInputMethodSubtype mCurrentRichInputMethodSubtype; 708a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka private InputMethodInfo mShortcutInputMethodInfo; 718a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka private InputMethodSubtype mShortcutSubtype; 726fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 7385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka private static final int INDEX_NOT_FOUND = -1; 7485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka 756fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public static RichInputMethodManager getInstance() { 766fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka sInstance.checkInitialized(); 776fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return sInstance; 786fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 796fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 80f90fc105ab1159f43f536bcacdd1224c2c05bacbTadashi G. Takaoka public static void init(final Context context) { 81052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa sInstance.initInternal(context); 8285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka } 8385e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka 8485e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka private boolean isInitialized() { 8585e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka return mImmWrapper != null; 866fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 876fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 886fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private void checkInitialized() { 8985e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka if (!isInitialized()) { 906fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka throw new RuntimeException(TAG + " is used before initialization"); 916fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 926fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 936fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 94052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa private void initInternal(final Context context) { 9585e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka if (isInitialized()) { 9685e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka return; 9785e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka } 986fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mImmWrapper = new InputMethodManagerCompatWrapper(context); 99f13487dfbf2b7547b48a5e9123235ee8a1d660c8Jean Chalard mContext = context; 100ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka mInputMethodInfoCache = new InputMethodInfoCache( 101ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka mImmWrapper.mImm, context.getPackageName()); 10285e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka 10385e397cd1060f3878d9a55373b7409641175179aTadashi G. Takaoka // Initialize additional subtypes. 104a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka SubtypeLocaleUtils.init(context); 1058a711f2a547a61b9f4f3ef3bdb79a66b618db58fTadashi G. Takaoka final InputMethodSubtype[] additionalSubtypes = getAdditionalSubtypes(); 1064486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka mImmWrapper.mImm.setAdditionalInputMethodSubtypes( 1074486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka getInputMethodIdOfThisIme(), additionalSubtypes); 1084486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka 1094486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka // Initialize the current input method subtype and the shortcut IME. 1104486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka refreshSubtypeCaches(); 111052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa } 112052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa 1138a711f2a547a61b9f4f3ef3bdb79a66b618db58fTadashi G. Takaoka public InputMethodSubtype[] getAdditionalSubtypes() { 1148a711f2a547a61b9f4f3ef3bdb79a66b618db58fTadashi G. Takaoka final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext); 115d3b0ecec22cda883150851dced32c1eda2910a66Tadashi G. Takaoka final String prefAdditionalSubtypes = Settings.readPrefAdditionalSubtypes( 1168a711f2a547a61b9f4f3ef3bdb79a66b618db58fTadashi G. Takaoka prefs, mContext.getResources()); 117052ec62abd577182af8d5b50564d8075b18be3c9Yohei Yukawa return AdditionalSubtypeUtils.createAdditionalSubtypesArray(prefAdditionalSubtypes); 1186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 1196fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 1206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public InputMethodManager getInputMethodManager() { 1216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka checkInitialized(); 1226fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return mImmWrapper.mImm; 1236fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 1246fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 125b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka public List<InputMethodSubtype> getMyEnabledInputMethodSubtypeList( 126b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka boolean allowsImplicitlySelectedSubtypes) { 127ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka return getEnabledInputMethodSubtypeList( 128ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka getInputMethodInfoOfThisIme(), allowsImplicitlySelectedSubtypes); 129b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka } 130b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka 1316fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public boolean switchToNextInputMethod(final IBinder token, final boolean onlyCurrentIme) { 13285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (mImmWrapper.switchToNextInputMethod(token, onlyCurrentIme)) { 13385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return true; 13485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 13585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka // Was not able to call {@link InputMethodManager#switchToNextInputMethodIBinder,boolean)} 13685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka // because the current device is running ICS or previous and lacks the API. 13785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (switchToNextInputSubtypeInThisIme(token, onlyCurrentIme)) { 13885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return true; 13985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 14085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return switchToNextInputMethodAndSubtype(token); 14185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 14285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka 14385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka private boolean switchToNextInputSubtypeInThisIme(final IBinder token, 14485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final boolean onlyCurrentIme) { 14585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodManager imm = mImmWrapper.mImm; 14685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodSubtype currentSubtype = imm.getCurrentInputMethodSubtype(); 147b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka final List<InputMethodSubtype> enabledSubtypes = getMyEnabledInputMethodSubtypeList( 148b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka true /* allowsImplicitlySelectedSubtypes */); 14985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final int currentIndex = getSubtypeIndexInList(currentSubtype, enabledSubtypes); 15085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (currentIndex == INDEX_NOT_FOUND) { 15185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka Log.w(TAG, "Can't find current subtype in enabled subtypes: subtype=" 152a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka + SubtypeLocaleUtils.getSubtypeNameForLogging(currentSubtype)); 1536fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return false; 1546fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 15585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final int nextIndex = (currentIndex + 1) % enabledSubtypes.size(); 15685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (nextIndex <= currentIndex && !onlyCurrentIme) { 15785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka // The current subtype is the last or only enabled one and it needs to switch to 15885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka // next IME. 15985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return false; 16085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 16185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodSubtype nextSubtype = enabledSubtypes.get(nextIndex); 16285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka setInputMethodAndSubtype(token, nextSubtype); 16385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return true; 16485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 16585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka 16685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka private boolean switchToNextInputMethodAndSubtype(final IBinder token) { 16785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodManager imm = mImmWrapper.mImm; 16885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final List<InputMethodInfo> enabledImis = imm.getEnabledInputMethodList(); 169ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka final int currentIndex = getImiIndexInList(getInputMethodInfoOfThisIme(), enabledImis); 17085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (currentIndex == INDEX_NOT_FOUND) { 17185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka Log.w(TAG, "Can't find current IME in enabled IMEs: IME package=" 172ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka + getInputMethodInfoOfThisIme().getPackageName()); 17385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return false; 17485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 17585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodInfo nextImi = getNextNonAuxiliaryIme(currentIndex, enabledImis); 176ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard final List<InputMethodSubtype> enabledSubtypes = getEnabledInputMethodSubtypeList(nextImi, 177ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard true /* allowsImplicitlySelectedSubtypes */); 17885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (enabledSubtypes.isEmpty()) { 17985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka // The next IME has no subtype. 18085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka imm.setInputMethod(token, nextImi.getId()); 18185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return true; 18285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 18385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodSubtype firstSubtype = enabledSubtypes.get(0); 18485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka imm.setInputMethodAndSubtype(token, nextImi.getId(), firstSubtype); 18585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return true; 18685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 18785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka 18885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka private static int getImiIndexInList(final InputMethodInfo inputMethodInfo, 18985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final List<InputMethodInfo> imiList) { 19085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final int count = imiList.size(); 19185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka for (int index = 0; index < count; index++) { 19285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodInfo imi = imiList.get(index); 19385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (imi.equals(inputMethodInfo)) { 19485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return index; 19585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 19685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 19785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return INDEX_NOT_FOUND; 19885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 19985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka 20085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka // This method mimics {@link InputMethodManager#switchToNextInputMethod(IBinder,boolean)}. 20185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka private static InputMethodInfo getNextNonAuxiliaryIme(final int currentIndex, 20285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final List<InputMethodInfo> imiList) { 20385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final int count = imiList.size(); 20485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka for (int i = 1; i < count; i++) { 20585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final int nextIndex = (currentIndex + i) % count; 20685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodInfo nextImi = imiList.get(nextIndex); 20785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (!isAuxiliaryIme(nextImi)) { 20885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return nextImi; 20985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 21085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 21185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return imiList.get(currentIndex); 21285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 21385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka 21485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka // Copied from {@link InputMethodInfo}. See how auxiliary of IME is determined. 21585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka private static boolean isAuxiliaryIme(final InputMethodInfo imi) { 21685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final int count = imi.getSubtypeCount(); 21785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (count == 0) { 21885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return false; 21985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 22085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka for (int index = 0; index < count; index++) { 22185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodSubtype subtype = imi.getSubtypeAt(index); 22285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka if (!subtype.isAuxiliary()) { 22385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return false; 22485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 22585629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 2266fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return true; 2276fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 2286fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 229ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka private static class InputMethodInfoCache { 230ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka private final InputMethodManager mImm; 231ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka private final String mImePackageName; 232ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka 233afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka private InputMethodInfo mCachedThisImeInfo; 234afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka private final HashMap<InputMethodInfo, List<InputMethodSubtype>> 235afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedSubtypeListWithImplicitlySelected; 236afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka private final HashMap<InputMethodInfo, List<InputMethodSubtype>> 237afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedSubtypeListOnlyExplicitlySelected; 238ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka 239ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka public InputMethodInfoCache(final InputMethodManager imm, final String imePackageName) { 240ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka mImm = imm; 241ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka mImePackageName = imePackageName; 242afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedSubtypeListWithImplicitlySelected = new HashMap<>(); 243afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedSubtypeListOnlyExplicitlySelected = new HashMap<>(); 244ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka } 245ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka 246afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka public synchronized InputMethodInfo getInputMethodOfThisIme() { 247afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka if (mCachedThisImeInfo != null) { 248afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka return mCachedThisImeInfo; 249ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka } 250ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka for (final InputMethodInfo imi : mImm.getInputMethodList()) { 251ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka if (imi.getPackageName().equals(mImePackageName)) { 252afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedThisImeInfo = imi; 253ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka return imi; 254ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka } 255ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka } 256ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka throw new RuntimeException("Input method id for " + mImePackageName + " not found."); 257ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka } 258ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka 259afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka public synchronized List<InputMethodSubtype> getEnabledInputMethodSubtypeList( 260afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka final InputMethodInfo imi, final boolean allowsImplicitlySelectedSubtypes) { 261afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka final HashMap<InputMethodInfo, List<InputMethodSubtype>> cache = 262afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka allowsImplicitlySelectedSubtypes 263afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka ? mCachedSubtypeListWithImplicitlySelected 264afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka : mCachedSubtypeListOnlyExplicitlySelected; 265afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka final List<InputMethodSubtype> cachedList = cache.get(imi); 266afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka if (cachedList != null) { 267afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka return cachedList; 268afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka } 269afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka final List<InputMethodSubtype> result = mImm.getEnabledInputMethodSubtypeList( 270afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka imi, allowsImplicitlySelectedSubtypes); 271afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka cache.put(imi, result); 272afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka return result; 273afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka } 274afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka 275ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka public synchronized void clear() { 276afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedThisImeInfo = null; 277afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedSubtypeListWithImplicitlySelected.clear(); 278afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka mCachedSubtypeListOnlyExplicitlySelected.clear(); 279ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka } 280ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka } 281ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka 2826fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public InputMethodInfo getInputMethodInfoOfThisIme() { 283afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka return mInputMethodInfoCache.getInputMethodOfThisIme(); 2846fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 2856fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 2866fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public String getInputMethodIdOfThisIme() { 287ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka return getInputMethodInfoOfThisIme().getId(); 2886fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 2896fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 29076d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka public boolean checkIfSubtypeBelongsToThisImeAndEnabled(final InputMethodSubtype subtype) { 29112d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic return checkIfSubtypeBelongsToList(subtype, 29212d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic getEnabledInputMethodSubtypeList( 29312d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic getInputMethodInfoOfThisIme(), 29412d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic true /* allowsImplicitlySelectedSubtypes */)); 29576d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka } 29676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka 29776d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka public boolean checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled( 29876d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka final InputMethodSubtype subtype) { 29976d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka final boolean subtypeEnabled = checkIfSubtypeBelongsToThisImeAndEnabled(subtype); 30012d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic final boolean subtypeExplicitlyEnabled = checkIfSubtypeBelongsToList(subtype, 30112d80ebead6a1d7f704a5a3af3b6fe3313ceab05Dan Zivkovic getMyEnabledInputMethodSubtypeList(false /* allowsImplicitlySelectedSubtypes */)); 30276d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka return subtypeEnabled && !subtypeExplicitlyEnabled; 3036fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3046fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 30576d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka private static boolean checkIfSubtypeBelongsToList(final InputMethodSubtype subtype, 30676d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka final List<InputMethodSubtype> subtypes) { 30785629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return getSubtypeIndexInList(subtype, subtypes) != INDEX_NOT_FOUND; 30885629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka } 30985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka 31085629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka private static int getSubtypeIndexInList(final InputMethodSubtype subtype, 31185629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final List<InputMethodSubtype> subtypes) { 31285629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final int count = subtypes.size(); 31385629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka for (int index = 0; index < count; index++) { 31485629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka final InputMethodSubtype ims = subtypes.get(index); 31576d4ffeebfd084913a8c1b7433dff48f5b2063dfTadashi G. Takaoka if (ims.equals(subtype)) { 31685629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return index; 3176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 31985629debaaaa576047a4f01430411f0d7b41762dTadashi G. Takaoka return INDEX_NOT_FOUND; 3206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 3224486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka public void onSubtypeChanged(@Nonnull final InputMethodSubtype newSubtype) { 3234486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka updateCurrentSubtype(newSubtype); 3244486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka updateShortcutIme(); 3257fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka if (DEBUG) { 3264486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka Log.w(TAG, "onSubtypeChanged: " + mCurrentRichInputMethodSubtype.getNameForLogging()); 3277fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 3287fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 3297fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka 3307fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka private static RichInputMethodSubtype sForcedSubtypeForTesting = null; 3317fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka 3327fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka @UsedForTesting 3334486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka static void forceSubtype(@Nonnull final InputMethodSubtype subtype) { 334b86ca76cea9aedf47a81f9272fb59897de3bbbe7Dan Zivkovic sForcedSubtypeForTesting = RichInputMethodSubtype.getRichInputMethodSubtype(subtype); 3357fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 3367fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka 3374486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka @Nonnull 338107fb4c476779df16be23e245547253978c197acDan Zivkovic public Locale getCurrentSubtypeLocale() { 3397fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka if (null != sForcedSubtypeForTesting) { 340107fb4c476779df16be23e245547253978c197acDan Zivkovic return sForcedSubtypeForTesting.getLocale(); 3417fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 342107fb4c476779df16be23e245547253978c197acDan Zivkovic return getCurrentSubtype().getLocale(); 3437fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 3447fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka 3454486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka @Nonnull 3467fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka public RichInputMethodSubtype getCurrentSubtype() { 3477fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka if (null != sForcedSubtypeForTesting) { 3487fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka return sForcedSubtypeForTesting; 3497fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 3507fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka return mCurrentRichInputMethodSubtype; 3517fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 3527fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka 3537fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka 3547fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka public String getCombiningRulesExtraValueOfCurrentSubtype() { 3557fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka return SubtypeLocaleUtils.getCombiningRulesExtraValue(getCurrentSubtype().getRawSubtype()); 3567fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka } 3577fb0ed58edd4cc2514f0b5dd5bd2083889ff325cTadashi G. Takaoka 3586fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public boolean hasMultipleEnabledIMEsOrSubtypes(final boolean shouldIncludeAuxiliarySubtypes) { 3596fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final List<InputMethodInfo> enabledImis = mImmWrapper.mImm.getEnabledInputMethodList(); 3606fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, enabledImis); 3616fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3626fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 3636fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public boolean hasMultipleEnabledSubtypesInThisIme( 3646fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final boolean shouldIncludeAuxiliarySubtypes) { 365ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka final List<InputMethodInfo> imiList = Collections.singletonList( 366ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka getInputMethodInfoOfThisIme()); 3676fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return hasMultipleEnabledSubtypes(shouldIncludeAuxiliarySubtypes, imiList); 3686fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3696fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 3706fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka private boolean hasMultipleEnabledSubtypes(final boolean shouldIncludeAuxiliarySubtypes, 3716fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final List<InputMethodInfo> imiList) { 3726fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // Number of the filtered IMEs 3736fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka int filteredImisCount = 0; 3746fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 3756fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka for (InputMethodInfo imi : imiList) { 3766fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // We can return true immediately after we find two or more filtered IMEs. 3776fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (filteredImisCount > 1) return true; 378ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard final List<InputMethodSubtype> subtypes = getEnabledInputMethodSubtypeList(imi, true); 3796fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // IMEs that have no subtypes should be counted. 3806fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (subtypes.isEmpty()) { 3816fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka ++filteredImisCount; 3826fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka continue; 3836fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3846fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 3856fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka int auxCount = 0; 3866fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka for (InputMethodSubtype subtype : subtypes) { 3876fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (subtype.isAuxiliary()) { 3886fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka ++auxCount; 3896fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3906fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3916fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final int nonAuxCount = subtypes.size() - auxCount; 3926fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 3936fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // IMEs that have one or more non-auxiliary subtypes should be counted. 3946fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // If shouldIncludeAuxiliarySubtypes is true, IMEs that have two or more auxiliary 3956fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // subtypes should be counted as well. 3966fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (nonAuxCount > 0 || (shouldIncludeAuxiliarySubtypes && auxCount > 1)) { 3976fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka ++filteredImisCount; 3986fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 3996fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4006fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 4016fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (filteredImisCount > 1) { 4026fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return true; 4036fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 404b902109000bcef184e69daac7dc3906fc969791eSatoshi Kataoka final List<InputMethodSubtype> subtypes = getMyEnabledInputMethodSubtypeList(true); 4056fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka int keyboardCount = 0; 4066fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // imm.getEnabledInputMethodSubtypeList(null, true) will return the current IME's 4076fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // both explicitly and implicitly enabled input method subtype. 4086fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka // (The current IME should be LatinIME.) 4096fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka for (InputMethodSubtype subtype : subtypes) { 4106fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (KEYBOARD_MODE.equals(subtype.getMode())) { 4116fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka ++keyboardCount; 4126fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4136fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4146fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return keyboardCount > 1; 4156fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4166fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 4176fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public InputMethodSubtype findSubtypeByLocaleAndKeyboardLayoutSet(final String localeString, 4186fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final String keyboardLayoutSetName) { 419ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka final InputMethodInfo myImi = getInputMethodInfoOfThisIme(); 4206fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final int count = myImi.getSubtypeCount(); 4216fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka for (int i = 0; i < count; i++) { 4226fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka final InputMethodSubtype subtype = myImi.getSubtypeAt(i); 423a410cb48eab0cd75aa27e20f60e47a29a59fb9ffTadashi G. Takaoka final String layoutName = SubtypeLocaleUtils.getKeyboardLayoutSetName(subtype); 4246fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka if (localeString.equals(subtype.getLocale()) 4256fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka && keyboardLayoutSetName.equals(layoutName)) { 4266fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return subtype; 4276fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4286fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4296fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka return null; 4306fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4316fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka 432809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa public InputMethodSubtype findSubtypeByLocale(final Locale locale) { 433809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa // Find the best subtype based on a straightforward matching algorithm. 434809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa // TODO: Use LocaleList#getFirstMatch() instead. 435809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final List<InputMethodSubtype> subtypes = 436809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa getMyEnabledInputMethodSubtypeList(true /* allowsImplicitlySelectedSubtypes */); 437809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final int count = subtypes.size(); 438809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa for (int i = 0; i < count; ++i) { 439809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final InputMethodSubtype subtype = subtypes.get(i); 440809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); 441809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa if (subtypeLocale.equals(locale)) { 442809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa return subtype; 443809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 444809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 445809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa for (int i = 0; i < count; ++i) { 446809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final InputMethodSubtype subtype = subtypes.get(i); 447809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); 448809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa if (subtypeLocale.getLanguage().equals(locale.getLanguage()) && 449809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa subtypeLocale.getCountry().equals(locale.getCountry()) && 450809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa subtypeLocale.getVariant().equals(locale.getVariant())) { 451809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa return subtype; 452809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 453809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 454809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa for (int i = 0; i < count; ++i) { 455809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final InputMethodSubtype subtype = subtypes.get(i); 456809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); 457809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa if (subtypeLocale.getLanguage().equals(locale.getLanguage()) && 458809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa subtypeLocale.getCountry().equals(locale.getCountry())) { 459809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa return subtype; 460809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 461809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 462809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa for (int i = 0; i < count; ++i) { 463809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final InputMethodSubtype subtype = subtypes.get(i); 464809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); 465809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa if (subtypeLocale.getLanguage().equals(locale.getLanguage())) { 466809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa return subtype; 467809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 468809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 469809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa return null; 470809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa } 471809c93214bd85f038c3abb09d8dee60f778b7746Yohei Yukawa 4721931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) { 4731931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka mImmWrapper.mImm.setInputMethodAndSubtype( 474ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka token, getInputMethodIdOfThisIme(), subtype); 4751931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka } 4761931c1cab1c2b077030210f2dd7a1839da7211bcTadashi G. Takaoka 4776fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka public void setAdditionalInputMethodSubtypes(final InputMethodSubtype[] subtypes) { 4786fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka mImmWrapper.mImm.setAdditionalInputMethodSubtypes( 479ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka getInputMethodIdOfThisIme(), subtypes); 480ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka // Clear the cache so that we go read the {@link InputMethodInfo} of this IME and list of 481ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka // subtypes again next time. 4824486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka refreshSubtypeCaches(); 483ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard } 484ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard 485ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard private List<InputMethodSubtype> getEnabledInputMethodSubtypeList(final InputMethodInfo imi, 486ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard final boolean allowsImplicitlySelectedSubtypes) { 487afd52dfc601c635e8a729b30b4ccf7a7fd7ad134Tadashi G. Takaoka return mInputMethodInfoCache.getEnabledInputMethodSubtypeList( 488ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard imi, allowsImplicitlySelectedSubtypes); 489ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard } 490ff6445ed0eac57f9daf573178ffe9f4e1e2b246aJean Chalard 4914486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka public void refreshSubtypeCaches() { 492ad5795a89117dbb5ebe4f1f308bc7e8a685ebf46Tadashi G. Takaoka mInputMethodInfoCache.clear(); 4934486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka updateCurrentSubtype(mImmWrapper.mImm.getCurrentInputMethodSubtype()); 4944486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka updateShortcutIme(); 4956fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka } 4968ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa 4978ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa public boolean shouldOfferSwitchingToNextInputMethod(final IBinder binder, 4988ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa boolean defaultValue) { 49958e248ebda82ef5ae16f3b5192635409ffad5f00Yohei Yukawa // Use the default value instead on Jelly Bean MR2 and previous where 50058e248ebda82ef5ae16f3b5192635409ffad5f00Yohei Yukawa // {@link InputMethodManager#shouldOfferSwitchingToNextInputMethod} isn't yet available 50158e248ebda82ef5ae16f3b5192635409ffad5f00Yohei Yukawa // and on KitKat where the API is still just a stub to return true always. 50258e248ebda82ef5ae16f3b5192635409ffad5f00Yohei Yukawa if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) { 5038ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa return defaultValue; 5048ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa } 5058ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa return mImmWrapper.shouldOfferSwitchingToNextInputMethod(binder); 5068ba4f33709e6c40ade96922f88feace6e4b75b56Yohei Yukawa } 5072a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka 5082a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka public boolean isSystemLocaleSameAsLocaleOfAllEnabledSubtypesOfEnabledImes() { 5092a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka final Locale systemLocale = mContext.getResources().getConfiguration().locale; 5102a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka final Set<InputMethodSubtype> enabledSubtypesOfEnabledImes = new HashSet<>(); 5112a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka final InputMethodManager inputMethodManager = getInputMethodManager(); 5122a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka final List<InputMethodInfo> enabledInputMethodInfoList = 5132a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka inputMethodManager.getEnabledInputMethodList(); 5142a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka for (final InputMethodInfo info : enabledInputMethodInfoList) { 5152a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka final List<InputMethodSubtype> enabledSubtypes = 5162a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka inputMethodManager.getEnabledInputMethodSubtypeList( 5172a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka info, true /* allowsImplicitlySelectedSubtypes */); 5182a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka if (enabledSubtypes.isEmpty()) { 5192a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka // An IME with no subtypes is found. 5202a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka return false; 5212a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka } 5222a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka enabledSubtypesOfEnabledImes.addAll(enabledSubtypes); 5232a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka } 5242a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka for (final InputMethodSubtype subtype : enabledSubtypesOfEnabledImes) { 5252a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka if (!subtype.isAuxiliary() && !subtype.getLocale().isEmpty() 5262a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka && !systemLocale.equals(SubtypeLocaleUtils.getSubtypeLocale(subtype))) { 5272a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka return false; 5282a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka } 5292a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka } 5302a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka return true; 5312a7da0ab87db1166c62c171858b589da3d9c2ca7Tadashi G. Takaoka } 5328a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka 533b86ca76cea9aedf47a81f9272fb59897de3bbbe7Dan Zivkovic private void updateCurrentSubtype(@Nullable final InputMethodSubtype subtype) { 534b86ca76cea9aedf47a81f9272fb59897de3bbbe7Dan Zivkovic mCurrentRichInputMethodSubtype = RichInputMethodSubtype.getRichInputMethodSubtype(subtype); 5354486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka } 5364486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka 5374486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka private void updateShortcutIme() { 5388a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka if (DEBUG) { 5398a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka Log.d(TAG, "Update shortcut IME from : " 5408a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka + (mShortcutInputMethodInfo == null 5418a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " 5428a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka + (mShortcutSubtype == null ? "<null>" : ( 5438a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); 5448a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 54531a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka final RichInputMethodSubtype richSubtype = mCurrentRichInputMethodSubtype; 54631a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka final boolean implicitlyEnabledSubtype = checkIfSubtypeBelongsToThisImeAndImplicitlyEnabled( 54731a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka richSubtype.getRawSubtype()); 54831a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka final Locale systemLocale = mContext.getResources().getConfiguration().locale; 54931a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka LanguageOnSpacebarUtils.onSubtypeChanged( 55031a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka richSubtype, implicitlyEnabledSubtype, systemLocale); 55131a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka LanguageOnSpacebarUtils.setEnabledSubtypes(getMyEnabledInputMethodSubtypeList( 55231a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka true /* allowsImplicitlySelectedSubtypes */)); 55331a10e226d23b30b24d9c902608ff013cc1c3e0cTadashi G. Takaoka 5548a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka // TODO: Update an icon for shortcut IME 5558a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka final Map<InputMethodInfo, List<InputMethodSubtype>> shortcuts = 5568a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka getInputMethodManager().getShortcutInputMethodsAndSubtypes(); 5578a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka mShortcutInputMethodInfo = null; 5588a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka mShortcutSubtype = null; 5598a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka for (final InputMethodInfo imi : shortcuts.keySet()) { 5608a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka final List<InputMethodSubtype> subtypes = shortcuts.get(imi); 5618a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka // TODO: Returns the first found IMI for now. Should handle all shortcuts as 5628a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka // appropriate. 5638a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka mShortcutInputMethodInfo = imi; 5648a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka // TODO: Pick up the first found subtype for now. Should handle all subtypes 5658a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka // as appropriate. 5668a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null; 5678a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka break; 5688a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 5698a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka if (DEBUG) { 5708a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka Log.d(TAG, "Update shortcut IME to : " 5718a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka + (mShortcutInputMethodInfo == null 5728a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " 5738a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka + (mShortcutSubtype == null ? "<null>" : ( 5748a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka mShortcutSubtype.getLocale() + ", " + mShortcutSubtype.getMode()))); 5758a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 5768a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 5778a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka 5784486314225c4bbb97f35cdbdbb2da1de4fc28be2Tadashi G. Takaoka public void switchToShortcutIme(final InputMethodService context) { 5798a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka if (mShortcutInputMethodInfo == null) { 5808a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka return; 5818a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 5828a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka 5838a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka final String imiId = mShortcutInputMethodInfo.getId(); 5848a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka switchToTargetIME(imiId, mShortcutSubtype, context); 5858a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 5868a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka 5878a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka private void switchToTargetIME(final String imiId, final InputMethodSubtype subtype, 5888a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka final InputMethodService context) { 5898a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka final IBinder token = context.getWindow().getWindow().getAttributes().token; 5908a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka if (token == null) { 5918a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka return; 5928a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 5938a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka final InputMethodManager imm = getInputMethodManager(); 5948a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka new AsyncTask<Void, Void, Void>() { 5958a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka @Override 5968a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka protected Void doInBackground(Void... params) { 5978a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka imm.setInputMethodAndSubtype(token, imiId, subtype); 5988a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka return null; 5998a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 6008a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 6018a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 6028a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka 6038a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka public boolean isShortcutImeReady() { 6048a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka if (mShortcutInputMethodInfo == null) { 6058a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka return false; 6068a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 6078a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka if (mShortcutSubtype == null) { 6088a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka return true; 6098a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 6108a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka return true; 6118a2c4afad4c30fe7c082387b4beafd95c3c823e8Tadashi G. Takaoka } 6126fbbab3b8442ad010c53dc53a09535f7b0ef0323Tadashi G. Takaoka} 613