KeyboardSwitcher.java revision 9b6d1d52d91f8f18952ae3841f4bb0d7309bfc0e
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
19571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME;
209502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaokaimport com.android.inputmethod.latin.Settings;
219502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaokaimport com.android.inputmethod.latin.Utils;
22571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger;
23571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.R;
24571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeSwitcher;
255a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka
268b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaokaimport android.content.Context;
27979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.content.SharedPreferences;
2836fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasaniimport android.content.res.Resources;
298b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaokaimport android.util.Log;
30979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.view.InflateException;
3179efbed76f638be298493107fa2d0cd1b5eb529esatokimport android.view.inputmethod.InputMethodManager;
3236fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
33681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaokaimport java.lang.ref.SoftReference;
3412659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.HashMap;
3512659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.Locale;
3612659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka
37979f8690967ff5409fe18f5085858ccdb8e0ccf1satokpublic class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener {
388b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static final String TAG = "KeyboardSwitcher";
398b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static final boolean DEBUG = false;
40f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public static final boolean DEBUG_STATE = false;
41923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
4275fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka    // Changing DEFAULT_LAYOUT_ID also requires prefs_for_debug.xml to be matched with.
4375fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka    public static final String DEFAULT_LAYOUT_ID = "5";
44a327485e595c9f7676989097c830ff452085d4c9satok    public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902";
45979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private static final int[] THEMES = new int [] {
4675fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_basic,
4775fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_basic_highcontrast,
4875fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_stone_normal,
4975fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_stone_bold,
5075fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_gingerbread,
5175fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka        R.layout.input_honeycomb, // DEFAULT_LAYOUT_ID
5275fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka    };
53979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
54b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private static final int SYMBOLS_MODE_STATE_NONE = 0;
55b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private static final int SYMBOLS_MODE_STATE_BEGIN = 1;
56b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private static final int SYMBOLS_MODE_STATE_SYMBOL = 2;
57b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
580ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private SubtypeSwitcher mSubtypeSwitcher;
5927d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa    private SharedPreferences mPrefs;
600ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
613a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    private LatinKeyboardView mInputView;
620ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private LatinIME mInputMethodService;
6331adfa78e2edae188edb05e869f9f68798857582satok
64f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
65f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
66889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
67353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mSymbolsId;
68353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mSymbolsShiftedId;
69353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
70353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId mCurrentId;
718b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache =
728b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            new HashMap<KeyboardId, SoftReference<LatinKeyboard>>();
73466741d8a78965b8509bf527344f289e50873092Mike LeBeau
745a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka    private int mMode = KeyboardId.MODE_TEXT; /* default value */
75923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    private int mImeOptions;
76353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private boolean mIsSymbols;
771b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of
7841feaaadb758a8b31d3e436063b4b5faed104d4dsatok     * what user actually typed. */
791b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    private boolean mIsAutoCorrectionActive;
8004448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka    private boolean mVoiceKeyEnabled;
81507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka    private boolean mVoiceButtonOnPrimary;
82b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
83923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
841508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    // Indicates whether or not we have the settings key
853a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    private boolean mHasSettingsKey;
861508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto;
87503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka    private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW =
88503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka            R.string.settings_key_mode_always_show;
8917fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to
9017fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // in the source code now.
9117fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    // Default is SETTINGS_KEY_MODE_AUTO.
9217fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa    private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO;
931508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa
94979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    private int mLayoutId;
95979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
960ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private static final KeyboardSwitcher sInstance = new KeyboardSwitcher();
970ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
980ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    public static KeyboardSwitcher getInstance() {
990ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        return sInstance;
1000ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
1010ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
1020ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    private KeyboardSwitcher() {
103e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        // Intentional empty constructor for singleton.
1040ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok    }
1050ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok
10627d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa    public static void init(LatinIME ims, SharedPreferences prefs) {
1070ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        sInstance.mInputMethodService = ims;
10827d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        sInstance.mPrefs = prefs;
1090ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance();
110979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
1110ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        sInstance.mLayoutId = Integer.valueOf(
1120ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID));
1130ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        prefs.registerOnSharedPreferenceChangeListener(sInstance);
114979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
115979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
116e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa    private void makeSymbolsKeyboardIds() {
1170ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        final Locale locale = mSubtypeSwitcher.getInputLocale();
1189b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        final Resources res = mInputMethodService.getResources();
1199b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        final int orientation = res.getConfiguration().orientation;
1208b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final int mode = mMode;
12159c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka        final int colorScheme = getColorScheme();
1228b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final boolean hasSettingsKey = mHasSettingsKey;
12304448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka        final boolean voiceKeyEnabled = mVoiceKeyEnabled;
12404448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka        final boolean hasVoiceKey = voiceKeyEnabled && !mVoiceButtonOnPrimary;
1258b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final int imeOptions = mImeOptions;
1264b8bbbadac9276df7ab587a228a84f93d74c5541Tadashi G. Takaoka        // Note: This comment is only applied for phone number keyboard layout.
1274b8bbbadac9276df7ab587a228a84f93d74c5541Tadashi G. Takaoka        // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch
1284b8bbbadac9276df7ab587a228a84f93d74c5541Tadashi G. Takaoka        // between "phone keyboard" and "phone symbols keyboard".  But on xlarge device,
1294b8bbbadac9276df7ab587a228a84f93d74c5541Tadashi G. Takaoka        // "@integer/key_shift" key code is used for that purpose in order to properly display
1304b8bbbadac9276df7ab587a228a84f93d74c5541Tadashi G. Takaoka        // "more" and "locked more" key labels.  To achieve these behavior, we should initialize
1314b8bbbadac9276df7ab587a228a84f93d74c5541Tadashi G. Takaoka        // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard"
1324b8bbbadac9276df7ab587a228a84f93d74c5541Tadashi G. Takaoka        // respectively here for xlarge device's layout switching.
1339b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        int xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols;
1349b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        mSymbolsId = new KeyboardId(
1359b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
1369b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka                hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
1379b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        xmlId = mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift;
1389b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        mSymbolsShiftedId = new KeyboardId(
1399b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, colorScheme,
1409b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka                hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true);
141353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
142353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
1438b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private boolean hasVoiceKey(boolean isSymbols) {
14404448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka        return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary);
145466741d8a78965b8509bf527344f289e50873092Mike LeBeau    }
146466741d8a78965b8509bf527344f289e50873092Mike LeBeau
14704448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka    public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled,
148507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka            boolean voiceButtonOnPrimary) {
149e3803800c53cc813e27dd1e7c31bdb4d075f0252Amith Yamasani        mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
150979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        try {
15104448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka            loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary,
152507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka                    false);
153979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        } catch (RuntimeException e) {
154b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            Log.w(TAG, e);
155e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa            LatinImeLogger.logOnException(mode + "," + imeOptions, e);
156979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
157353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
158353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
1598b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled,
160507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka            boolean voiceButtonOnPrimary, boolean isSymbols) {
1616516d0fdfcbaa4eb809a8a69bd876293043a68a4Amith Yamasani        if (mInputView == null) return;
1628b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mInputView.setPreviewEnabled(mInputMethodService.getPopupOn());
1638b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
164923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mMode = mode;
165923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        mImeOptions = imeOptions;
16604448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka        mVoiceKeyEnabled = voiceButtonEnabled;
1678b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mVoiceButtonOnPrimary = voiceButtonOnPrimary;
168c5bb4591b67b165f007e29bd9424d319ac3c7c28Brandon Ballinger        mIsSymbols = isSymbols;
1698b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        // Update the settings key state because number of enabled IMEs could have been changed
17027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa        mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService);
1718b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        makeSymbolsKeyboardIds();
172466741d8a78965b8509bf527344f289e50873092Mike LeBeau
173353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols);
1748b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        LatinKeyboard keyboard = getKeyboard(id);
175353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
176353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        mCurrentId = id;
177353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        mInputView.setKeyboard(keyboard);
178353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
179353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
180353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private LatinKeyboard getKeyboard(KeyboardId id) {
1818b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id);
182681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        LatinKeyboard keyboard = (ref == null) ? null : ref.get();
183681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        if (keyboard == null) {
1840ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok            final Locale savedLocale =  mSubtypeSwitcher.changeSystemLocale(
1850ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok                    mSubtypeSwitcher.getInputLocale());
1868b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
187b0465116bd3786174ccd0034c8a165ebc723b60fTadashi G. Takaoka            keyboard = new LatinKeyboard(mInputMethodService, id);
188358e485b14938fbcb5af5be75aa29f2b73674100Amith Yamasani
189353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            if (id.mEnableShiftLock) {
190353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger                keyboard.enableShiftLock();
191353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            }
1928b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
1938b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard));
1948b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            if (DEBUG)
1958b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": "
1968b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                        + ((ref == null) ? "LOAD" : "GCed") + " id=" + id);
19736fcf25833f7c8876cbc8286e0c159b052dc2626Amith Yamasani
1980ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok            mSubtypeSwitcher.changeSystemLocale(savedLocale);
1998b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        } else if (DEBUG) {
2008b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT  id=" + id);
201353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger        }
2028b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka
2031b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive);
2048b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        keyboard.setShifted(false);
205681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka        return keyboard;
206353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    }
207353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger
208353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger    private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) {
2098b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final boolean hasVoiceKey = hasVoiceKey(isSymbols);
21059c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka        final int charColorId = getColorScheme();
21159c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka        final int xmlId;
212e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        final boolean enableShiftLock;
213e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa
214e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        if (isSymbols) {
2155a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            if (mode == KeyboardId.MODE_PHONE) {
2162c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_phone_symbols;
2175a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            } else if (mode == KeyboardId.MODE_NUMBER) {
2182c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                // Note: MODE_NUMBER keyboard layout has no "switch alpha symbol" key.
2192c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_number;
2202c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            } else {
2212c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_symbols;
2222c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            }
223e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa            enableShiftLock = false;
2242c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka        } else {
2255a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            if (mode == KeyboardId.MODE_PHONE) {
2262c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_phone;
2272c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                enableShiftLock = false;
2285a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka            } else if (mode == KeyboardId.MODE_NUMBER) {
2292c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_number;
2302c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                enableShiftLock = false;
2312c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            } else {
2322c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                xmlId = R.xml.kbd_qwerty;
2332c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka                enableShiftLock = true;
2342c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka            }
235923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
2369b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        final Resources res = mInputMethodService.getResources();
2379b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        final int orientation = res.getConfiguration().orientation;
2380ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok        final Locale locale = mSubtypeSwitcher.getInputLocale();
2399b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka        return new KeyboardId(
2409b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka                res.getResourceEntryName(xmlId), xmlId, locale, orientation, mode, charColorId,
24104448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka                mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock);
242923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
243923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2443a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public int getKeyboardMode() {
245923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        return mMode;
246923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
2471679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2483a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka    public boolean isAlphabetMode() {
249571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka        return mCurrentId != null && mCurrentId.isAlphabetKeyboard();
250923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
251923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
2521679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isInputViewShown() {
2531679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka        return mInputView != null && mInputView.isShown();
2541679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2551679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2561679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isKeyboardAvailable() {
257b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (mInputView != null)
258b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return mInputView.getLatinKeyboard() != null;
259b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
260b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
261b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
262b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    private LatinKeyboard getLatinKeyboard() {
263b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (mInputView != null)
264b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return mInputView.getLatinKeyboard();
265b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return null;
2661679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2671679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2681679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public void setPreferredLetters(int[] frequencies) {
269b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
270b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null)
2711679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            latinKeyboard.setPreferredLetters(frequencies);
2721679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2731679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2741679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public void keyReleased() {
275b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
276b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null)
2771679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka            latinKeyboard.keyReleased();
2781679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2791679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
280f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isShiftedOrShiftLocked() {
281b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
282b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null)
283f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            return latinKeyboard.isShiftedOrShiftLocked();
284b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
2851679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2861679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
2871679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    public boolean isShiftLocked() {
288b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
289b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null)
290b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return latinKeyboard.isShiftLocked();
291b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        return false;
2921679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka    }
2931679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka
294f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isAutomaticTemporaryUpperCase() {
295f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
296f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (latinKeyboard != null)
297f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            return latinKeyboard.isAutomaticTemporaryUpperCase();
298f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        return false;
299f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
300f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
301f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    public boolean isManualTemporaryUpperCase() {
302f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
303f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (latinKeyboard != null)
304f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            return latinKeyboard.isManualTemporaryUpperCase();
305f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        return false;
306f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
307f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
308f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private void setManualTemporaryUpperCase(boolean shifted) {
309b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
3100d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka        if (latinKeyboard != null) {
3110d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // On non-distinct multi touch panel device, we should also turn off the shift locked
3120d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // state when shift key is pressed to go to normal mode.
3130d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // On the other hand, on distinct multi touch panel device, turning off the shift locked
3140d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            // state with shift key pressing is handled by onReleaseShift().
3150d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) {
3160d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka                latinKeyboard.setShiftLocked(false);
3170d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            }
3180d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            if (latinKeyboard.setShifted(shifted)) {
3190d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka                mInputView.invalidateAllKeys();
3200d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka            }
321979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
322979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
323979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
324b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    private void setShiftLocked(boolean shiftLocked) {
325b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
326b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) {
327b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            mInputView.invalidateAllKeys();
328b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
329979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
330979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
3310d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka    /**
3320d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     * Toggle keyboard shift state triggered by user touch event.
3330d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     */
334b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void toggleShift() {
335b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mInputMethodService.mHandler.cancelUpdateShiftState();
336f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
337f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "toggleShift:"
338f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
339f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState);
340b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
341f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            setManualTemporaryUpperCase(!isShiftedOrShiftLocked());
342b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        } else {
343b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            toggleShiftInSymbol();
344b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
345b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
346b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
347b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void toggleCapsLock() {
348b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        mInputMethodService.mHandler.cancelUpdateShiftState();
349f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
350f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "toggleCapsLock:"
351f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
352f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState);
353b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
354b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            if (isShiftLocked()) {
355f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift key is long pressed while caps lock state, we will toggle back to normal
356f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // state. And mark as if shift key is released.
357f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                setShiftLocked(false);
358f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                mShiftKeyState.onRelease();
359b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            } else {
360b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                setShiftLocked(true);
361b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
362b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
363889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
364889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
365f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private void setAutomaticTemporaryUpperCase() {
366f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        LatinKeyboard latinKeyboard = getLatinKeyboard();
367f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (latinKeyboard != null) {
368f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            latinKeyboard.setAutomaticTemporaryUpperCase();
369f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            mInputView.invalidateAllKeys();
370f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        }
371f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    }
372f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka
3730d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka    /**
3740d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     * Update keyboard shift state triggered by connected EditText status change.
3750d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka     */
376b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void updateShiftState() {
37745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        final ShiftKeyState shiftKeyState = mShiftKeyState;
378f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
379f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "updateShiftState:"
380f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState()
381f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
38245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " shiftKeyState=" + shiftKeyState);
38345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (isAlphabetMode()) {
38445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            if (!isShiftLocked() && !shiftKeyState.isIgnoring()) {
38545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) {
38645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    // Only when shift key is releasing, automatic temporary upper case will be set.
38745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    setAutomaticTemporaryUpperCase();
38845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                } else {
38945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    setManualTemporaryUpperCase(shiftKeyState.isMomentary());
39045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                }
391f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            }
39245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        } else {
39345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            // In symbol keyboard mode, we should clear shift key state because only alphabet
39445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            // keyboard has shift key.
39545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            shiftKeyState.onRelease();
396b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
397889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
398889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
399b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void changeKeyboardMode() {
400f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
401f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "changeKeyboardMode:"
402f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
403f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState);
404b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        toggleKeyboardMode();
405b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isShiftLocked() && isAlphabetMode())
406b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            setShiftLocked(true);
407b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        updateShiftState();
408889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
409889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
410b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void onPressShift() {
411b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!isKeyboardAvailable())
412b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return;
413f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        ShiftKeyState shiftKeyState = mShiftKeyState;
414f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
415f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "onPressShift:"
416f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
417f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + shiftKeyState);
418f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (isAlphabetMode()) {
419f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (isShiftLocked()) {
420f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift key is pressed while caps lock state, we will treat this state as shifted
421f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // caps lock state and mark as if shift key pressed while normal state.
422f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                shiftKeyState.onPress();
4236769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka                setManualTemporaryUpperCase(true);
424f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else if (isAutomaticTemporaryUpperCase()) {
425f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift key is pressed while automatic temporary upper case, we have to move to
426f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // manual temporary upper case.
4276769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka                shiftKeyState.onPress();
428f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                setManualTemporaryUpperCase(true);
429f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else if (isShiftedOrShiftLocked()) {
430f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // In manual upper case state, we just record shift key has been pressing while
431f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // shifted state.
432f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                shiftKeyState.onPressOnShifted();
433f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else {
434f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // In base layout, chording or manual temporary upper case mode is started.
435f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                shiftKeyState.onPress();
4366769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka                toggleShift();
437f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            }
438b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        } else {
439f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            // In symbol mode, just toggle symbol and symbol more keyboard.
440f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            shiftKeyState.onPress();
4416769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka            toggleShift();
442b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
443b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    }
444b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka
445b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void onReleaseShift() {
446b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (!isKeyboardAvailable())
447b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            return;
448f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        ShiftKeyState shiftKeyState = mShiftKeyState;
449f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
450f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "onReleaseShift:"
451f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
452f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " shiftKeyState=" + shiftKeyState);
453b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (isAlphabetMode()) {
454f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            if (shiftKeyState.isMomentary()) {
455f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // After chording input while normal state.
456f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                toggleShift();
457f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else if (isShiftLocked() && !shiftKeyState.isIgnoring()) {
458f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift has been pressed without chording while caps lock state.
459f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                toggleCapsLock();
460f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) {
461f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                // Shift has been pressed without chording while shifted state.
462b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                toggleShift();
463b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
464b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        }
465f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        shiftKeyState.onRelease();
466889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka    }
467889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka
4686c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onPressSymbol() {
469f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
470f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "onReleaseShift:"
471f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
472f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " symbolKeyState=" + mSymbolKeyState);
473b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        changeKeyboardMode();
4746c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onPress();
4756c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4766c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4776c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onReleaseSymbol() {
478f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        if (DEBUG_STATE)
479f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka            Log.d(TAG, "onReleaseShift:"
480f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
481f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka                    + " symbolKeyState=" + mSymbolKeyState);
482b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        if (mSymbolKeyState.isMomentary())
483b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            changeKeyboardMode();
4846c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onRelease();
4856c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4866c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
4876c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    public void onOtherKeyPressed() {
48845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka        if (DEBUG_STATE)
48945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka            Log.d(TAG, "onOtherKeyPressed:"
49045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " keyboard=" + getLatinKeyboard().getKeyboardShiftState()
49145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " shiftKeyState=" + mShiftKeyState
49245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka                    + " symbolKeyState=" + mSymbolKeyState);
493f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka        mShiftKeyState.onOtherKeyPressed();
4946c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka        mSymbolKeyState.onOtherKeyPressed();
4956c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka    }
4966c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka
497b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    private void toggleShiftInSymbol() {
4987e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        if (isAlphabetMode())
4997e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka            return;
5008b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        final LatinKeyboard keyboard;
5017e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) {
502353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            mCurrentId = mSymbolsShiftedId;
5038b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard = getKeyboard(mCurrentId);
50412659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To
50512659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true).
50612659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is
50712659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // called.
5088b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setShiftLocked(true);
5097e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka        } else {
510353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger            mCurrentId = mSymbolsId;
5118b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard = getKeyboard(mCurrentId);
51212659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the
51312659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka            // indicator, we need to call enableShiftLock() and setShiftLocked(false).
5148b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            keyboard.setShifted(false);
515923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project        }
5168b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        mInputView.setKeyboard(keyboard);
517923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
518923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project
519f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka    private void toggleKeyboardMode() {
52004448c2978a81b8c479b254e0f40bce128da8f7bTadashi G. Takaoka        loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary,
521507495efd57074994fdc2fda78db9d5345f4a3a8Tadashi G. Takaoka                !mIsSymbols);
522e354a85ef44e13999aaefd735cef7f659090f6e8Ken Wakasa        if (mIsSymbols) {
523b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN;
524b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        } else {
525b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani            mSymbolsModeState = SYMBOLS_MODE_STATE_NONE;
526b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
527b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    }
528b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani
529c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    public boolean hasDistinctMultitouch() {
530c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka        return mInputView != null && mInputView.hasDistinctMultitouch();
531c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka    }
532c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka
533b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani    /**
534b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani     * Updates state machine to figure out when to automatically switch back to alpha mode.
535b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani     */
536b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka    public void onKey(int key) {
537b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        // Switch back to alpha mode if user types one or more non-space/enter
538b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        // characters followed by a space/enter
539b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        switch (mSymbolsModeState) {
540b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        case SYMBOLS_MODE_STATE_BEGIN:
541571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key > 0) {
542b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL;
543b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
544b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            break;
545b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka        case SYMBOLS_MODE_STATE_SYMBOL:
546571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka            if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) {
547b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka                changeKeyboardMode();
548b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            }
549b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka            break;
550b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani        }
551923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project    }
552979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
553979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public LatinKeyboardView getInputView() {
554979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        return mInputView;
555979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
556979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5578d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    public LatinKeyboardView onCreateInputView() {
5588d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        createInputViewInternal(mLayoutId, true);
5598d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        return mInputView;
560979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
561979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5628d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    private void createInputViewInternal(int newLayout, boolean forceReset) {
563e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        int layoutId = newLayout;
564e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka        if (mLayoutId != layoutId || mInputView == null || forceReset) {
565979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            if (mInputView != null) {
566979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mInputView.closing();
567979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
568e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            if (THEMES.length <= layoutId) {
569e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                layoutId = Integer.valueOf(DEFAULT_LAYOUT_ID);
570979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
571979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
5729502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            Utils.GCUtils.getInstance().reset();
573979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            boolean tryGC = true;
5749502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) {
575979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                try {
576979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater(
577e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                            ).inflate(THEMES[layoutId], null);
578979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    tryGC = false;
579979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                } catch (OutOfMemoryError e) {
5807f0befe1f0e346ec6468f229f337eda32e19f6d8Tadashi G. Takaoka                    Log.w(TAG, "load keyboard failed: " + e);
5819502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                    tryGC = Utils.GCUtils.getInstance().tryGCOrWait(
582e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                            mLayoutId + "," + layoutId, e);
583979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                } catch (InflateException e) {
5847f0befe1f0e346ec6468f229f337eda32e19f6d8Tadashi G. Takaoka                    Log.w(TAG, "load keyboard failed: " + e);
5859502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                    tryGC = Utils.GCUtils.getInstance().tryGCOrWait(
586e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka                            mLayoutId + "," + layoutId, e);
587979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
588979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            }
589979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            mInputView.setOnKeyboardActionListener(mInputMethodService);
590e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka            mLayoutId = layoutId;
591979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
5928d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    }
5938d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka
5948d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    private void postSetInputView() {
595979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        mInputMethodService.mHandler.post(new Runnable() {
5968d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            @Override
597979f8690967ff5409fe18f5085858ccdb8e0ccf1satok            public void run() {
598979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                if (mInputView != null) {
599979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                    mInputMethodService.setInputView(mInputView);
600979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                }
601979f8690967ff5409fe18f5085858ccdb8e0ccf1satok                mInputMethodService.updateInputViewShown();
6028d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            }
6038d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka        });
604979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
605979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
6068d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka    @Override
607979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
608979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        if (PREF_KEYBOARD_LAYOUT.equals(key)) {
6098b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            final int layoutId = Integer.valueOf(
6108b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                    sharedPreferences.getString(key, DEFAULT_LAYOUT_ID));
6118d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            createInputViewInternal(layoutId, false);
6128d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            postSetInputView();
6139502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka        } else if (Settings.PREF_SETTINGS_KEY.equals(key)) {
6148b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka            mHasSettingsKey = getSettingsKeyMode(sharedPreferences, mInputMethodService);
6158d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            createInputViewInternal(mLayoutId, true);
6168d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka            postSetInputView();
617979f8690967ff5409fe18f5085858ccdb8e0ccf1satok        }
618979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
619979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
62059c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka    private int getColorScheme() {
62159c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka        return (mInputView != null)
6225a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka                ? mInputView.getColorScheme() : KeyboardView.COLOR_SCHEME_WHITE;
623979f8690967ff5409fe18f5085858ccdb8e0ccf1satok    }
624979f8690967ff5409fe18f5085858ccdb8e0ccf1satok
6251b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka    public void onAutoCorrectionStateChanged(boolean isAutoCorrection) {
6261b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka        if (isAutoCorrection != mIsAutoCorrectionActive) {
62741feaaadb758a8b31d3e436063b4b5faed104d4dsatok            LatinKeyboardView keyboardView = getInputView();
6281b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka            mIsAutoCorrectionActive = isAutoCorrection;
62941feaaadb758a8b31d3e436063b4b5faed104d4dsatok            keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard())
6301b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka                    .onAutoCorrectionStateChanged(isAutoCorrection));
63141feaaadb758a8b31d3e436063b4b5faed104d4dsatok        }
63241feaaadb758a8b31d3e436063b4b5faed104d4dsatok    }
6331508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa
6348b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka    private static boolean getSettingsKeyMode(SharedPreferences prefs, Context context) {
6358b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        Resources resources = context.getResources();
636503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka        final boolean showSettingsKeyOption = resources.getBoolean(
637503797ae0e55c74068470d237fb47c4da13ec4fbTadashi G. Takaoka                R.bool.config_enable_show_settings_key_option);
63817fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa        if (showSettingsKeyOption) {
6399502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka            final String settingsKeyMode = prefs.getString(Settings.PREF_SETTINGS_KEY,
64017fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa                    resources.getString(DEFAULT_SETTINGS_KEY_MODE));
64117fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or
64217fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system
64317fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW))
64417fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa                    || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO))
6459502cc177cc53678c9ddcc01d4d046f69220e13bTadashi G. Takaoka                            && Utils.hasMultipleEnabledIMEsOrSubtypes(
64679efbed76f638be298493107fa2d0cd1b5eb529esatok                                    ((InputMethodManager) context.getSystemService(
64779efbed76f638be298493107fa2d0cd1b5eb529esatok                                            Context.INPUT_METHOD_SERVICE))))) {
6488b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka                return true;
64917fcd719de9a0ddcf9fd712481b28038419eec4eKen Wakasa            }
6501508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa        }
6518b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka        return false;
6521508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa    }
653923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project}
654