KeyboardSwitcher.java revision 7a16a061e622539e54d7d649dcb8d4965aea575a
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/*
2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project
3571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka *
4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of
6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at
7571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka *
8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka *
10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under
14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License.
15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */
16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
17571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokapackage com.android.inputmethod.keyboard;
18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
19c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.content.Context;
20c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.content.SharedPreferences;
21364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaokaimport android.content.res.Configuration;
22c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.content.res.Resources;
23b39f612d9791877bf0136fa7af9ae054092b9eabTadashi G. Takaokaimport android.util.DisplayMetrics;
24c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.util.Log;
2513a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaokaimport android.view.ContextThemeWrapper;
26c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.InflateException;
27c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.LayoutInflater;
28c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.View;
29c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.inputmethod.EditorInfo;
30c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka
315ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy;
32b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.KeyboardState;
33f451ed2012df7eb080de045a93a494aecd2775b4Tadashi G. Takaokaimport com.android.inputmethod.latin.InputView;
34571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME;
35571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger;
36ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalardimport com.android.inputmethod.latin.LocaleUtils;
37571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
385cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaokaimport com.android.inputmethod.latin.Settings;
397a16a061e622539e54d7d649dcb8d4965aea575aJean Chalardimport com.android.inputmethod.latin.SettingsValues;
40571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeSwitcher;
415cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaokaimport com.android.inputmethod.latin.Utils;
425a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka
43681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaokaimport java.lang.ref.SoftReference;
4412659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.HashMap;
4512659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.Locale;
4612659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka
47eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaokapublic class KeyboardSwitcher implements KeyboardState.SwitchActions,
48eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        SharedPreferences.OnSharedPreferenceChangeListener {
49c25e07d21261583d0eeca5aa0fb6e3ffe93dc603Tadashi G. Takaoka    private static final String TAG = KeyboardSwitcher.class.getSimpleName();
50c25e07d21261583d0eeca5aa0fb6e3ffe93dc603Tadashi G. Takaoka    private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG;
51f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public static final boolean DEBUG_STATE = false;
52923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
532d9722e46c774d51c834c3a8b11261a2a22e09d3Ken Wakasa    public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20110916";
5405ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka    private static final int[] KEYBOARD_THEMES = {
5513a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka        R.style.KeyboardTheme,
5613a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka        R.style.KeyboardTheme_HighContrast,
5713a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka        R.style.KeyboardTheme_Stone,
5813a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka        R.style.KeyboardTheme_Stone_Bold,
5913a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka        R.style.KeyboardTheme_Gingerbread,
609116bf18f9c83084f9d451e2e709eff32db27d36Tadashi G. Takaoka        R.style.KeyboardTheme_IceCreamSandwich,
6175fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka    };
62979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
630ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
6427d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa    private SharedPreferences mPrefs;
650ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
66f451ed2012df7eb080de045a93a494aecd2775b4Tadashi G. Takaoka    private InputView mCurrentInputView;
67c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka    private LatinKeyboardView mKeyboardView;
680ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private LatinIME mInputMethodService;
690a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka    private String mPackageName;
700a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka    private Resources mResources;
7131adfa78e2edae188edb05e869f9f68798857582satok
72b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka    private KeyboardState mState;
73889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
7460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka    private KeyboardId mMainKeyboardId;
7560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka    private KeyboardId mSymbolsKeyboardId;
7660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka    private KeyboardId mSymbolsShiftedKeyboardId;
77353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
78353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mCurrentId;
798b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
808b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
81466741d8a78965b8509bf527344f289e50873092Mike LeBeau
821b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
8341feaaadb758a8b31d3e436063b4b5faed104d4dsatok     * what user actually typed. */
841b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private boolean mIsAutoCorrectionActive;
859e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka
865a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka    private int mThemeIndex = -1;
875a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka    private Context mThemeContext;
88979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
890ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
900ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
910ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    public static KeyboardSwitcher getInstance() {
920ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        return sInstance;
930ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
940ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
950ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private KeyboardSwitcher() {
96e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        // Intentional empty constructor for singleton.
970ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
980ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
9927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa    public static void init(LatinIME ims, SharedPreferences prefs) {
100364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        sInstance.initInternal(ims, prefs);
101364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka    }
102364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka
103364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka    private void initInternal(LatinIME ims, SharedPreferences prefs) {
104364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        mInputMethodService = ims;
105364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        mPackageName = ims.getPackageName();
106364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        mResources = ims.getResources();
107364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        mPrefs = prefs;
108364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        mSubtypeSwitcher = SubtypeSwitcher.getInstance();
109eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState = new KeyboardState(this);
110364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs));
111364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka        prefs.registerOnSharedPreferenceChangeListener(this);
1125a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka    }
113979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1145a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka    private static int getKeyboardThemeIndex(Context context, SharedPreferences prefs) {
1155a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka        final String defaultThemeId = context.getString(R.string.config_default_keyboard_theme_id);
1162d9722e46c774d51c834c3a8b11261a2a22e09d3Ken Wakasa        final String themeId = prefs.getString(PREF_KEYBOARD_LAYOUT, defaultThemeId);
11705ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka        try {
1185a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka            final int themeIndex = Integer.valueOf(themeId);
1195a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka            if (themeIndex >= 0 && themeIndex < KEYBOARD_THEMES.length)
1205a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka                return themeIndex;
12105ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka        } catch (NumberFormatException e) {
1225a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka            // Format error, keyboard theme is default to 0.
1235a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka        }
1245a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka        Log.w(TAG, "Illegal keyboard theme in preference: " + themeId + ", default to 0");
1255a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka        return 0;
1265a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka    }
1275a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka
1285a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka    private void setContextThemeWrapper(Context context, int themeIndex) {
1295a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka        if (mThemeIndex != themeIndex) {
1305a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka            mThemeIndex = themeIndex;
1315a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka            mThemeContext = new ContextThemeWrapper(context, KEYBOARD_THEMES[themeIndex]);
1325a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka            mKeyboardCache.clear();
13305ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka        }
134979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
135979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1367a16a061e622539e54d7d649dcb8d4965aea575aJean Chalard    public void loadKeyboard(EditorInfo editorInfo, SettingsValues settingsValues) {
137979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        try {
1382ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues);
1392ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues);
1402ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues);
141eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka            mState.onLoadKeyboard(mResources.getString(R.string.layout_switch_back_symbols));
142979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } catch (RuntimeException e) {
14360ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e);
14460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            LatinImeLogger.logOnException(mMainKeyboardId.toString(), e);
145979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
146353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
147353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
14859f8ca752d5f79d4469519623590052c050c9d23Tadashi G. Takaoka    public void saveKeyboardState() {
1492e263b70d5769b52cba4a002e44dbf81db5de7f8Tadashi G. Takaoka        if (mCurrentId != null) {
150cf58f53a1ab53b427a3d9784502b47ba1833b018Tadashi G. Takaoka            mState.onSaveKeyboardState(isAlphabetMode(), isSymbolShifted());
1512e263b70d5769b52cba4a002e44dbf81db5de7f8Tadashi G. Takaoka        }
152055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    }
153055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
154055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    public void onFinishInputView() {
155055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        mIsAutoCorrectionActive = false;
156055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    }
157055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
158c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka    public void onHideWindow() {
159c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka        mIsAutoCorrectionActive = false;
160c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka    }
161c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka
162055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    private void setKeyboard(final Keyboard keyboard) {
163c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        final Keyboard oldKeyboard = mKeyboardView.getKeyboard();
164055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        mKeyboardView.setKeyboard(keyboard);
165f451ed2012df7eb080de045a93a494aecd2775b4Tadashi G. Takaoka        mCurrentInputView.setKeyboardGeometry(keyboard.mTopPadding);
166055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        mCurrentId = keyboard.mId;
167eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onSetKeyboard(isAlphabetMode());
168055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        updateShiftLockState(keyboard);
169c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        mKeyboardView.setKeyPreviewPopupEnabled(
1707a16a061e622539e54d7d649dcb8d4965aea575aJean Chalard                SettingsValues.isKeyPreviewPopupEnabled(mPrefs, mResources),
1717a16a061e622539e54d7d649dcb8d4965aea575aJean Chalard                SettingsValues.getKeyPreviewPopupDismissDelay(mPrefs, mResources));
172050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        final boolean localeChanged = (oldKeyboard == null)
173055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka                || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
174050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
175286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa        updateShiftState();
176353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
177353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
178055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    private void updateShiftLockState(Keyboard keyboard) {
179055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        if (mCurrentId.equals(mSymbolsShiftedKeyboardId)) {
180055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            // Symbol keyboard may have an ALT key that has a caps lock style indicator (a.k.a.
181055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked()
182055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            // that takes care of the current keyboard having such ALT key or not.
183055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            keyboard.setShiftLocked(keyboard.hasShiftLockKey());
184055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        } else if (mCurrentId.equals(mSymbolsKeyboardId)) {
185055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
186055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            // indicator, we need to call setShiftLocked(false).
187055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka            keyboard.setShiftLocked(false);
188055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka        }
189055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka    }
190055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka
191353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private LatinKeyboard getKeyboard(KeyboardId id) {
1928b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
193681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        LatinKeyboard keyboard = (ref == null) ? null : ref.get();
194681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        if (keyboard == null) {
195ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard            final Locale savedLocale = LocaleUtils.setSystemLocale(mResources, id.mLocale);
1968da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            try {
197294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                final LatinKeyboard.Builder builder = new LatinKeyboard.Builder(mThemeContext);
198294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                builder.load(id);
199294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                builder.setTouchPositionCorrectionEnabled(
200294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                        mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(
201294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                                LatinIME.SUBTYPE_EXTRA_VALUE_SUPPORT_TOUCH_POSITION_CORRECTION));
202294e1b4a5abb86e58deefc8eee40e6b661524b28Yusuke Nojima                keyboard = builder.build();
2038da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            } finally {
204ef35cb631c45c8b106fe7ed9e0d1178c3e5fb963Jean Chalard                LocaleUtils.setSystemLocale(mResources, savedLocale);
2058da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            }
2068b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
2078da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka
2088da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            if (DEBUG_CACHE) {
2098b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
21063584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka                        + ((ref == null) ? "LOAD" : "GCed") + " id=" + id
21163584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka                        + " theme=" + Keyboard.themeName(keyboard.mThemeId));
2128da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka            }
213e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        } else if (DEBUG_CACHE) {
21463584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka            Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT  id=" + id
21563584323cab56c76debf6bb000621f2c605329a9Tadashi G. Takaoka                    + " theme=" + Keyboard.themeName(keyboard.mThemeId));
216353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
2178b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
2181b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive);
21973c02390d31bbf32b78763db66b04004666fb5a3Tadashi G. Takaoka        keyboard.setShiftLocked(false);
2208b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        keyboard.setShifted(false);
221de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        // If the cached keyboard had been switched to another keyboard while the language was
222de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        // displayed on its spacebar, it might have had arbitrary text fade factor. In such case,
2235cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaoka        // we should reset the text fade factor. It is also applicable to shortcut key.
224de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka        keyboard.setSpacebarTextFadeFactor(0.0f, null);
2254503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka        keyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady(), null);
226681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        return keyboard;
227353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
228353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
2292ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa    private KeyboardId getKeyboardId(EditorInfo editorInfo, final boolean isSymbols,
2307a16a061e622539e54d7d649dcb8d4965aea575aJean Chalard            final boolean isShift, SettingsValues settingsValues) {
2312ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        final int mode = Utils.getKeyboardMode(editorInfo);
23259c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka        final int xmlId;
23360ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka        switch (mode) {
23460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka        case KeyboardId.MODE_PHONE:
23560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            xmlId = (isSymbols && isShift) ? R.xml.kbd_phone_shift : R.xml.kbd_phone;
23660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            break;
23760ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka        case KeyboardId.MODE_NUMBER:
23860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            xmlId = R.xml.kbd_number;
23960ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            break;
24060ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka        default:
24160ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            if (isSymbols) {
24260ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka                xmlId = isShift ? R.xml.kbd_symbols_shift : R.xml.kbd_symbols;
2432c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            } else {
2442c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_qwerty;
2452c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            }
24660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka            break;
247923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
24860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka
249cee174b8ccb47ccddc8a8a7e88a9c617f9b5e766Ken Wakasa        final boolean settingsKeyEnabled = settingsValues.isSettingsKeyEnabled();
250ab72a97d7ce44230a0c824797d1675a5ca354a56Tadashi G. Takaoka        @SuppressWarnings("deprecation")
25173e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka        final boolean noMicrophone = Utils.inPrivateImeOptions(
25273e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka                mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo)
25373e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka                || Utils.inPrivateImeOptions(
25473e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka                        null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo);
25573e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka        final boolean voiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo)
25673e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka                && !noMicrophone;
2572ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        final boolean voiceKeyOnMain = settingsValues.isVoiceKeyOnMain();
2580a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka        final boolean noSettingsKey = Utils.inPrivateImeOptions(
2592ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa                mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, editorInfo);
2602ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        final boolean hasSettingsKey = settingsKeyEnabled && !noSettingsKey;
2612ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        final int f2KeyMode = getF2KeyMode(settingsKeyEnabled, noSettingsKey);
262c3afe2c244c14ed0f8a355fe608b3402e3656330Tadashi G. Takaoka        final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != voiceKeyOnMain);
263af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka        final boolean forceAscii = Utils.inPrivateImeOptions(
264af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka                mPackageName, LatinIME.IME_OPTION_FORCE_ASCII, editorInfo);
265af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka        final boolean asciiCapable = mSubtypeSwitcher.currentSubtypeContainsExtraValueKey(
266af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka                LatinIME.SUBTYPE_EXTRA_VALUE_ASCII_CAPABLE);
267af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka        final Locale locale = (forceAscii && !asciiCapable)
268af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka                ? Locale.US : mSubtypeSwitcher.getInputLocale();
2692ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        final Configuration conf = mResources.getConfiguration();
270b39f612d9791877bf0136fa7af9ae054092b9eabTadashi G. Takaoka        final DisplayMetrics dm = mResources.getDisplayMetrics();
2710a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka
2729b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        return new KeyboardId(
273af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka                mResources.getResourceEntryName(xmlId), xmlId, locale, conf.orientation,
274af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka                dm.widthPixels, mode, editorInfo, hasSettingsKey, f2KeyMode, noSettingsKey,
275af52c0ea04c6563feaa6ea7dbac5dd87c2a48cc6Tadashi G. Takaoka                voiceKeyEnabled, hasShortcutKey);
2764199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    }
2774199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
2783a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public int getKeyboardMode() {
279cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT;
280923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2811679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2826ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka    // TODO: Delegate to KeyboardState
2833a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public boolean isAlphabetMode() {
284571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        return mCurrentId != null && mCurrentId.isAlphabetKeyboard();
285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2871679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isInputViewShown() {
28886e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka        return mCurrentInputView != null && mCurrentInputView.isShown();
2891679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2901679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2911679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isKeyboardAvailable() {
292c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        if (mKeyboardView != null)
293c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            return mKeyboardView.getKeyboard() != null;
294b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
295b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
296b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
297050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka    public LatinKeyboard getLatinKeyboard() {
298c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        if (mKeyboardView != null) {
299c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            final Keyboard keyboard = mKeyboardView.getKeyboard();
300050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka            if (keyboard instanceof LatinKeyboard)
301050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka                return (LatinKeyboard)keyboard;
302050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        }
303b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return null;
3041679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3051679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
306f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isShiftedOrShiftLocked() {
307c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka        return mState.isShiftedOrShiftLocked();
308f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
309f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
310f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isManualTemporaryUpperCase() {
311c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka        return mState.isManualTemporaryUpperCase();
312f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
313f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
314eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    // Implements {@link KeyboardState.SwitchActions}.
315eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    @Override
316eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    public void setShifted(int shiftMode) {
317f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka        mInputMethodService.mHandler.cancelUpdateShiftState();
318b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
3196ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka        if (latinKeyboard == null)
3206ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka            return;
3216ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka        if (shiftMode == AUTOMATIC_SHIFT) {
322c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            mState.setAutomaticTemporaryUpperCase();
3236ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka            latinKeyboard.setAutomaticTemporaryUpperCase();
3246ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka        } else {
3256ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka            final boolean shifted = (shiftMode == MANUAL_SHIFT);
3260d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // On non-distinct multi touch panel device, we should also turn off the shift locked
3270d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // state when shift key is pressed to go to normal mode.
3286ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka            // On the other hand, on distinct multi touch panel device, turning off the shift
3296ddb07433fc8ed8675f0996a48790a05a97b61f0Tadashi G. Takaoka            // locked state with shift key pressing is handled by onReleaseShift().
330101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) {
331c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka                mState.setShiftLocked(false);
3320d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka                latinKeyboard.setShiftLocked(false);
3330d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            }
334c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            mState.setShifted(shifted);
3354f7f61730cbd45871c1e9044da84b494831f97c3Tadashi G. Takaoka            latinKeyboard.setShifted(shifted);
336979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
3374f7f61730cbd45871c1e9044da84b494831f97c3Tadashi G. Takaoka        mKeyboardView.invalidateAllKeys();
338979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
339979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
340eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    // Implements {@link KeyboardState.SwitchActions}.
341eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    @Override
342eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    public void setShiftLocked(boolean shiftLocked) {
343f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka        mInputMethodService.mHandler.cancelUpdateShiftState();
344b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
345c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka        if (latinKeyboard == null)
346c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            return;
347c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka        mState.setShiftLocked(shiftLocked);
348c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka        latinKeyboard.setShiftLocked(shiftLocked);
349c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka        mKeyboardView.invalidateAllKeys();
350f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka        if (!shiftLocked) {
351f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka            // To be able to turn off caps lock by "double tap" on shift key, we should ignore
352f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka            // the second tap of the "double tap" from now for a while because we just have
353f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka            // already turned off caps lock above.
354f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka            mKeyboardView.startIgnoringDoubleTap();
355f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka        }
356979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
357979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3580d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka    /**
3590d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     * Toggle keyboard shift state triggered by user touch event.
3600d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     */
361b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void toggleShift() {
362b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
363c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "toggleShift: " + mState);
364b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        }
365b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
366c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            setShifted(mState.isShiftedOrShiftLocked() ? UNSHIFT : MANUAL_SHIFT);
367b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        } else {
3686ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka            if (isSymbolShifted()) {
3696ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka                setSymbolsKeyboard();
3706ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka            } else {
3716ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka                setSymbolsShiftedKeyboard();
3726ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka            }
373b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
374b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
375b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
3766ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka    /**
3776ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka     * Toggle caps lock state triggered by user touch event.
3786ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka     */
379b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void toggleCapsLock() {
380b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
381c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "toggleCapsLock: " + mState);
382b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        }
383b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
384c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            if (mState.isShiftLocked()) {
385f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka                setShiftLocked(false);
386f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka                // TODO: Remove this.
387f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift key is long pressed while caps lock state, we will toggle back to normal
388f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // state. And mark as if shift key is released.
389f47993ee34d1111fdbb1afb44fcac64a132a2e57Tadashi G. Takaoka                mState.onReleaseCapsLock();
390b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            } else {
391b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                setShiftLocked(true);
392b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
393b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
394889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
395889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
3966ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka    /**
3976ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka     * Toggle keyboard mode triggered by user touch event.
3986ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka     */
3998a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka    public void toggleKeyboardMode() {
40046831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka        if (DEBUG_STATE) {
4016ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka            Log.d(TAG, "toggleKeyboardMode: " + mState);
4026ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka        }
4036ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka        if (isAlphabetMode()) {
4046ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka            setSymbolsKeyboard();
4056ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka        } else {
4066ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka            setAlphabetKeyboard();
40746831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka        }
40846831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka    }
40946831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka
4100d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka    /**
4110d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     * Update keyboard shift state triggered by connected EditText status change.
4120d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     */
413b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void updateShiftState() {
414b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
415c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "updateShiftState: " + mState
416c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka                    + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState());
417b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        }
418eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onUpdateShiftState(isAlphabetMode(), mInputMethodService.getCurrentAutoCapsState());
419889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
420889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
421e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPressShift(boolean withSliding) {
422b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!isKeyboardAvailable())
423b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return;
424b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
425c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "onPressShift: " + mState + " sliding=" + withSliding);
426b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        }
427eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onPressShift(isAlphabetMode(), isSymbolShifted());
428b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
429b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
430e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onReleaseShift(boolean withSliding) {
431b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!isKeyboardAvailable())
432b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return;
433b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
434c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "onReleaseShift: " + mState + " sliding=" + withSliding);
435b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        }
436eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onReleaseShift(isAlphabetMode(), isSymbolShifted(), withSliding);
437889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
438889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
4396c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onPressSymbol() {
440b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
441c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "onPressSymbol: " + mState);
442b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        }
443eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onPressSymbol(isAlphabetMode());
4446c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4456c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4466c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onReleaseSymbol() {
447b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
448c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "onReleaseSymbol: " + mState);
449717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        }
450eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onReleaseSymbol(isAlphabetMode());
4516c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4526c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4536c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onOtherKeyPressed() {
454b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        if (DEBUG_STATE) {
455c1859b8fd22b2c4cc2a700566f57f3e3d04e1580Tadashi G. Takaoka            Log.d(TAG, "onOtherKeyPressed: " + mState);
456b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        }
457b88c9acd88348c160e3d114593660bfd362bee29Tadashi G. Takaoka        mState.onOtherKeyPressed();
4586c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4596c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4605f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    public void onCancelInput() {
461eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onCancelInput(isAlphabetMode(), isSymbolShifted(), isSinglePointer());
4625f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    }
4635f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka
464eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    // Implements {@link KeyboardState.SwitchActions}.
465eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    @Override
466eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    public void setSymbolsKeyboard() {
4676ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka        mState.onSaveShiftLockState();
4688a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka        setKeyboard(getKeyboard(mSymbolsKeyboardId));
4698a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka    }
4708a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka
471eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    // Implements {@link KeyboardState.SwitchActions}.
472eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    @Override
473eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    public void setAlphabetKeyboard() {
4748a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka        setKeyboard(getKeyboard(mMainKeyboardId));
4756ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka        mState.onRestoreShiftLockState();
47646831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka    }
47746831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka
4786ad9b012d947458155609e418aaeb3904cf27f6fTadashi G. Takaoka    // TODO: Remove this method
4798a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka    private boolean isSymbolShifted() {
4808a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka        return mCurrentId != null && mCurrentId.equals(mSymbolsShiftedKeyboardId);
4818a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka    }
4828a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka
483eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    // Implements {@link KeyboardState.SwitchActions}.
484eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    @Override
485eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    public void setSymbolsShiftedKeyboard() {
4868a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka        setKeyboard(getKeyboard(mSymbolsShiftedKeyboardId));
4878a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka    }
4888a70e70c849cc2c5553c6fd79891c22893fd761bTadashi G. Takaoka
489717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    public boolean isInMomentarySwitchState() {
490eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        return mState.isInMomentarySwitchState();
4919e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka    }
4929e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka
493cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka    public boolean isVibrateAndSoundFeedbackRequired() {
494416ee19d330f08e329cce4fd7cb66003cfb64f4aTadashi G. Takaoka        return mKeyboardView != null && !mKeyboardView.isInSlidingKeyInput();
495cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka    }
496cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka
49746831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka    private boolean isSinglePointer() {
49846831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka        return mKeyboardView != null && mKeyboardView.getPointerCount() == 1;
499b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    }
500b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
501c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    public boolean hasDistinctMultitouch() {
502c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch();
503c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    }
504c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka
505b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    /**
5069e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka     * Updates state machine to figure out when to automatically snap back to the previous mode.
507b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani     */
508eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka    public void onCodeInput(int code) {
50946831d5a4b135e5c21f2212d1d8aef09806800edTadashi G. Takaoka        if (DEBUG_STATE) {
510eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka            Log.d(TAG, "onCodeInput: code=" + code + " isSinglePointer=" + isSinglePointer()
511eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka                    + " " + mState);
512b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
513eef6238f94b5046054d9ae9c06f775362893c0eeTadashi G. Takaoka        mState.onCodeInput(isAlphabetMode(), isSymbolShifted(), code, isSinglePointer());
514923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
515979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
516c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka    public LatinKeyboardView getKeyboardView() {
517c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return mKeyboardView;
518979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
519979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
520c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    public View onCreateInputView() {
521f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        return createInputView(mThemeIndex, true);
522979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
523979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
524f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka    private View createInputView(final int newThemeIndex, final boolean forceRecreate) {
525f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        if (mCurrentInputView != null && mThemeIndex == newThemeIndex && !forceRecreate)
526f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            return mCurrentInputView;
527f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka
528f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        if (mKeyboardView != null) {
529f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            mKeyboardView.closing();
530f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        }
531f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka
5325a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka        final int oldThemeIndex = mThemeIndex;
533f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
534f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        boolean tryGC = true;
535f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
536f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            try {
5375a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka                setContextThemeWrapper(mInputMethodService, newThemeIndex);
538f451ed2012df7eb080de045a93a494aecd2775b4Tadashi G. Takaoka                mCurrentInputView = (InputView)LayoutInflater.from(mThemeContext).inflate(
53913a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka                        R.layout.input_view, null);
540f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                tryGC = false;
541f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            } catch (OutOfMemoryError e) {
542f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                Log.w(TAG, "load keyboard failed: " + e);
5435a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait(
5445a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka                        oldThemeIndex + "," + newThemeIndex, e);
545f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            } catch (InflateException e) {
546f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                Log.w(TAG, "load keyboard failed: " + e);
5475a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait(
5485a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka                        oldThemeIndex + "," + newThemeIndex, e);
549979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
550979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
551f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka
552c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka        mKeyboardView = (LatinKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view);
5535a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka        mKeyboardView.setKeyboardActionListener(mInputMethodService);
5545ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette
5555ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette        // This always needs to be set since the accessibility state can
5565ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette        // potentially change without the input view being re-created.
5575ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette        AccessibleKeyboardViewProxy.setView(mKeyboardView);
5585ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette
559f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        return mCurrentInputView;
5608d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    }
5618d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka
562f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka    private void postSetInputView(final View newInputView) {
563979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mInputMethodService.mHandler.post(new Runnable() {
5648d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            @Override
565979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            public void run() {
566f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                if (newInputView != null) {
567f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                    mInputMethodService.setInputView(newInputView);
568979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
569979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mInputMethodService.updateInputViewShown();
5708d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            }
5718d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        });
572979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
573979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5748d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    @Override
575979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
576979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (PREF_KEYBOARD_LAYOUT.equals(key)) {
5772ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            final int themeIndex = getKeyboardThemeIndex(mInputMethodService, sharedPreferences);
5782ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            postSetInputView(createInputView(themeIndex, false));
5792ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        } else if (Settings.PREF_SHOW_SETTINGS_KEY.equals(key)) {
580f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            postSetInputView(createInputView(mThemeIndex, true));
581979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
582979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
583979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5841b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onAutoCorrectionStateChanged(boolean isAutoCorrection) {
5855e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka        if (mIsAutoCorrectionActive != isAutoCorrection) {
5861b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mIsAutoCorrectionActive = isAutoCorrection;
5875e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka            final LatinKeyboard keyboard = getLatinKeyboard();
5885e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka            if (keyboard != null && keyboard.needsAutoCorrectionSpacebarLed()) {
5895e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka                final Key invalidatedKey = keyboard.onAutoCorrectionStateChanged(isAutoCorrection);
590c84bc3460d2fb386a1db2a2c8b135b746fa706cdTadashi G. Takaoka                final LatinKeyboardView keyboardView = getKeyboardView();
5915e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka                if (keyboardView != null)
5925e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka                    keyboardView.invalidateKey(invalidatedKey);
5935e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka            }
59441feaaadb758a8b31d3e436063b4b5faed104d4dsatok        }
59541feaaadb758a8b31d3e436063b4b5faed104d4dsatok    }
5961508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa
5972ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa    private static int getF2KeyMode(boolean settingsKeyEnabled, boolean noSettingsKey) {
5982ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        if (noSettingsKey) {
5992ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            // Never shows the Settings key
600cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka            return KeyboardId.F2KEY_MODE_SHORTCUT_IME;
601cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka        }
6022ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa
6032ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        if (settingsKeyEnabled) {
6042ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            return KeyboardId.F2KEY_MODE_SETTINGS;
6052ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        } else {
6062ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            // It should be alright to fall back to the Settings key on 7-inch layouts
6072ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            // even when the Settings key is not explicitly enabled.
6082ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa            return KeyboardId.F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS;
6092ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa        }
610cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka    }
611923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
612