KeyboardSwitcher.java revision f3cd2bb33d1688fd6de01787140a1ef2de4b7723
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;
21c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.content.res.Resources;
22c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.util.Log;
23c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.InflateException;
24c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.LayoutInflater;
25c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.View;
26c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.inputmethod.EditorInfo;
27c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka
28610f1dc8553cf2ed97e763a06a19380c4a6cd636satokimport com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
29571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME;
30571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger;
31571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
325cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaokaimport com.android.inputmethod.latin.Settings;
33571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeSwitcher;
345cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaokaimport com.android.inputmethod.latin.Utils;
355a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka
36681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaokaimport java.lang.ref.SoftReference;
3712659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.HashMap;
3812659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.Locale;
3912659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka
40979f8690967ff5409fe18f5085858ccdb8e0ccf1satokpublic class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
418b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static final String TAG = "KeyboardSwitcher";
42e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    private static final boolean DEBUG_CACHE = false;
43f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public static final boolean DEBUG_STATE = false;
44923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
4505ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka    private static String sConfigDefaultKeyboardThemeId;
46a327485e595c9f7676989097c830ff452085d4c9satok    public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
4705ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka    private static final int[] KEYBOARD_THEMES = {
4875fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_basic,
4975fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_basic_highcontrast,
5075fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_stone_normal,
5175fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_stone_bold,
5275fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_gingerbread,
5305ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka        R.layout.input_honeycomb,
5475fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka    };
55979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
560ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
5727d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa    private SharedPreferences mPrefs;
580ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
59c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    private LatinKeyboardView mKeyboardView;
600ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private LatinIME mInputMethodService;
6131adfa78e2edae188edb05e869f9f68798857582satok
62717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    // TODO: Combine these key state objects with auto mode switch state.
63f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
64f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
65889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
66353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mSymbolsId;
67353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mSymbolsShiftedId;
68353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
69353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mCurrentId;
708b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
718b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
72466741d8a78965b8509bf527344f289e50873092Mike LeBeau
734b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka    private EditorInfo mAttribute;
74353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private boolean mIsSymbols;
751b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
7641feaaadb758a8b31d3e436063b4b5faed104d4dsatok     * what user actually typed. */
771b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private boolean mIsAutoCorrectionActive;
7804448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka    private boolean mVoiceKeyEnabled;
79507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private boolean mVoiceButtonOnPrimary;
809e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka
81717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState
82717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    // and ModifierKeyState.
83717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static final int SWITCH_STATE_ALPHA = 0;
84717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static final int SWITCH_STATE_SYMBOL_BEGIN = 1;
85717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static final int SWITCH_STATE_SYMBOL = 2;
869e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka    // The following states are used only on the distinct multi-touch panel devices.
87717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3;
88717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4;
89717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static final int SWITCH_STATE_CHORDING_ALPHA = 5;
90717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static final int SWITCH_STATE_CHORDING_SYMBOL = 6;
91717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private int mSwitchState = SWITCH_STATE_ALPHA;
92923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
934199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    // Indicates whether or not we have the settings key in option of settings
944199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    private boolean mSettingsKeyEnabledInSettings;
951508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto;
96503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka    private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW =
97503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka            R.string.settings_key_mode_always_show;
9817fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to
9917fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // in the source code now.
10017fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // Default is SETTINGS_KEY_MODE_AUTO.
10117fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO;
1021508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa
103f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka    private int mThemeIndex;
104e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    private int mKeyboardWidth;
105979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1060ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
1070ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
1080ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    public static KeyboardSwitcher getInstance() {
1090ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        return sInstance;
1100ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
1110ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
1120ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private KeyboardSwitcher() {
113e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        // Intentional empty constructor for singleton.
1140ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
1150ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
11627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa    public static void init(LatinIME ims, SharedPreferences prefs) {
1170ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        sInstance.mInputMethodService = ims;
11827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        sInstance.mPrefs = prefs;
1190ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance();
120979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
12105ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka        try {
12205ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka            sConfigDefaultKeyboardThemeId = ims.getString(
12305ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka                    R.string.config_default_keyboard_theme_id);
124f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            sInstance.mThemeIndex = Integer.valueOf(
12505ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka                    prefs.getString(PREF_KEYBOARD_LAYOUT, sConfigDefaultKeyboardThemeId));
12605ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka        } catch (NumberFormatException e) {
12705ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka            sConfigDefaultKeyboardThemeId = "0";
128f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            sInstance.mThemeIndex = 0;
12905ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka        }
1300ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        prefs.registerOnSharedPreferenceChangeListener(sInstance);
131979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
132979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
133cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    public void loadKeyboard(EditorInfo attribute, boolean voiceKeyEnabled,
134507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka            boolean voiceButtonOnPrimary) {
135717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        mSwitchState = SWITCH_STATE_ALPHA;
136979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        try {
137cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            loadKeyboardInternal(attribute, voiceKeyEnabled, voiceButtonOnPrimary, false);
138979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } catch (RuntimeException e) {
1394b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka            // Get KeyboardId to record which keyboard has been failed to load.
140cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka            final KeyboardId id = getKeyboardId(attribute, false);
1414b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka            Log.w(TAG, "loading keyboard failed: " + id, e);
1424b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka            LatinImeLogger.logOnException(id.toString(), e);
143979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
144353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
145353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
146cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private void loadKeyboardInternal(EditorInfo attribute, boolean voiceButtonEnabled,
147507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka            boolean voiceButtonOnPrimary, boolean isSymbols) {
148c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        if (mKeyboardView == null) return;
1498b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
1504b13b4f94215368c6387b2564bdaf2cbcbe4c130Tadashi G. Takaoka        mAttribute = attribute;
15104448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka        mVoiceKeyEnabled = voiceButtonEnabled;
1528b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mVoiceButtonOnPrimary = voiceButtonOnPrimary;
153c5bb4591b67b165f007e29bd9424d319ac3c7c28Brandon Ballinger        mIsSymbols = isSymbols;
1548b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        // Update the settings key state because number of enabled IMEs could have been changed
1554199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka        mSettingsKeyEnabledInSettings = getSettingsKeyMode(mPrefs, mInputMethodService);
156cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        final KeyboardId id = getKeyboardId(attribute, isSymbols);
157e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka
158e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // Note: This comment is only applied for phone number keyboard layout.
159e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
160e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // between "phone keyboard" and "phone symbols keyboard".  But on xlarge device,
161e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // "@integer/key_shift" key code is used for that purpose in order to properly display
162e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // "more" and "locked more" key labels.  To achieve these behavior, we should initialize
163e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
164e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // respectively here for xlarge device's layout switching.
165e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        mSymbolsId = makeSiblingKeyboardId(id, R.xml.kbd_symbols, R.xml.kbd_phone);
166e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        mSymbolsShiftedId = makeSiblingKeyboardId(
167e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka                id, R.xml.kbd_symbols_shift, R.xml.kbd_phone_symbols);
168e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka
169050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        setKeyboard(getKeyboard(id));
170050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka    }
171050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka
172e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    public void onSizeChanged() {
173e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        final int width = mInputMethodService.getWindow().getWindow().getDecorView().getWidth();
174e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        if (width == 0)
175e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka            return;
176e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        mKeyboardWidth = width;
177e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        // Set keyboard with new width.
178e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        final KeyboardId newId = mCurrentId.cloneWithNewGeometry(width);
179e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        setKeyboard(getKeyboard(newId));
180e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    }
181e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka
182050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka    private void setKeyboard(final Keyboard newKeyboard) {
183c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        final Keyboard oldKeyboard = mKeyboardView.getKeyboard();
184c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        mKeyboardView.setKeyboard(newKeyboard);
185e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        mCurrentId = newKeyboard.mId;
186e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        final Resources res = mInputMethodService.getResources();
187c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        mKeyboardView.setKeyPreviewPopupEnabled(
188e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka                Settings.Values.isKeyPreviewPopupEnabled(mPrefs, res),
189e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka                Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, res));
190050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        final boolean localeChanged = (oldKeyboard == null)
191050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka                || !newKeyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale);
192050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged);
193353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
194353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
195353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private LatinKeyboard getKeyboard(KeyboardId id) {
1968b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
197681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        LatinKeyboard keyboard = (ref == null) ? null : ref.get();
198681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        if (keyboard == null) {
199309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard            final Resources res = mInputMethodService.getResources();
200309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard            final Locale savedLocale = Utils.setSystemLocale(res,
2010ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                    mSubtypeSwitcher.getInputLocale());
2028b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
203e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka            keyboard = new LatinKeyboard(mInputMethodService, id, id.mWidth);
204358e485b14938fbcb5af5be75aa29f2b73674100Amith Yamasani
205353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            if (id.mEnableShiftLock) {
206353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger                keyboard.enableShiftLock();
207353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            }
2088b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
2098b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
210e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka            if (DEBUG_CACHE)
2118b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
2128b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                        + ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
21336fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
214309bff562fbaf47488e6bf6636840f00574187d8Jean Chalard            Utils.setSystemLocale(res, savedLocale);
215e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        } else if (DEBUG_CACHE) {
2168b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT  id=" + id);
217353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
2188b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
2191b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive);
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);
22675136cd009ef37b9a5a013200444e149f8461ff5Tadashi G. Takaoka        keyboard.setSpacebarSlidingLanguageSwitchDiff(0);
227681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        return keyboard;
228353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
229353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
2304199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    private boolean hasVoiceKey(boolean isSymbols) {
2314199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka        return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
2324199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    }
2334199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
2344199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    private boolean hasSettingsKey(EditorInfo attribute) {
2354199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka        return mSettingsKeyEnabledInSettings
2364199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka            && !Utils.inPrivateImeOptions(mInputMethodService.getPackageName(),
2374199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka                    LatinIME.IME_OPTION_NO_SETTINGS_KEY, attribute);
2384199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    }
2394199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
240cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka    private KeyboardId getKeyboardId(EditorInfo attribute, boolean isSymbols) {
241cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        final int mode = Utils.getKeyboardMode(attribute);
2428b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final boolean hasVoiceKey = hasVoiceKey(isSymbols);
24359c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka        final int charColorId = getColorScheme();
24459c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka        final int xmlId;
245e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        final boolean enableShiftLock;
246e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa
247e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        if (isSymbols) {
2485a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            if (mode == KeyboardId.MODE_PHONE) {
2492c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_phone_symbols;
2505a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            } else if (mode == KeyboardId.MODE_NUMBER) {
2512c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                // Note: MODE_NUMBER keyboard layout has no "switch alpha symbol" key.
2522c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_number;
2532c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            } else {
2542c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_symbols;
2552c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            }
256e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa            enableShiftLock = false;
2572c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka        } else {
2585a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            if (mode == KeyboardId.MODE_PHONE) {
2592c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_phone;
2602c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                enableShiftLock = false;
2615a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            } else if (mode == KeyboardId.MODE_NUMBER) {
2622c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_number;
2632c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                enableShiftLock = false;
2642c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            } else {
2652c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_qwerty;
2662c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                enableShiftLock = true;
2672c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            }
268923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2694199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka        final boolean hasSettingsKey = hasSettingsKey(attribute);
2709b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        final Resources res = mInputMethodService.getResources();
2719b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        final int orientation = res.getConfiguration().orientation;
272e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        if (mKeyboardWidth == 0)
273e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka            mKeyboardWidth = res.getDisplayMetrics().widthPixels;
2740ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        final Locale locale = mSubtypeSwitcher.getInputLocale();
2759b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        return new KeyboardId(
276e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka                res.getResourceEntryName(xmlId), xmlId, charColorId, locale, orientation,
277e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka                mKeyboardWidth, mode, attribute, hasSettingsKey, mVoiceKeyEnabled, hasVoiceKey,
278e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka                enableShiftLock);
2794199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka    }
2804199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka
281e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka    private KeyboardId makeSiblingKeyboardId(KeyboardId base, int alphabet, int phone) {
282e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        final int xmlId = base.mMode == KeyboardId.MODE_PHONE ? phone : alphabet;
283e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        final String xmlName = mInputMethodService.getResources().getResourceEntryName(xmlId);
284e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka        return base.cloneWithNewLayout(xmlName, xmlId);
285923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
286923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2873a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public int getKeyboardMode() {
288cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT;
289923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2901679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2913a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public boolean isAlphabetMode() {
292571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        return mCurrentId != null && mCurrentId.isAlphabetKeyboard();
293923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
294923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2951679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isInputViewShown() {
296c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return mKeyboardView != null && mKeyboardView.isShown();
2971679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2981679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2991679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isKeyboardAvailable() {
300c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        if (mKeyboardView != null)
301c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            return mKeyboardView.getKeyboard() != null;
302b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
303b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
304b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
305050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka    public LatinKeyboard getLatinKeyboard() {
306c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        if (mKeyboardView != null) {
307c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            final Keyboard keyboard = mKeyboardView.getKeyboard();
308050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka            if (keyboard instanceof LatinKeyboard)
309050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka                return (LatinKeyboard)keyboard;
310050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        }
311b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return null;
3121679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3131679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
314f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isShiftedOrShiftLocked() {
315b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
316b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null)
317f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            return latinKeyboard.isShiftedOrShiftLocked();
318b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
3191679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3201679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
3211679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isShiftLocked() {
322b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
323b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null)
324b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return latinKeyboard.isShiftLocked();
325b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
3261679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
3271679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
328f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isAutomaticTemporaryUpperCase() {
329f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
330f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (latinKeyboard != null)
331f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            return latinKeyboard.isAutomaticTemporaryUpperCase();
332f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        return false;
333f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
334f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
335f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isManualTemporaryUpperCase() {
336f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
337f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (latinKeyboard != null)
338f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            return latinKeyboard.isManualTemporaryUpperCase();
339f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        return false;
340f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
341f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
342d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka    private boolean isManualTemporaryUpperCaseFromAuto() {
343d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
344d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka        if (latinKeyboard != null)
345d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka            return latinKeyboard.isManualTemporaryUpperCaseFromAuto();
346d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka        return false;
347d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka    }
348d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka
349f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private void setManualTemporaryUpperCase(boolean shifted) {
350b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
3510d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka        if (latinKeyboard != null) {
3520d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // On non-distinct multi touch panel device, we should also turn off the shift locked
3530d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // state when shift key is pressed to go to normal mode.
3540d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // On the other hand, on distinct multi touch panel device, turning off the shift locked
3550d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // state with shift key pressing is handled by onReleaseShift().
356101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka            if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) {
3570d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka                latinKeyboard.setShiftLocked(false);
3580d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            }
3590d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            if (latinKeyboard.setShifted(shifted)) {
360c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                mKeyboardView.invalidateAllKeys();
3610d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            }
362979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
363979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
364979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
365b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    private void setShiftLocked(boolean shiftLocked) {
366b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
367b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) {
368c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            mKeyboardView.invalidateAllKeys();
369b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
370979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
371979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3720d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka    /**
3730d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     * Toggle keyboard shift state triggered by user touch event.
3740d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     */
375b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void toggleShift() {
376b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mInputMethodService.mHandler.cancelUpdateShiftState();
377f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
378f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "toggleShift:"
379f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
380f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState);
381b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
382f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            setManualTemporaryUpperCase(!isShiftedOrShiftLocked());
383b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        } else {
384b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            toggleShiftInSymbol();
385b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
386b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
387b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
388b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void toggleCapsLock() {
389b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mInputMethodService.mHandler.cancelUpdateShiftState();
390f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
391f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "toggleCapsLock:"
392f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
393f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState);
394b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
395b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            if (isShiftLocked()) {
396f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift key is long pressed while caps lock state, we will toggle back to normal
397f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // state. And mark as if shift key is released.
398f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                setShiftLocked(false);
399f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                mShiftKeyState.onRelease();
400b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            } else {
401b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                setShiftLocked(true);
402b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
403b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
404889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
405889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
406f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private void setAutomaticTemporaryUpperCase() {
407f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
408f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (latinKeyboard != null) {
409f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            latinKeyboard.setAutomaticTemporaryUpperCase();
410c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            mKeyboardView.invalidateAllKeys();
411f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        }
412f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
413f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
4140d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka    /**
4150d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     * Update keyboard shift state triggered by connected EditText status change.
4160d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     */
417b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void updateShiftState() {
41845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final ShiftKeyState shiftKeyState = mShiftKeyState;
419f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
420f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "updateShiftState:"
421f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState()
422f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
42345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " shiftKeyState=" + shiftKeyState);
42445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (isAlphabetMode()) {
42545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            if (!isShiftLocked() && !shiftKeyState.isIgnoring()) {
42645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) {
42745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    // Only when shift key is releasing, automatic temporary upper case will be set.
42845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    setAutomaticTemporaryUpperCase();
42945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                } else {
43045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    setManualTemporaryUpperCase(shiftKeyState.isMomentary());
43145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                }
432f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            }
43345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        } else {
43445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            // In symbol keyboard mode, we should clear shift key state because only alphabet
43545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            // keyboard has shift key.
43645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            shiftKeyState.onRelease();
437b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
438889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
439889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
440b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void changeKeyboardMode() {
441f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
442f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "changeKeyboardMode:"
443f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
444f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState);
445b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        toggleKeyboardMode();
446b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isShiftLocked() && isAlphabetMode())
447b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            setShiftLocked(true);
448b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        updateShiftState();
449889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
450889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
451e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onPressShift(boolean withSliding) {
452b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!isKeyboardAvailable())
453b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return;
454f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        ShiftKeyState shiftKeyState = mShiftKeyState;
455f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
456f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "onPressShift:"
457f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
458e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka                    + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding);
459f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (isAlphabetMode()) {
460f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (isShiftLocked()) {
461f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift key is pressed while caps lock state, we will treat this state as shifted
462f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // caps lock state and mark as if shift key pressed while normal state.
463f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                shiftKeyState.onPress();
4646769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka                setManualTemporaryUpperCase(true);
465f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else if (isAutomaticTemporaryUpperCase()) {
466f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift key is pressed while automatic temporary upper case, we have to move to
467f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // manual temporary upper case.
4686769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka                shiftKeyState.onPress();
469f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                setManualTemporaryUpperCase(true);
470f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else if (isShiftedOrShiftLocked()) {
471f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // In manual upper case state, we just record shift key has been pressing while
472f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // shifted state.
473f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                shiftKeyState.onPressOnShifted();
474f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else {
475f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // In base layout, chording or manual temporary upper case mode is started.
476f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                shiftKeyState.onPress();
4776769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka                toggleShift();
478f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            }
479b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        } else {
480f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            // In symbol mode, just toggle symbol and symbol more keyboard.
481f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            shiftKeyState.onPress();
4826769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka            toggleShift();
483717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
484b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
485b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
486b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
487e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka    public void onReleaseShift(boolean withSliding) {
488b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!isKeyboardAvailable())
489b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return;
490f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        ShiftKeyState shiftKeyState = mShiftKeyState;
491f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
492f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "onReleaseShift:"
493f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
494e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka                    + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding);
495b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
496f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (shiftKeyState.isMomentary()) {
497f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // After chording input while normal state.
498f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                toggleShift();
499e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) {
500f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift has been pressed without chording while caps lock state.
501f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                toggleCapsLock();
502e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka                // To be able to turn off caps lock by "double tap" on shift key, we should ignore
503e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka                // the second tap of the "double tap" from now for a while because we just have
504e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka                // already turned off caps lock above.
505c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                mKeyboardView.startIgnoringDoubleTap();
506e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()
507e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka                    && !withSliding) {
508f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift has been pressed without chording while shifted state.
509b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                toggleShift();
510e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka            } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing()
511e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka                    && !withSliding) {
512d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka                // Shift has been pressed without chording while manual temporary upper case
513d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka                // transited from automatic temporary upper case.
514d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka                toggleShift();
515b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
516717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        } else {
517717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            // In symbol mode, snap back to the previous keyboard mode if the user chords the shift
518717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            // key and another key, then releases the shift key.
519717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) {
520717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                toggleShift();
521717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            }
522b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
523f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        shiftKeyState.onRelease();
524889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
525889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
5266c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onPressSymbol() {
527f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
5289e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            Log.d(TAG, "onPressSymbol:"
529f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
530f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " symbolKeyState=" + mSymbolKeyState);
531b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        changeKeyboardMode();
5326c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onPress();
533717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL;
5346c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
5356c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
5366c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onReleaseSymbol() {
537f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
5389e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            Log.d(TAG, "onReleaseSymbol:"
539f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
540f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " symbolKeyState=" + mSymbolKeyState);
5419e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka        // Snap back to the previous keyboard mode if the user chords the mode change key and
542717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // another key, then releases the mode change key.
543717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) {
544b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            changeKeyboardMode();
545717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        }
5466c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onRelease();
5476c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
5486c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
5496c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onOtherKeyPressed() {
55045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (DEBUG_STATE)
55145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            Log.d(TAG, "onOtherKeyPressed:"
55245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
55345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState
55445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " symbolKeyState=" + mSymbolKeyState);
555f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        mShiftKeyState.onOtherKeyPressed();
5566c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onOtherKeyPressed();
5576c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
5586c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
5595f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    public void onCancelInput() {
5605f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka        // Snap back to the previous keyboard mode if the user cancels sliding input.
561717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        if (getPointerCount() == 1) {
562717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) {
563717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                changeKeyboardMode();
564717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) {
565717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                toggleShift();
566717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            }
567717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        }
5685f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka    }
5695f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka
570b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    private void toggleShiftInSymbol() {
5717e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        if (isAlphabetMode())
5727e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka            return;
5738b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final LatinKeyboard keyboard;
5747e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) {
575e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka            keyboard = getKeyboard(mSymbolsShiftedId);
57612659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To
577e7c0e73a19e6eb6cb9a4aded8a0a7240db544d85Tadashi G. Takaoka            // enable the indicator, we need to call setShiftLocked(true).
5788b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setShiftLocked(true);
5797e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        } else {
580e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka            keyboard = getKeyboard(mSymbolsId);
58112659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
582e7c0e73a19e6eb6cb9a4aded8a0a7240db544d85Tadashi G. Takaoka            // indicator, we need to call setShiftLocked(false).
583e7c0e73a19e6eb6cb9a4aded8a0a7240db544d85Tadashi G. Takaoka            keyboard.setShiftLocked(false);
584923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
585050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka        setKeyboard(keyboard);
586923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
587923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
588717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    public boolean isInMomentarySwitchState() {
589717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL
590717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE;
5919e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka    }
5929e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka
593cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka    public boolean isVibrateAndSoundFeedbackRequired() {
594c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return mKeyboardView == null || !mKeyboardView.isInSlidingKeyInput();
595cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka    }
596cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka
5979e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka    private int getPointerCount() {
598c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return mKeyboardView == null ? 0 : mKeyboardView.getPointerCount();
5999e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka    }
6009e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka
601f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private void toggleKeyboardMode() {
602cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka        loadKeyboardInternal(mAttribute, mVoiceKeyEnabled, mVoiceButtonOnPrimary, !mIsSymbols);
603e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        if (mIsSymbols) {
604717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
605b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        } else {
606717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            mSwitchState = SWITCH_STATE_ALPHA;
607b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
608b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    }
609b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
610c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    public boolean hasDistinctMultitouch() {
611c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch();
612c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    }
613c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka
614717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static boolean isSpaceCharacter(int c) {
615717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER;
616717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    }
617717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka
618717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    private static boolean isQuoteCharacter(int c) {
619717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // Apostrophe, quotation mark.
6200730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard        if (c == Keyboard.CODE_SINGLE_QUOTE || c == Keyboard.CODE_DOUBLE_QUOTE)
621717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            return true;
622717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u2018: Left single quotation mark
623717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u2019: Right single quotation mark
624717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u201a: Single low-9 quotation mark
625717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u201b: Single high-reversed-9 quotation mark
626717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u201c: Left double quotation mark
627717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u201d: Right double quotation mark
628717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u201e: Double low-9 quotation mark
629717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u201f: Double high-reversed-9 quotation mark
630717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        if (c >= '\u2018' && c <= '\u201f')
631717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            return true;
632717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u00ab: Left-pointing double angle quotation mark
633717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        // \u00bb: Right-pointing double angle quotation mark
634717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        if (c == '\u00ab' || c == '\u00bb')
635717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            return true;
636717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        return false;
637717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    }
638717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka
639b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    /**
6409e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka     * Updates state machine to figure out when to automatically snap back to the previous mode.
641b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani     */
642717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka    public void onKey(int code) {
6439e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka        if (DEBUG_STATE)
644717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState
6459e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                    + " pointers=" + getPointerCount());
646717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        switch (mSwitchState) {
647717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL:
6489e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            // Only distinct multi touch devices can be in this state.
6495f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka            // On non-distinct multi touch devices, mode change key is handled by
6505f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka            // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and
651717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts
652717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from
653717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            // {@link #SWITCH_STATE_MOMENTARY}.
654717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) {
6559e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                // Detected only the mode change key has been pressed, and then released.
6569e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                if (mIsSymbols) {
657717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                    mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
6589e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                } else {
659717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                    mSwitchState = SWITCH_STATE_ALPHA;
6609e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                }
6619e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            } else if (getPointerCount() == 1) {
6629e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                // Snap back to the previous keyboard mode if the user pressed the mode change key
6639e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                // and slid to other key, then released the finger.
6645f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka                // If the user cancels the sliding input, snapping back to the previous keyboard
6655f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka                // mode is handled by {@link #onCancelInput}.
6669e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                changeKeyboardMode();
6679e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            } else {
6689e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                // Chording input is being started. The keyboard mode will be snapped back to the
6699e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka                // previous mode in {@link onReleaseSymbol} when the mode change key is released.
670717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                mSwitchState = SWITCH_STATE_CHORDING_ALPHA;
671717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            }
672717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            break;
673717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE:
674717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            if (code == Keyboard.CODE_SHIFT) {
675717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                // Detected only the shift key has been pressed on symbol layout, and then released.
676717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                mSwitchState = SWITCH_STATE_SYMBOL_BEGIN;
677717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            } else if (getPointerCount() == 1) {
678717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                // Snap back to the previous keyboard mode if the user pressed the shift key on
679717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                // symbol mode and slid to other key, then released the finger.
680717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                toggleShift();
681717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                mSwitchState = SWITCH_STATE_SYMBOL;
682717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            } else {
683717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                // Chording input is being started. The keyboard mode will be snapped back to the
684717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                // previous mode in {@link onReleaseShift} when the shift key is released.
685717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                mSwitchState = SWITCH_STATE_CHORDING_SYMBOL;
6869e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            }
6879e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            break;
688717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        case SWITCH_STATE_SYMBOL_BEGIN:
689717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            if (!isSpaceCharacter(code) && code >= 0) {
690717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka                mSwitchState = SWITCH_STATE_SYMBOL;
691b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
6920b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa            // Snap back to alpha keyboard mode immediately if user types a quote character.
6930b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa            if (isQuoteCharacter(code)) {
6940b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa                changeKeyboardMode();
6950b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa            }
696b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            break;
697717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        case SWITCH_STATE_SYMBOL:
698717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka        case SWITCH_STATE_CHORDING_SYMBOL:
6999e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka            // Snap back to alpha keyboard mode if user types one or more non-space/enter
7000b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa            // characters followed by a space/enter or a quote character.
701717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka            if (isSpaceCharacter(code) || isQuoteCharacter(code)) {
702b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                changeKeyboardMode();
703b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
704b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            break;
705b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
706923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
707979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
708c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    public LatinKeyboardView getKeyboardView() {
709c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return mKeyboardView;
710979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
711979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
712c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka    public View onCreateInputView() {
713f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        return createInputView(mThemeIndex, true);
714979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
715979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
716f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka    // Instance variable only for {@link #createInputView(int, boolean)}.
717f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka    private View mCurrentInputView;
718979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
719f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka    private View createInputView(final int newThemeIndex, final boolean forceRecreate) {
720f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        if (mCurrentInputView != null && mThemeIndex == newThemeIndex && !forceRecreate)
721f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            return mCurrentInputView;
722f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka
723f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        if (mKeyboardView != null) {
724f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            mKeyboardView.closing();
725f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        }
726f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        final int themeIndex = (newThemeIndex < KEYBOARD_THEMES.length) ? newThemeIndex
727f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                : Integer.valueOf(sConfigDefaultKeyboardThemeId);
728f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka
729f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        Utils.GCUtils.getInstance().reset();
730f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        boolean tryGC = true;
731f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
732f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            try {
733f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                mCurrentInputView = LayoutInflater.from(mInputMethodService).inflate(
734f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                        KEYBOARD_THEMES[themeIndex], null);
735f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                tryGC = false;
736f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            } catch (OutOfMemoryError e) {
737f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                Log.w(TAG, "load keyboard failed: " + e);
738f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait(mThemeIndex + "," + themeIndex, e);
739f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            } catch (InflateException e) {
740f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                Log.w(TAG, "load keyboard failed: " + e);
741f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                tryGC = Utils.GCUtils.getInstance().tryGCOrWait(mThemeIndex + "," + themeIndex, e);
742979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
743979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
744f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka
745f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        mKeyboardView = (LatinKeyboardView) mCurrentInputView.findViewById(
746f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                R.id.latin_keyboard_view);
747f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        mKeyboardView.setOnKeyboardActionListener(mInputMethodService);
748f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        mThemeIndex = themeIndex;
749f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka        return mCurrentInputView;
7508d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    }
7518d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka
752f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka    private void postSetInputView(final View newInputView) {
753979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mInputMethodService.mHandler.post(new Runnable() {
7548d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            @Override
755979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            public void run() {
756f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                if (newInputView != null) {
757f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka                    mInputMethodService.setInputView(newInputView);
758979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
759979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mInputMethodService.updateInputViewShown();
7608d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            }
7618d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        });
762979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
763979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
7648d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    @Override
765979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
766979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (PREF_KEYBOARD_LAYOUT.equals(key)) {
7678b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            final int layoutId = Integer.valueOf(
76805ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka                    sharedPreferences.getString(key, sConfigDefaultKeyboardThemeId));
769f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            postSetInputView(createInputView(layoutId, false));
7709502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        } else if (Settings.PREF_SETTINGS_KEY.equals(key)) {
7714199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka            mSettingsKeyEnabledInSettings = getSettingsKeyMode(sharedPreferences,
7724199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka                    mInputMethodService);
773f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka            postSetInputView(createInputView(mThemeIndex, true));
774979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
775979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
776979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
77759c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka    private int getColorScheme() {
778c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka        return (mKeyboardView != null)
779c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka                ? mKeyboardView.getColorScheme() : KeyboardView.COLOR_SCHEME_WHITE;
780979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
781979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
7821b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onAutoCorrectionStateChanged(boolean isAutoCorrection) {
7831b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (isAutoCorrection != mIsAutoCorrectionActive) {
784c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka            LatinKeyboardView keyboardView = getKeyboardView();
7851b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mIsAutoCorrectionActive = isAutoCorrection;
78641feaaadb758a8b31d3e436063b4b5faed104d4dsatok            keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard())
7871b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .onAutoCorrectionStateChanged(isAutoCorrection));
78841feaaadb758a8b31d3e436063b4b5faed104d4dsatok        }
78941feaaadb758a8b31d3e436063b4b5faed104d4dsatok    }
7901508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa
7918b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static boolean getSettingsKeyMode(SharedPreferences prefs, Context context) {
7928b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        Resources resources = context.getResources();
793503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka        final boolean showSettingsKeyOption = resources.getBoolean(
794503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka                R.bool.config_enable_show_settings_key_option);
79517fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa        if (showSettingsKeyOption) {
7969502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            final String settingsKeyMode = prefs.getString(Settings.PREF_SETTINGS_KEY,
79717fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa                    resources.getString(DEFAULT_SETTINGS_KEY_MODE));
79817fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or
79917fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system
80017fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
80117fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa                    || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
8029502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                            && Utils.hasMultipleEnabledIMEsOrSubtypes(
803610f1dc8553cf2ed97e763a06a19380c4a6cd636satok                                    (InputMethodManagerCompatWrapper.getInstance(context))))) {
8048b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                return true;
80517fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            }
8064199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka            return false;
8071508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa        }
8084199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka        // If the show settings key option is disabled, we always try showing the settings key.
8094199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka        return true;
8101508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    }
811923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
812