KeyboardSwitcher.java revision cee174b8ccb47ccddc8a8a7e88a9c617f9b5e766
1923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project/* 2443c360d0afdbab091994244f045f4756feaf2b4Jean-Baptiste Queru * Copyright (C) 2008 The Android Open Source Project 3571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka * 4923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy of 6923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License at 7571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka * 8923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 9571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka * 10923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 11923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * License for the specific language governing permissions and limitations under 14923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project * the License. 15923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project */ 16923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 17571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokapackage com.android.inputmethod.keyboard; 18923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 19c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.content.Context; 20c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.content.SharedPreferences; 21364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaokaimport android.content.res.Configuration; 22c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.content.res.Resources; 23364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaokaimport android.inputmethodservice.InputMethodService; 24c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.util.Log; 2513a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaokaimport android.view.ContextThemeWrapper; 26c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.InflateException; 27c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.LayoutInflater; 28c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.View; 29c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaokaimport android.view.inputmethod.EditorInfo; 30c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka 315ac4638f999db4fea8a9e24171dbceb640a10858Alan Viveretteimport com.android.inputmethod.accessibility.AccessibleKeyboardViewProxy; 3272934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.ModifierKeyState; 3372934bd5967d0127f71fd4d66158b18b4e6ceefeTadashi G. Takaokaimport com.android.inputmethod.keyboard.internal.ShiftKeyState; 34571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinIME; 35571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.LatinImeLogger; 36571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.R; 375cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaokaimport com.android.inputmethod.latin.Settings; 38571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaokaimport com.android.inputmethod.latin.SubtypeSwitcher; 395cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaokaimport com.android.inputmethod.latin.Utils; 405a309f57155fb95667c2ccdda730eaf175de8876Tadashi G. Takaoka 41681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaokaimport java.lang.ref.SoftReference; 42364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaokaimport java.util.Arrays; 4312659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.HashMap; 4412659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaokaimport java.util.Locale; 4512659d4c0ce04aaf3d8479e44f9230881b964000Tadashi G. Takaoka 46979f8690967ff5409fe18f5085858ccdb8e0ccf1satokpublic class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener { 47c25e07d21261583d0eeca5aa0fb6e3ffe93dc603Tadashi G. Takaoka private static final String TAG = KeyboardSwitcher.class.getSimpleName(); 48c25e07d21261583d0eeca5aa0fb6e3ffe93dc603Tadashi G. Takaoka private static final boolean DEBUG_CACHE = LatinImeLogger.sDBG; 49f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka public static final boolean DEBUG_STATE = false; 50923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 51a327485e595c9f7676989097c830ff452085d4c9satok public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902"; 5205ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka private static final int[] KEYBOARD_THEMES = { 5313a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka R.style.KeyboardTheme, 5413a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka R.style.KeyboardTheme_HighContrast, 5513a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka R.style.KeyboardTheme_Stone, 5613a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka R.style.KeyboardTheme_Stone_Bold, 5713a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka R.style.KeyboardTheme_Gingerbread, 589116bf18f9c83084f9d451e2e709eff32db27d36Tadashi G. Takaoka R.style.KeyboardTheme_IceCreamSandwich, 5975fde6489039c09056fb5e64d39630ece5ad57cfTadashi G. Takaoka }; 60979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 610ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private SubtypeSwitcher mSubtypeSwitcher; 6227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa private SharedPreferences mPrefs; 630ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok 6486e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka private View mCurrentInputView; 65c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka private LatinKeyboardView mKeyboardView; 660ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private LatinIME mInputMethodService; 670a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka private String mPackageName; 680a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka private Resources mResources; 6931adfa78e2edae188edb05e869f9f68798857582satok 70717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // TODO: Combine these key state objects with auto mode switch state. 71f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); 72f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); 73889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 7460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka private KeyboardId mMainKeyboardId; 7560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka private KeyboardId mSymbolsKeyboardId; 7660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka private KeyboardId mSymbolsShiftedKeyboardId; 77353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger 78353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger private KeyboardId mCurrentId; 798b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache = 808b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka new HashMap<KeyboardId, SoftReference<LatinKeyboard>>(); 81364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // TODO: Remove this cache object when {@link DisplayMetrics} has actual window width excluding 82364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // system navigation bar. 83364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private WindowWidthCache mWindowWidthCache; 84466741d8a78965b8509bf527344f289e50873092Mike LeBeau 85055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private KeyboardLayoutState mSavedKeyboardState = new KeyboardLayoutState(); 86055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 871b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka /** mIsAutoCorrectionActive indicates that auto corrected word will be input instead of 8841feaaadb758a8b31d3e436063b4b5faed104d4dsatok * what user actually typed. */ 891b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka private boolean mIsAutoCorrectionActive; 909e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka 91717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // TODO: Encapsulate these state handling to separate class and combine with ShiftKeyState 92717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // and ModifierKeyState. 93717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static final int SWITCH_STATE_ALPHA = 0; 94717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static final int SWITCH_STATE_SYMBOL_BEGIN = 1; 95717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static final int SWITCH_STATE_SYMBOL = 2; 969e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // The following states are used only on the distinct multi-touch panel devices. 97717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static final int SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL = 3; 98717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static final int SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE = 4; 99717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static final int SWITCH_STATE_CHORDING_ALPHA = 5; 100717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static final int SWITCH_STATE_CHORDING_SYMBOL = 6; 101717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private int mSwitchState = SWITCH_STATE_ALPHA; 102923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 1035a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka private int mThemeIndex = -1; 1045a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka private Context mThemeContext; 105979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 1060ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); 1070ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok 108364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private static class WindowWidthCache { 109364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private final InputMethodService mService; 110364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private final Resources mResources; 111364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private final boolean mIsRegistered[] = new boolean[Configuration.ORIENTATION_SQUARE + 1]; 112364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private final int mWidth[] = new int[Configuration.ORIENTATION_SQUARE + 1]; 113364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 114364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka public WindowWidthCache(InputMethodService service) { 115364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mService = service; 116364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mResources = service.getResources(); 117364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 118364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka Arrays.fill(mIsRegistered, false); 119364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka Arrays.fill(mWidth, 0); 120364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 121364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 122364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private int getCurrentWindowWidth() { 123364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka return mService.getWindow().getWindow().getDecorView().getWidth(); 124364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 125364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 126364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka public int getWidth(Configuration conf) { 127364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int orientation = conf.orientation; 128364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka try { 129364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int width = mWidth[orientation]; 130364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka if (mIsRegistered[orientation] || width > 0) { 131364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // Return registered or cached window width for this orientation. 132364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka return width; 133364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 134364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // Fall through 135364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } catch (IndexOutOfBoundsException e) { 136364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka Log.w(TAG, "unknwon orientation value " + orientation); 137364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // Fall through 138364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 139364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 140364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // Return screen width as default window width. 141364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka return mResources.getDisplayMetrics().widthPixels; 142364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 143364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 144364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka public int getWidthOnSizeChanged(Configuration conf) { 145364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int orientation = conf.orientation; 146364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka try { 147364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka if (mIsRegistered[orientation]) { 148364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // Return registered window width for this orientation. 149364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka return mWidth[orientation]; 150364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 151364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 152364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // Cache the current window width without registering. 153364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int width = getCurrentWindowWidth(); 154364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mWidth[orientation] = width; 155364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka return width; 156364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } catch (IndexOutOfBoundsException e) { 157364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka Log.w(TAG, "unknwon orientation value " + orientation); 158364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka return 0; 159364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 160364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 161364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 162364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka public void registerWidth() { 163364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int orientation = mResources.getConfiguration().orientation; 164364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka try { 165364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka if (!mIsRegistered[orientation]) { 166364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int width = getCurrentWindowWidth(); 167364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka if (width > 0) { 168364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka // Register current window width. 169364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mWidth[orientation] = width; 170364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mIsRegistered[orientation] = true; 171364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 172364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 173364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } catch (IndexOutOfBoundsException e) { 174364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka Log.w(TAG, "unknwon orientation value " + orientation); 175364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 176364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 177364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 178364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 179055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public class KeyboardLayoutState { 180055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private boolean mIsValid; 181055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private boolean mIsAlphabetMode; 182055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private boolean mIsShiftLocked; 183055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private boolean mIsShifted; 184055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 185055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public boolean isValid() { 186055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return mIsValid; 187055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 188055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 189055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public void save() { 19094ac3d760b98aa148cc9386e0a4b4a20978db85dTadashi G. Takaoka if (mCurrentId == null) { 19194ac3d760b98aa148cc9386e0a4b4a20978db85dTadashi G. Takaoka return; 19294ac3d760b98aa148cc9386e0a4b4a20978db85dTadashi G. Takaoka } 193055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsAlphabetMode = isAlphabetMode(); 19438b5605feed7260a6dc43ce7bd88d0f95cf43261Tadashi G. Takaoka if (mIsAlphabetMode) { 19538b5605feed7260a6dc43ce7bd88d0f95cf43261Tadashi G. Takaoka mIsShiftLocked = isShiftLocked(); 19638b5605feed7260a6dc43ce7bd88d0f95cf43261Tadashi G. Takaoka mIsShifted = !mIsShiftLocked && isShiftedOrShiftLocked(); 19738b5605feed7260a6dc43ce7bd88d0f95cf43261Tadashi G. Takaoka } else { 19838b5605feed7260a6dc43ce7bd88d0f95cf43261Tadashi G. Takaoka mIsShiftLocked = false; 19994ac3d760b98aa148cc9386e0a4b4a20978db85dTadashi G. Takaoka mIsShifted = mCurrentId.equals(mSymbolsShiftedKeyboardId); 20038b5605feed7260a6dc43ce7bd88d0f95cf43261Tadashi G. Takaoka } 201055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsValid = true; 202055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 203055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 204055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public KeyboardId getKeyboardId() { 205055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (!mIsValid) return mMainKeyboardId; 206055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 207055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mIsAlphabetMode) { 208055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return mMainKeyboardId; 209055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } else { 210055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return mIsShifted ? mSymbolsShiftedKeyboardId : mSymbolsKeyboardId; 211055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 212055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 213055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 214055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public void restore() { 215055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (!mIsValid) return; 216055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsValid = false; 217055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 218055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mIsAlphabetMode) { 219055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final boolean isAlphabetMode = isAlphabetMode(); 220055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final boolean isShiftLocked = isAlphabetMode && isShiftLocked(); 221055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final boolean isShifted = !isShiftLocked && isShiftedOrShiftLocked(); 222055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mIsShiftLocked != isShiftLocked) { 223055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka toggleCapsLock(); 224055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } else if (mIsShifted != isShifted) { 225055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka onPressShift(false); 226055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka onReleaseShift(false); 227055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 228055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 229055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 230055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 231055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 2320ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok public static KeyboardSwitcher getInstance() { 2330ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok return sInstance; 2340ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok } 2350ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok 2360ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private KeyboardSwitcher() { 237e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka // Intentional empty constructor for singleton. 2380ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok } 2390ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok 24027d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa public static void init(LatinIME ims, SharedPreferences prefs) { 241364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka sInstance.initInternal(ims, prefs); 242364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 243364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 244364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private void initInternal(LatinIME ims, SharedPreferences prefs) { 245364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mInputMethodService = ims; 246364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mPackageName = ims.getPackageName(); 247364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mResources = ims.getResources(); 248364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mPrefs = prefs; 249364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 250364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mWindowWidthCache = new WindowWidthCache(ims); 251364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs)); 252364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka prefs.registerOnSharedPreferenceChangeListener(this); 2535a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka } 254979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2555a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka private static int getKeyboardThemeIndex(Context context, SharedPreferences prefs) { 2565a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final String defaultThemeId = context.getString(R.string.config_default_keyboard_theme_id); 2575a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final String themeId = prefs.getString(PREF_KEYBOARD_LAYOUT, defaultThemeId); 25805ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka try { 2595a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final int themeIndex = Integer.valueOf(themeId); 2605a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka if (themeIndex >= 0 && themeIndex < KEYBOARD_THEMES.length) 2615a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka return themeIndex; 26205ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka } catch (NumberFormatException e) { 2635a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka // Format error, keyboard theme is default to 0. 2645a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka } 2655a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka Log.w(TAG, "Illegal keyboard theme in preference: " + themeId + ", default to 0"); 2665a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka return 0; 2675a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka } 2685a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka 2695a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka private void setContextThemeWrapper(Context context, int themeIndex) { 2705a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka if (mThemeIndex != themeIndex) { 2715a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mThemeIndex = themeIndex; 2725a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mThemeContext = new ContextThemeWrapper(context, KEYBOARD_THEMES[themeIndex]); 2735a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mKeyboardCache.clear(); 27405ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka } 275979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 276979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2772ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa public void loadKeyboard(EditorInfo editorInfo, Settings.Values settingsValues) { 278979f8690967ff5409fe18f5085858ccdb8e0ccf1satok try { 2792ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues); 2802ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues); 2812ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues); 282055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId())); 283979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } catch (RuntimeException e) { 28460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e); 28560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka LatinImeLogger.logOnException(mMainKeyboardId.toString(), e); 286979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 287353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 288353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger 289055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public KeyboardLayoutState getKeyboardState() { 290055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return mSavedKeyboardState; 291055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 292055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 293055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public void onFinishInputView() { 294055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsAutoCorrectionActive = false; 295055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 296055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 297c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka public void onHideWindow() { 298c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mIsAutoCorrectionActive = false; 299c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka } 300c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka 301055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public void registerWindowWidth() { 302055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mWindowWidthCache.registerWidth(); 303055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 304055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 30538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka @SuppressWarnings("unused") 30638f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka public void onSizeChanged(int w, int h, int oldw, int oldh) { 307c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka // TODO: This hack should be removed when display metric returns a proper width. 308c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka // Until then, the behavior of KeyboardSwitcher is suboptimal on a device that has a 309c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka // vertical system navigation bar in landscape screen orientation, for instance. 310364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final Configuration conf = mResources.getConfiguration(); 311364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int width = mWindowWidthCache.getWidthOnSizeChanged(conf); 31238f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // If the window width hasn't fixed yet or keyboard doesn't exist, nothing to do with. 31387154c656eaa2b9bf1f93e990a61b9f1c7d48babTadashi G. Takaoka if (width == 0 || mCurrentId == null) 314e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka return; 31538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Reload keyboard with new width. 316364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final KeyboardId newId = mCurrentId.cloneWithNewGeometry(conf.orientation, width); 317055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mInputMethodService.mHandler.postRestoreKeyboardLayout(); 318e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka setKeyboard(getKeyboard(newId)); 319e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 320e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 321055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private void setKeyboard(final Keyboard keyboard) { 322c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka final Keyboard oldKeyboard = mKeyboardView.getKeyboard(); 323055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardView.setKeyboard(keyboard); 324055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mCurrentId = keyboard.mId; 325055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mSwitchState = getSwitchState(mCurrentId); 326055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka updateShiftLockState(keyboard); 327c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.setKeyPreviewPopupEnabled( 3280a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources), 3290a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); 330050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka final boolean localeChanged = (oldKeyboard == null) 331055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); 332050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged); 333286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa updateShiftState(); 334353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 335353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger 336055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private int getSwitchState(KeyboardId id) { 337055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return id.equals(mMainKeyboardId) ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN; 338055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 339055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 340055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private void updateShiftLockState(Keyboard keyboard) { 341055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mCurrentId.equals(mSymbolsShiftedKeyboardId)) { 342055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // Symbol keyboard may have an ALT key that has a caps lock style indicator (a.k.a. 343055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked() 344055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // that takes care of the current keyboard having such ALT key or not. 345055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka keyboard.setShiftLocked(keyboard.hasShiftLockKey()); 346055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } else if (mCurrentId.equals(mSymbolsKeyboardId)) { 347055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the 348055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // indicator, we need to call setShiftLocked(false). 349055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka keyboard.setShiftLocked(false); 350055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 351055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 352055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 353353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger private LatinKeyboard getKeyboard(KeyboardId id) { 3548b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id); 355681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka LatinKeyboard keyboard = (ref == null) ? null : ref.get(); 356681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka if (keyboard == null) { 3570a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka final Locale savedLocale = Utils.setSystemLocale( 3580a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka mResources, mSubtypeSwitcher.getInputLocale()); 3598da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka try { 3608da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka keyboard = new LatinKeyboard.Builder(mThemeContext).load(id).build(); 3618da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka } finally { 3628da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka Utils.setSystemLocale(mResources, savedLocale); 3638da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka } 3648b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard)); 3658da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 3668da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka if (DEBUG_CACHE) { 3678b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": " 3688b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); 3698da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka } 370e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } else if (DEBUG_CACHE) { 3718b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id); 372353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 3738b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka 3741b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive); 37573c02390d31bbf32b78763db66b04004666fb5a3Tadashi G. Takaoka keyboard.setShiftLocked(false); 3768b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka keyboard.setShifted(false); 377de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka // If the cached keyboard had been switched to another keyboard while the language was 378de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka // displayed on its spacebar, it might have had arbitrary text fade factor. In such case, 3795cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaoka // we should reset the text fade factor. It is also applicable to shortcut key. 380de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka keyboard.setSpacebarTextFadeFactor(0.0f, null); 3814503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka keyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady(), null); 382681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka return keyboard; 383353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 384353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger 3852ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa private KeyboardId getKeyboardId(EditorInfo editorInfo, final boolean isSymbols, 3862ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final boolean isShift, Settings.Values settingsValues) { 3872ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final int mode = Utils.getKeyboardMode(editorInfo); 38859c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka final int xmlId; 38960ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka switch (mode) { 39060ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka case KeyboardId.MODE_PHONE: 39160ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka xmlId = (isSymbols && isShift) ? R.xml.kbd_phone_shift : R.xml.kbd_phone; 39260ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka break; 39360ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka case KeyboardId.MODE_NUMBER: 39460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka xmlId = R.xml.kbd_number; 39560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka break; 39660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka default: 39760ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (isSymbols) { 39860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka xmlId = isShift ? R.xml.kbd_symbols_shift : R.xml.kbd_symbols; 3992c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka } else { 4002c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka xmlId = R.xml.kbd_qwerty; 4012c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka } 40260ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka break; 403923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 40460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka 405cee174b8ccb47ccddc8a8a7e88a9c617f9b5e766Ken Wakasa final boolean settingsKeyEnabled = settingsValues.isSettingsKeyEnabled(); 40673e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka final boolean noMicrophone = Utils.inPrivateImeOptions( 40773e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo) 40873e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka || Utils.inPrivateImeOptions( 40973e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo); 41073e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka final boolean voiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo) 41173e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka && !noMicrophone; 4122ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final boolean voiceKeyOnMain = settingsValues.isVoiceKeyOnMain(); 4130a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka final boolean noSettingsKey = Utils.inPrivateImeOptions( 4142ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, editorInfo); 4152ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final boolean hasSettingsKey = settingsKeyEnabled && !noSettingsKey; 4162ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final int f2KeyMode = getF2KeyMode(settingsKeyEnabled, noSettingsKey); 417c3afe2c244c14ed0f8a355fe608b3402e3656330Tadashi G. Takaoka final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != voiceKeyOnMain); 4182ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final Configuration conf = mResources.getConfiguration(); 4190a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka 4209b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka return new KeyboardId( 4212ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mResources.getResourceEntryName(xmlId), xmlId, mSubtypeSwitcher.getInputLocale(), 4222ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa conf.orientation, mWindowWidthCache.getWidth(conf), mode, editorInfo, 423c3afe2c244c14ed0f8a355fe608b3402e3656330Tadashi G. Takaoka hasSettingsKey, f2KeyMode, noSettingsKey, voiceKeyEnabled, hasShortcutKey); 4244199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka } 4254199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka 4263a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka public int getKeyboardMode() { 427cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT; 428923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 4291679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 4303a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka public boolean isAlphabetMode() { 431571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka return mCurrentId != null && mCurrentId.isAlphabetKeyboard(); 432923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 433923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 4341679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka public boolean isInputViewShown() { 43586e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return mCurrentInputView != null && mCurrentInputView.isShown(); 4361679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4371679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 4381679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka public boolean isKeyboardAvailable() { 439c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka if (mKeyboardView != null) 440c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView.getKeyboard() != null; 441b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 442b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 443b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka 444050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka public LatinKeyboard getLatinKeyboard() { 445c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka if (mKeyboardView != null) { 446c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka final Keyboard keyboard = mKeyboardView.getKeyboard(); 447050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka if (keyboard instanceof LatinKeyboard) 448050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka return (LatinKeyboard)keyboard; 449050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka } 450b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return null; 4511679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4521679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 453f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka public boolean isShiftedOrShiftLocked() { 454b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 455b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (latinKeyboard != null) 456f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return latinKeyboard.isShiftedOrShiftLocked(); 457b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 4581679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4591679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 4601679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka public boolean isShiftLocked() { 461b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 462b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (latinKeyboard != null) 463b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return latinKeyboard.isShiftLocked(); 464b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 4651679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4661679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 467f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka public boolean isAutomaticTemporaryUpperCase() { 468f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 469f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (latinKeyboard != null) 470f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return latinKeyboard.isAutomaticTemporaryUpperCase(); 471f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return false; 472f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 473f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka 474f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka public boolean isManualTemporaryUpperCase() { 475f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 476f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (latinKeyboard != null) 477f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return latinKeyboard.isManualTemporaryUpperCase(); 478f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return false; 479f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 480f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka 481d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka private boolean isManualTemporaryUpperCaseFromAuto() { 482d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 483d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka if (latinKeyboard != null) 484d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka return latinKeyboard.isManualTemporaryUpperCaseFromAuto(); 485d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka return false; 486d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka } 487d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka 488f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private void setManualTemporaryUpperCase(boolean shifted) { 489b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 4900d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka if (latinKeyboard != null) { 4910d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // On non-distinct multi touch panel device, we should also turn off the shift locked 4920d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // state when shift key is pressed to go to normal mode. 4930d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // On the other hand, on distinct multi touch panel device, turning off the shift locked 4940d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // state with shift key pressing is handled by onReleaseShift(). 495101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) { 4960d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka latinKeyboard.setShiftLocked(false); 4970d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka } 4980d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka if (latinKeyboard.setShifted(shifted)) { 499c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.invalidateAllKeys(); 5000d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka } 501979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 502979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 503979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 504b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka private void setShiftLocked(boolean shiftLocked) { 505b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 506b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) { 507c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.invalidateAllKeys(); 508b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 509979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 510979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 5110d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka /** 5120d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka * Toggle keyboard shift state triggered by user touch event. 5130d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka */ 514b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void toggleShift() { 515b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mInputMethodService.mHandler.cancelUpdateShiftState(); 516f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 517f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "toggleShift:" 518f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 519f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState); 520b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isAlphabetMode()) { 521f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka setManualTemporaryUpperCase(!isShiftedOrShiftLocked()); 522b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } else { 523b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka toggleShiftInSymbol(); 524b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 525b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 526b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka 527b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void toggleCapsLock() { 528b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mInputMethodService.mHandler.cancelUpdateShiftState(); 529f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 530f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "toggleCapsLock:" 531f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 532f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState); 533b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isAlphabetMode()) { 534b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isShiftLocked()) { 535f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift key is long pressed while caps lock state, we will toggle back to normal 536f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // state. And mark as if shift key is released. 537f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka setShiftLocked(false); 538f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka mShiftKeyState.onRelease(); 539b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } else { 540b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka setShiftLocked(true); 541b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 542b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 543889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 544889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 545f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private void setAutomaticTemporaryUpperCase() { 546286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa if (mKeyboardView == null) return; 547286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa final Keyboard keyboard = mKeyboardView.getKeyboard(); 548e56e88beffe7afee3b41da4697304e1f4c031787Ken Wakasa if (keyboard == null) return; 549e56e88beffe7afee3b41da4697304e1f4c031787Ken Wakasa keyboard.setAutomaticTemporaryUpperCase(); 550286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa mKeyboardView.invalidateAllKeys(); 551f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 552f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka 5530d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka /** 5540d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka * Update keyboard shift state triggered by connected EditText status change. 5550d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka */ 556b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void updateShiftState() { 55745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final ShiftKeyState shiftKeyState = mShiftKeyState; 558f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 559f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "updateShiftState:" 560f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState() 561f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 562286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa + " shiftKeyState=" + shiftKeyState 563286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa + " isAlphabetMode=" + isAlphabetMode() 564286a5bf1c68c8dd06ece9701a904593af2457586Ken Wakasa + " isShiftLocked=" + isShiftLocked()); 56545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (isAlphabetMode()) { 56645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (!isShiftLocked() && !shiftKeyState.isIgnoring()) { 56745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) { 56845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka // Only when shift key is releasing, automatic temporary upper case will be set. 56945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka setAutomaticTemporaryUpperCase(); 57045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } else { 57145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka setManualTemporaryUpperCase(shiftKeyState.isMomentary()); 57245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } 573f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 57445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } else { 57545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka // In symbol keyboard mode, we should clear shift key state because only alphabet 57645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka // keyboard has shift key. 57745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka shiftKeyState.onRelease(); 578b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 579889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 580889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 581b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void changeKeyboardMode() { 582f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 583f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "changeKeyboardMode:" 584f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 585f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState); 586b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka toggleKeyboardMode(); 587b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isShiftLocked() && isAlphabetMode()) 588b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka setShiftLocked(true); 589b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka updateShiftState(); 590889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 591889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 592e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onPressShift(boolean withSliding) { 593b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (!isKeyboardAvailable()) 594b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return; 595f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka ShiftKeyState shiftKeyState = mShiftKeyState; 596f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 597f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "onPressShift:" 598f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 599e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding); 600f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (isAlphabetMode()) { 601f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (isShiftLocked()) { 602f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift key is pressed while caps lock state, we will treat this state as shifted 603f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // caps lock state and mark as if shift key pressed while normal state. 604f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPress(); 6056769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka setManualTemporaryUpperCase(true); 606f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } else if (isAutomaticTemporaryUpperCase()) { 607f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift key is pressed while automatic temporary upper case, we have to move to 608f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // manual temporary upper case. 6096769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka shiftKeyState.onPress(); 610f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka setManualTemporaryUpperCase(true); 611f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } else if (isShiftedOrShiftLocked()) { 612f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // In manual upper case state, we just record shift key has been pressing while 613f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // shifted state. 614f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPressOnShifted(); 615f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } else { 616f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // In base layout, chording or manual temporary upper case mode is started. 617f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPress(); 6186769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka toggleShift(); 619f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 620b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } else { 621f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // In symbol mode, just toggle symbol and symbol more keyboard. 622f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPress(); 6236769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka toggleShift(); 624717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; 625b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 626b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 627b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka 628e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onReleaseShift(boolean withSliding) { 629b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (!isKeyboardAvailable()) 630b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return; 631f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka ShiftKeyState shiftKeyState = mShiftKeyState; 632f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 633f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "onReleaseShift:" 634f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 635e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding); 636b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isAlphabetMode()) { 637f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (shiftKeyState.isMomentary()) { 638f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // After chording input while normal state. 639f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka toggleShift(); 640e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) { 641f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift has been pressed without chording while caps lock state. 642f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka toggleCapsLock(); 643e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka // To be able to turn off caps lock by "double tap" on shift key, we should ignore 644e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka // the second tap of the "double tap" from now for a while because we just have 645e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka // already turned off caps lock above. 646c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.startIgnoringDoubleTap(); 647e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted() 648e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka && !withSliding) { 649f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift has been pressed without chording while shifted state. 650b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka toggleShift(); 651e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing() 652e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka && !withSliding) { 653d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka // Shift has been pressed without chording while manual temporary upper case 654d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka // transited from automatic temporary upper case. 655d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka toggleShift(); 656b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 657717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else { 658717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // In symbol mode, snap back to the previous keyboard mode if the user chords the shift 659717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // key and another key, then releases the shift key. 660717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) { 661717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka toggleShift(); 662717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 663b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 664f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onRelease(); 665889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 666889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 6676c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka public void onPressSymbol() { 668f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 6699e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka Log.d(TAG, "onPressSymbol:" 670f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 671f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " symbolKeyState=" + mSymbolKeyState); 672b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka changeKeyboardMode(); 6736c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka mSymbolKeyState.onPress(); 674717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; 6756c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka } 6766c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka 6776c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka public void onReleaseSymbol() { 678f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 6799e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka Log.d(TAG, "onReleaseSymbol:" 680f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 681f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " symbolKeyState=" + mSymbolKeyState); 6829e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Snap back to the previous keyboard mode if the user chords the mode change key and 683717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // another key, then releases the mode change key. 684717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) { 685b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka changeKeyboardMode(); 686717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 6876c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka mSymbolKeyState.onRelease(); 6886c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka } 6896c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka 6906c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka public void onOtherKeyPressed() { 69145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (DEBUG_STATE) 69245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka Log.d(TAG, "onOtherKeyPressed:" 69345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 69445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState 69545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka + " symbolKeyState=" + mSymbolKeyState); 696f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka mShiftKeyState.onOtherKeyPressed(); 6976c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka mSymbolKeyState.onOtherKeyPressed(); 6986c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka } 6996c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka 7005f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka public void onCancelInput() { 7015f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Snap back to the previous keyboard mode if the user cancels sliding input. 702717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (getPointerCount() == 1) { 703717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) { 704717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka changeKeyboardMode(); 705717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) { 706717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka toggleShift(); 707717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 708717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 7095f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka } 7105f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka 711b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka private void toggleShiftInSymbol() { 7127e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka if (isAlphabetMode()) 7137e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka return; 7148b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka final LatinKeyboard keyboard; 71560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (mCurrentId.equals(mSymbolsKeyboardId) 71660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka || !mCurrentId.equals(mSymbolsShiftedKeyboardId)) { 71760ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka keyboard = getKeyboard(mSymbolsShiftedKeyboardId); 7187e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka } else { 71960ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka keyboard = getKeyboard(mSymbolsKeyboardId); 720923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 721050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka setKeyboard(keyboard); 722923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 723923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 724717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka public boolean isInMomentarySwitchState() { 725717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL 726717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; 7279e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 7289e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka 729cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isVibrateAndSoundFeedbackRequired() { 730c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView == null || !mKeyboardView.isInSlidingKeyInput(); 731cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 732cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 7339e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka private int getPointerCount() { 734c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView == null ? 0 : mKeyboardView.getPointerCount(); 7359e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 7369e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka 737f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private void toggleKeyboardMode() { 73860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (mCurrentId.equals(mMainKeyboardId)) { 73960ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka setKeyboard(getKeyboard(mSymbolsKeyboardId)); 740b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } else { 74160ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka setKeyboard(getKeyboard(mMainKeyboardId)); 742b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 743b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 744b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 745c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka public boolean hasDistinctMultitouch() { 746c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch(); 747c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka } 748c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka 749717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static boolean isSpaceCharacter(int c) { 750717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER; 751717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 752717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka 753717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static boolean isQuoteCharacter(int c) { 754717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Apostrophe, quotation mark. 7550730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard if (c == Keyboard.CODE_SINGLE_QUOTE || c == Keyboard.CODE_DOUBLE_QUOTE) 756717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return true; 757717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u2018: Left single quotation mark 758717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u2019: Right single quotation mark 759717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201a: Single low-9 quotation mark 760717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201b: Single high-reversed-9 quotation mark 761717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201c: Left double quotation mark 762717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201d: Right double quotation mark 763717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201e: Double low-9 quotation mark 764717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201f: Double high-reversed-9 quotation mark 765717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (c >= '\u2018' && c <= '\u201f') 766717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return true; 767717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u00ab: Left-pointing double angle quotation mark 768717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u00bb: Right-pointing double angle quotation mark 769717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (c == '\u00ab' || c == '\u00bb') 770717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return true; 771717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return false; 772717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 773717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka 774b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani /** 7759e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka * Updates state machine to figure out when to automatically snap back to the previous mode. 776b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani */ 777717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka public void onKey(int code) { 7789e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka if (DEBUG_STATE) 779717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState 7809e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka + " pointers=" + getPointerCount()); 781717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka switch (mSwitchState) { 782717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: 7839e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Only distinct multi touch devices can be in this state. 7845f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // On non-distinct multi touch devices, mode change key is handled by 7855f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and 786717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts 787717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from 788717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // {@link #SWITCH_STATE_MOMENTARY}. 789717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { 7909e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Detected only the mode change key has been pressed, and then released. 79160ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (mCurrentId.equals(mMainKeyboardId)) { 792717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_ALPHA; 79360ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka } else { 79460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; 7959e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 7969e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } else if (getPointerCount() == 1) { 7979e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Snap back to the previous keyboard mode if the user pressed the mode change key 7989e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // and slid to other key, then released the finger. 7995f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // If the user cancels the sliding input, snapping back to the previous keyboard 8005f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // mode is handled by {@link #onCancelInput}. 8019e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka changeKeyboardMode(); 8029e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } else { 8039e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Chording input is being started. The keyboard mode will be snapped back to the 8049e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // previous mode in {@link onReleaseSymbol} when the mode change key is released. 805717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_CHORDING_ALPHA; 806717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 807717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka break; 808717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: 809717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (code == Keyboard.CODE_SHIFT) { 810717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Detected only the shift key has been pressed on symbol layout, and then released. 811717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; 812717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else if (getPointerCount() == 1) { 813717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Snap back to the previous keyboard mode if the user pressed the shift key on 814717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // symbol mode and slid to other key, then released the finger. 815717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka toggleShift(); 816717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL; 817717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else { 818717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Chording input is being started. The keyboard mode will be snapped back to the 819717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // previous mode in {@link onReleaseShift} when the shift key is released. 820717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_CHORDING_SYMBOL; 8219e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 8229e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka break; 823717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_SYMBOL_BEGIN: 824717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (!isSpaceCharacter(code) && code >= 0) { 825717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL; 826b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 8270b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa // Snap back to alpha keyboard mode immediately if user types a quote character. 8280b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa if (isQuoteCharacter(code)) { 8290b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa changeKeyboardMode(); 8300b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa } 831b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka break; 832717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_SYMBOL: 833717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_CHORDING_SYMBOL: 8349e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Snap back to alpha keyboard mode if user types one or more non-space/enter 8350b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa // characters followed by a space/enter or a quote character. 836717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (isSpaceCharacter(code) || isQuoteCharacter(code)) { 837b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka changeKeyboardMode(); 838b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 839b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka break; 840b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 841923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 842979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 843c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public LatinKeyboardView getKeyboardView() { 844c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView; 845979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 846979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 847c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public View onCreateInputView() { 848f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka return createInputView(mThemeIndex, true); 849979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 850979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 851f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka private View createInputView(final int newThemeIndex, final boolean forceRecreate) { 852f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka if (mCurrentInputView != null && mThemeIndex == newThemeIndex && !forceRecreate) 853f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka return mCurrentInputView; 854f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka 855f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka if (mKeyboardView != null) { 856f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka mKeyboardView.closing(); 857f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka } 858f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka 8595a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final int oldThemeIndex = mThemeIndex; 860f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka Utils.GCUtils.getInstance().reset(); 861f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka boolean tryGC = true; 862f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 863f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka try { 8645a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka setContextThemeWrapper(mInputMethodService, newThemeIndex); 8655a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mCurrentInputView = LayoutInflater.from(mThemeContext).inflate( 86613a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka R.layout.input_view, null); 867f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka tryGC = false; 868f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka } catch (OutOfMemoryError e) { 869f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka Log.w(TAG, "load keyboard failed: " + e); 8705a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait( 8715a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka oldThemeIndex + "," + newThemeIndex, e); 872f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka } catch (InflateException e) { 873f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka Log.w(TAG, "load keyboard failed: " + e); 8745a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait( 8755a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka oldThemeIndex + "," + newThemeIndex, e); 876979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 877979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 878f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka 879070760dc5abdb9a850a94c509eeb9f486515af59Tadashi G. Takaoka mKeyboardView = (LatinKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); 8805a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboardView.setKeyboardActionListener(mInputMethodService); 8815ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 8825ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // This always needs to be set since the accessibility state can 8835ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // potentially change without the input view being re-created. 8845ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette AccessibleKeyboardViewProxy.setView(mKeyboardView); 8855ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 886f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka return mCurrentInputView; 8878d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka } 8888d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka 889f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka private void postSetInputView(final View newInputView) { 890979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mInputMethodService.mHandler.post(new Runnable() { 8918d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka @Override 892979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public void run() { 893f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka if (newInputView != null) { 894f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka mInputMethodService.setInputView(newInputView); 895979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 896979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mInputMethodService.updateInputViewShown(); 8978d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka } 8988d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka }); 899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 900979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 9018d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka @Override 902979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 903979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (PREF_KEYBOARD_LAYOUT.equals(key)) { 9042ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final int themeIndex = getKeyboardThemeIndex(mInputMethodService, sharedPreferences); 9052ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa postSetInputView(createInputView(themeIndex, false)); 9062ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa } else if (Settings.PREF_SHOW_SETTINGS_KEY.equals(key)) { 907f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka postSetInputView(createInputView(mThemeIndex, true)); 908979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 909979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 910979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 9111b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka public void onAutoCorrectionStateChanged(boolean isAutoCorrection) { 9125e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka if (mIsAutoCorrectionActive != isAutoCorrection) { 9131b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka mIsAutoCorrectionActive = isAutoCorrection; 9145e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka final LatinKeyboard keyboard = getLatinKeyboard(); 9155e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka if (keyboard != null && keyboard.needsAutoCorrectionSpacebarLed()) { 9165e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka final Key invalidatedKey = keyboard.onAutoCorrectionStateChanged(isAutoCorrection); 9175e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka final LatinKeyboardView keyboardView = getKeyboardView(); 9185e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka if (keyboardView != null) 9195e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka keyboardView.invalidateKey(invalidatedKey); 9205e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka } 92141feaaadb758a8b31d3e436063b4b5faed104d4dsatok } 92241feaaadb758a8b31d3e436063b4b5faed104d4dsatok } 9231508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa 9242ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa private static int getF2KeyMode(boolean settingsKeyEnabled, boolean noSettingsKey) { 9252ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa if (noSettingsKey) { 9262ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa // Never shows the Settings key 927cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka return KeyboardId.F2KEY_MODE_SHORTCUT_IME; 928cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka } 9292ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa 9302ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa if (settingsKeyEnabled) { 9312ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa return KeyboardId.F2KEY_MODE_SETTINGS; 9322ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa } else { 9332ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa // It should be alright to fall back to the Settings key on 7-inch layouts 9342ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa // even when the Settings key is not explicitly enabled. 9352ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa return KeyboardId.F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS; 9362ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa } 937cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka } 938923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 939