KeyboardSwitcher.java revision 055054eef3ccd32c6dfd69a3f76bfb7383ea93bb
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() { 190055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsAlphabetMode = isAlphabetMode(); 191055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsShiftLocked = mIsAlphabetMode && isShiftLocked(); 192055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsShifted = !mIsShiftLocked && isShiftedOrShiftLocked(); 193055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsValid = true; 194055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 195055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 196055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public KeyboardId getKeyboardId() { 197055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (!mIsValid) return mMainKeyboardId; 198055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 199055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mIsAlphabetMode) { 200055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return mMainKeyboardId; 201055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } else { 202055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return mIsShifted ? mSymbolsShiftedKeyboardId : mSymbolsKeyboardId; 203055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 204055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 205055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 206055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public void restore() { 207055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (!mIsValid) return; 208055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsValid = false; 209055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 210055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mIsAlphabetMode) { 211055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final boolean isAlphabetMode = isAlphabetMode(); 212055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final boolean isShiftLocked = isAlphabetMode && isShiftLocked(); 213055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka final boolean isShifted = !isShiftLocked && isShiftedOrShiftLocked(); 214055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mIsShiftLocked != isShiftLocked) { 215055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka toggleCapsLock(); 216055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } else if (mIsShifted != isShifted) { 217055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka onPressShift(false); 218055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka onReleaseShift(false); 219055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 220055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 221055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 222055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 223055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 2240ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok public static KeyboardSwitcher getInstance() { 2250ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok return sInstance; 2260ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok } 2270ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok 2280ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok private KeyboardSwitcher() { 229e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka // Intentional empty constructor for singleton. 2300ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok } 2310ed7191b4d1013a0b9d2fd1f26733dee7364871dsatok 23227d13713bbb291d25a910f97d88a81fdbabddc0eKen Wakasa public static void init(LatinIME ims, SharedPreferences prefs) { 233364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka sInstance.initInternal(ims, prefs); 234364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka } 235364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka 236364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka private void initInternal(LatinIME ims, SharedPreferences prefs) { 237364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mInputMethodService = ims; 238364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mPackageName = ims.getPackageName(); 239364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mResources = ims.getResources(); 240364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mPrefs = prefs; 241364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 242364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka mWindowWidthCache = new WindowWidthCache(ims); 243364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka setContextThemeWrapper(ims, getKeyboardThemeIndex(ims, prefs)); 244364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka prefs.registerOnSharedPreferenceChangeListener(this); 2455a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka } 246979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2475a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka private static int getKeyboardThemeIndex(Context context, SharedPreferences prefs) { 2485a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final String defaultThemeId = context.getString(R.string.config_default_keyboard_theme_id); 2495a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final String themeId = prefs.getString(PREF_KEYBOARD_LAYOUT, defaultThemeId); 25005ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka try { 2515a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final int themeIndex = Integer.valueOf(themeId); 2525a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka if (themeIndex >= 0 && themeIndex < KEYBOARD_THEMES.length) 2535a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka return themeIndex; 25405ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka } catch (NumberFormatException e) { 2555a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka // Format error, keyboard theme is default to 0. 2565a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka } 2575a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka Log.w(TAG, "Illegal keyboard theme in preference: " + themeId + ", default to 0"); 2585a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka return 0; 2595a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka } 2605a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka 2615a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka private void setContextThemeWrapper(Context context, int themeIndex) { 2625a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka if (mThemeIndex != themeIndex) { 2635a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mThemeIndex = themeIndex; 2645a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mThemeContext = new ContextThemeWrapper(context, KEYBOARD_THEMES[themeIndex]); 2655a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mKeyboardCache.clear(); 26605ddb9a5d2b36f519a4de4b50448e258f40d2c0fTadashi G. Takaoka } 267979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 268979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 2692ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa public void loadKeyboard(EditorInfo editorInfo, Settings.Values settingsValues) { 270979f8690967ff5409fe18f5085858ccdb8e0ccf1satok try { 2712ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mMainKeyboardId = getKeyboardId(editorInfo, false, false, settingsValues); 2722ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mSymbolsKeyboardId = getKeyboardId(editorInfo, true, false, settingsValues); 2732ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mSymbolsShiftedKeyboardId = getKeyboardId(editorInfo, true, true, settingsValues); 274055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka setKeyboard(getKeyboard(mSavedKeyboardState.getKeyboardId())); 275055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka updateShiftState(); 276979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } catch (RuntimeException e) { 27760ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka Log.w(TAG, "loading keyboard failed: " + mMainKeyboardId, e); 27860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka LatinImeLogger.logOnException(mMainKeyboardId.toString(), e); 279979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 280353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 281353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger 282055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public KeyboardLayoutState getKeyboardState() { 283055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return mSavedKeyboardState; 284055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 285055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 286055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public void onFinishInputView() { 287055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mIsAutoCorrectionActive = false; 288055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 289055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 290c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka public void onHideWindow() { 291c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka mIsAutoCorrectionActive = false; 292c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka } 293c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka 294055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka public void registerWindowWidth() { 295055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mWindowWidthCache.registerWidth(); 296055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 297055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 29838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka @SuppressWarnings("unused") 29938f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka public void onSizeChanged(int w, int h, int oldw, int oldh) { 300c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka // TODO: This hack should be removed when display metric returns a proper width. 301c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka // Until then, the behavior of KeyboardSwitcher is suboptimal on a device that has a 302c3d175c01ff1956ddb1c2d608d69af1793b4ad8aTadashi G. Takaoka // vertical system navigation bar in landscape screen orientation, for instance. 303364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final Configuration conf = mResources.getConfiguration(); 304364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final int width = mWindowWidthCache.getWidthOnSizeChanged(conf); 30538f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // If the window width hasn't fixed yet or keyboard doesn't exist, nothing to do with. 30687154c656eaa2b9bf1f93e990a61b9f1c7d48babTadashi G. Takaoka if (width == 0 || mCurrentId == null) 307e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka return; 30838f55b36c3992a580cf7e20668b1eb72a4eb2431Tadashi G. Takaoka // Reload keyboard with new width. 309364f1fd1f84cca6c8d396064bfd8bc8fd1efefcbTadashi G. Takaoka final KeyboardId newId = mCurrentId.cloneWithNewGeometry(conf.orientation, width); 310055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mInputMethodService.mHandler.postRestoreKeyboardLayout(); 311e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka setKeyboard(getKeyboard(newId)); 312e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } 313e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka 314055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private void setKeyboard(final Keyboard keyboard) { 315c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka final Keyboard oldKeyboard = mKeyboardView.getKeyboard(); 316055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mKeyboardView.setKeyboard(keyboard); 317055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mCurrentId = keyboard.mId; 318055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka mSwitchState = getSwitchState(mCurrentId); 319055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka updateShiftLockState(keyboard); 320c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.setKeyPreviewPopupEnabled( 3210a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka Settings.Values.isKeyPreviewPopupEnabled(mPrefs, mResources), 3220a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka Settings.Values.getKeyPreviewPopupDismissDelay(mPrefs, mResources)); 323050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka final boolean localeChanged = (oldKeyboard == null) 324055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka || !keyboard.mId.mLocale.equals(oldKeyboard.mId.mLocale); 325050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka mInputMethodService.mHandler.startDisplayLanguageOnSpacebar(localeChanged); 326353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 327353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger 328055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private int getSwitchState(KeyboardId id) { 329055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka return id.equals(mMainKeyboardId) ? SWITCH_STATE_ALPHA : SWITCH_STATE_SYMBOL_BEGIN; 330055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 331055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 332055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka private void updateShiftLockState(Keyboard keyboard) { 333055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka if (mCurrentId.equals(mSymbolsShiftedKeyboardId)) { 334055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // Symbol keyboard may have an ALT key that has a caps lock style indicator (a.k.a. 335055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // sticky shift key). To show or dismiss the indicator, we need to call setShiftLocked() 336055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // that takes care of the current keyboard having such ALT key or not. 337055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka keyboard.setShiftLocked(keyboard.hasShiftLockKey()); 338055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } else if (mCurrentId.equals(mSymbolsKeyboardId)) { 339055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the 340055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka // indicator, we need to call setShiftLocked(false). 341055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka keyboard.setShiftLocked(false); 342055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 343055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka } 344055054eef3ccd32c6dfd69a3f76bfb7383ea93bbTadashi G. Takaoka 345353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger private LatinKeyboard getKeyboard(KeyboardId id) { 3468b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id); 347681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka LatinKeyboard keyboard = (ref == null) ? null : ref.get(); 348681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka if (keyboard == null) { 3490a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka final Locale savedLocale = Utils.setSystemLocale( 3500a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka mResources, mSubtypeSwitcher.getInputLocale()); 3518da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka try { 3528da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka keyboard = new LatinKeyboard.Builder(mThemeContext).load(id).build(); 3538da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka } finally { 3548da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka Utils.setSystemLocale(mResources, savedLocale); 3558da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka } 3568b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard)); 3578da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka 3588da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka if (DEBUG_CACHE) { 3598b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": " 3608b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); 3618da9a13760896cd78235b60d0ea680ea13620532Tadashi G. Takaoka } 362e896d31bb92146379c8b7c0050ee05eec0830317Tadashi G. Takaoka } else if (DEBUG_CACHE) { 3638b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id); 364353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 3658b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka 3661b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka keyboard.onAutoCorrectionStateChanged(mIsAutoCorrectionActive); 3678b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka keyboard.setShifted(false); 368de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka // If the cached keyboard had been switched to another keyboard while the language was 369de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka // displayed on its spacebar, it might have had arbitrary text fade factor. In such case, 3705cd87e1b1c4258e8d016518914eccfbb4437caceTadashi G. Takaoka // we should reset the text fade factor. It is also applicable to shortcut key. 371de0c8874a4eb1250e8439d9e4e1badca88316670Tadashi G. Takaoka keyboard.setSpacebarTextFadeFactor(0.0f, null); 3724503e2ea9853c1573f60903d8639d82e39e07c56Tadashi G. Takaoka keyboard.updateShortcutKey(mSubtypeSwitcher.isShortcutImeReady(), null); 373681b676b0aecb30e644f25550018ce2b6cea3e15Tadashi G. Takaoka return keyboard; 374353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger } 375353da6d207bed3d32ec38b9ce52e4a136adbf060Brandon Ballinger 3762ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa private KeyboardId getKeyboardId(EditorInfo editorInfo, final boolean isSymbols, 3772ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final boolean isShift, Settings.Values settingsValues) { 3782ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final int mode = Utils.getKeyboardMode(editorInfo); 37959c9930ca98f68aeb6b0b9dc19e29666b8fb152aTadashi G. Takaoka final int xmlId; 38060ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka switch (mode) { 38160ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka case KeyboardId.MODE_PHONE: 38260ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka xmlId = (isSymbols && isShift) ? R.xml.kbd_phone_shift : R.xml.kbd_phone; 38360ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka break; 38460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka case KeyboardId.MODE_NUMBER: 38560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka xmlId = R.xml.kbd_number; 38660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka break; 38760ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka default: 38860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (isSymbols) { 38960ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka xmlId = isShift ? R.xml.kbd_symbols_shift : R.xml.kbd_symbols; 3902c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka } else { 3912c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka xmlId = R.xml.kbd_qwerty; 3922c60d6e28ecf7d6f7e97a504ebfa97e286d931edTadashi G. Takaoka } 39360ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka break; 394923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 39560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka 3962ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final boolean settingsKeyEnabled = settingsValues.isSettingsKeyEnabled(editorInfo); 39773e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka final boolean noMicrophone = Utils.inPrivateImeOptions( 39873e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka mPackageName, LatinIME.IME_OPTION_NO_MICROPHONE, editorInfo) 39973e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka || Utils.inPrivateImeOptions( 40073e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka null, LatinIME.IME_OPTION_NO_MICROPHONE_COMPAT, editorInfo); 40173e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka final boolean voiceKeyEnabled = settingsValues.isVoiceKeyEnabled(editorInfo) 40273e716f20284f929b2c0323c9e4759efe558de9dTadashi G. Takaoka && !noMicrophone; 4032ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final boolean voiceKeyOnMain = settingsValues.isVoiceKeyOnMain(); 4040a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka final boolean noSettingsKey = Utils.inPrivateImeOptions( 4052ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mPackageName, LatinIME.IME_OPTION_NO_SETTINGS_KEY, editorInfo); 4062ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final boolean hasSettingsKey = settingsKeyEnabled && !noSettingsKey; 4072ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final int f2KeyMode = getF2KeyMode(settingsKeyEnabled, noSettingsKey); 408c3afe2c244c14ed0f8a355fe608b3402e3656330Tadashi G. Takaoka final boolean hasShortcutKey = voiceKeyEnabled && (isSymbols != voiceKeyOnMain); 4092ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final Configuration conf = mResources.getConfiguration(); 4100a054dd1075d679385434ecef38a3d88c7551d7aTadashi G. Takaoka 4119b6d1d52d91f8f18952ae3841f4bb0d7309bfc0eTadashi G. Takaoka return new KeyboardId( 4122ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa mResources.getResourceEntryName(xmlId), xmlId, mSubtypeSwitcher.getInputLocale(), 4132ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa conf.orientation, mWindowWidthCache.getWidth(conf), mode, editorInfo, 414c3afe2c244c14ed0f8a355fe608b3402e3656330Tadashi G. Takaoka hasSettingsKey, f2KeyMode, noSettingsKey, voiceKeyEnabled, hasShortcutKey); 4154199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka } 4164199e29a7d796191d3e13ef07e6e80e91834fe7aTadashi G. Takaoka 4173a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka public int getKeyboardMode() { 418cb97c2f1407364b24dc1a54226481a55501d1533Tadashi G. Takaoka return mCurrentId != null ? mCurrentId.mMode : KeyboardId.MODE_TEXT; 419923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 4201679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 4213a2896c80475094f751ef447fc9c97028bfc2265Tadashi G. Takaoka public boolean isAlphabetMode() { 422571bdb401f670b92bd7710a12a990cb65a99b7d3Tadashi G. Takaoka return mCurrentId != null && mCurrentId.isAlphabetKeyboard(); 423923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 424923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 4251679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka public boolean isInputViewShown() { 42686e815a142c8aa13213151e381a8a24ef23073d3Tadashi G. Takaoka return mCurrentInputView != null && mCurrentInputView.isShown(); 4271679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4281679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 4291679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka public boolean isKeyboardAvailable() { 430c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka if (mKeyboardView != null) 431c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView.getKeyboard() != null; 432b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 433b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 434b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka 435050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka public LatinKeyboard getLatinKeyboard() { 436c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka if (mKeyboardView != null) { 437c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka final Keyboard keyboard = mKeyboardView.getKeyboard(); 438050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka if (keyboard instanceof LatinKeyboard) 439050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka return (LatinKeyboard)keyboard; 440050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka } 441b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return null; 4421679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4431679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 444f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka public boolean isShiftedOrShiftLocked() { 445b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 446b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (latinKeyboard != null) 447f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return latinKeyboard.isShiftedOrShiftLocked(); 448b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 4491679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4501679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 4511679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka public boolean isShiftLocked() { 452b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 453b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (latinKeyboard != null) 454b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return latinKeyboard.isShiftLocked(); 455b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return false; 4561679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka } 4571679432d1c8a8cfe6ff09be0a49792f4af91ab35Tadashi G. Takaoka 458f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka public boolean isAutomaticTemporaryUpperCase() { 459f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 460f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (latinKeyboard != null) 461f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return latinKeyboard.isAutomaticTemporaryUpperCase(); 462f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return false; 463f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 464f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka 465f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka public boolean isManualTemporaryUpperCase() { 466f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 467f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (latinKeyboard != null) 468f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return latinKeyboard.isManualTemporaryUpperCase(); 469f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka return false; 470f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 471f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka 472d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka private boolean isManualTemporaryUpperCaseFromAuto() { 473d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 474d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka if (latinKeyboard != null) 475d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka return latinKeyboard.isManualTemporaryUpperCaseFromAuto(); 476d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka return false; 477d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka } 478d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka 479f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private void setManualTemporaryUpperCase(boolean shifted) { 480b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 4810d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka if (latinKeyboard != null) { 4820d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // On non-distinct multi touch panel device, we should also turn off the shift locked 4830d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // state when shift key is pressed to go to normal mode. 4840d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // On the other hand, on distinct multi touch panel device, turning off the shift locked 4850d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka // state with shift key pressing is handled by onReleaseShift(). 486101a00e3d4b1c29ef2ecdecd1b72b43efde7791aTadashi G. Takaoka if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) { 4870d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka latinKeyboard.setShiftLocked(false); 4880d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka } 4890d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka if (latinKeyboard.setShifted(shifted)) { 490c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.invalidateAllKeys(); 4910d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka } 492979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 493979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 494979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 495b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka private void setShiftLocked(boolean shiftLocked) { 496b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 497b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) { 498c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.invalidateAllKeys(); 499b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 500979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 501979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 5020d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka /** 5030d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka * Toggle keyboard shift state triggered by user touch event. 5040d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka */ 505b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void toggleShift() { 506b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mInputMethodService.mHandler.cancelUpdateShiftState(); 507f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 508f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "toggleShift:" 509f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 510f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState); 511b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isAlphabetMode()) { 512f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka setManualTemporaryUpperCase(!isShiftedOrShiftLocked()); 513b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } else { 514b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka toggleShiftInSymbol(); 515b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 516b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 517b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka 518b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void toggleCapsLock() { 519b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka mInputMethodService.mHandler.cancelUpdateShiftState(); 520f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 521f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "toggleCapsLock:" 522f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 523f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState); 524b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isAlphabetMode()) { 525b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isShiftLocked()) { 526f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift key is long pressed while caps lock state, we will toggle back to normal 527f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // state. And mark as if shift key is released. 528f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka setShiftLocked(false); 529f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka mShiftKeyState.onRelease(); 530b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } else { 531b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka setShiftLocked(true); 532b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 533b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 534889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 535889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 536f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private void setAutomaticTemporaryUpperCase() { 537f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka LatinKeyboard latinKeyboard = getLatinKeyboard(); 538f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (latinKeyboard != null) { 539f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka latinKeyboard.setAutomaticTemporaryUpperCase(); 540c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.invalidateAllKeys(); 541f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 542f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 543f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka 5440d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka /** 5450d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka * Update keyboard shift state triggered by connected EditText status change. 5460d0a46da0393c6dd73cccf5e22cb0dd70c99e15aTadashi G. Takaoka */ 547b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void updateShiftState() { 54845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka final ShiftKeyState shiftKeyState = mShiftKeyState; 549f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 550f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "updateShiftState:" 551f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState() 552f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 55345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka + " shiftKeyState=" + shiftKeyState); 55445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (isAlphabetMode()) { 55545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (!isShiftLocked() && !shiftKeyState.isIgnoring()) { 55645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) { 55745911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka // Only when shift key is releasing, automatic temporary upper case will be set. 55845911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka setAutomaticTemporaryUpperCase(); 55945911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } else { 56045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka setManualTemporaryUpperCase(shiftKeyState.isMomentary()); 56145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } 562f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 56345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka } else { 56445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka // In symbol keyboard mode, we should clear shift key state because only alphabet 56545911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka // keyboard has shift key. 56645911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka shiftKeyState.onRelease(); 567b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 568889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 569889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 570b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka public void changeKeyboardMode() { 571f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 572f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "changeKeyboardMode:" 573f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 574f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState); 575b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka toggleKeyboardMode(); 576b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isShiftLocked() && isAlphabetMode()) 577b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka setShiftLocked(true); 578b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka updateShiftState(); 579889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 580889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 581e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onPressShift(boolean withSliding) { 582b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (!isKeyboardAvailable()) 583b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return; 584f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka ShiftKeyState shiftKeyState = mShiftKeyState; 585f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 586f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "onPressShift:" 587f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 588e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding); 589f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (isAlphabetMode()) { 590f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (isShiftLocked()) { 591f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift key is pressed while caps lock state, we will treat this state as shifted 592f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // caps lock state and mark as if shift key pressed while normal state. 593f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPress(); 5946769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka setManualTemporaryUpperCase(true); 595f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } else if (isAutomaticTemporaryUpperCase()) { 596f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift key is pressed while automatic temporary upper case, we have to move to 597f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // manual temporary upper case. 5986769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka shiftKeyState.onPress(); 599f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka setManualTemporaryUpperCase(true); 600f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } else if (isShiftedOrShiftLocked()) { 601f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // In manual upper case state, we just record shift key has been pressing while 602f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // shifted state. 603f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPressOnShifted(); 604f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } else { 605f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // In base layout, chording or manual temporary upper case mode is started. 606f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPress(); 6076769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka toggleShift(); 608f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka } 609b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } else { 610f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // In symbol mode, just toggle symbol and symbol more keyboard. 611f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onPress(); 6126769c67987f323008647f5d029c02f8cc95272eeTadashi G. Takaoka toggleShift(); 613717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; 614b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 615b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 616b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka 617e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka public void onReleaseShift(boolean withSliding) { 618b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (!isKeyboardAvailable()) 619b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka return; 620f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka ShiftKeyState shiftKeyState = mShiftKeyState; 621f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 622f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka Log.d(TAG, "onReleaseShift:" 623f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 624e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka + " shiftKeyState=" + shiftKeyState + " sliding=" + withSliding); 625b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka if (isAlphabetMode()) { 626f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (shiftKeyState.isMomentary()) { 627f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // After chording input while normal state. 628f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka toggleShift(); 629e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka } else if (isShiftLocked() && !shiftKeyState.isIgnoring() && !withSliding) { 630f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift has been pressed without chording while caps lock state. 631f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka toggleCapsLock(); 632e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka // To be able to turn off caps lock by "double tap" on shift key, we should ignore 633e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka // the second tap of the "double tap" from now for a while because we just have 634e541f03286189eebbc4a75615070e0e6f43ec37cTadashi G. Takaoka // already turned off caps lock above. 635c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka mKeyboardView.startIgnoringDoubleTap(); 636e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted() 637e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka && !withSliding) { 638f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka // Shift has been pressed without chording while shifted state. 639b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka toggleShift(); 640e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka } else if (isManualTemporaryUpperCaseFromAuto() && shiftKeyState.isPressing() 641e59491460b0411bed430a5ca6eca0c56c5bf18d9Tadashi G. Takaoka && !withSliding) { 642d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka // Shift has been pressed without chording while manual temporary upper case 643d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka // transited from automatic temporary upper case. 644d01ae897d38d4e788e4f089e2b1d6d74655847c6Tadashi G. Takaoka toggleShift(); 645b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 646717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else { 647717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // In symbol mode, snap back to the previous keyboard mode if the user chords the shift 648717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // key and another key, then releases the shift key. 649717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (mSwitchState == SWITCH_STATE_CHORDING_SYMBOL) { 650717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka toggleShift(); 651717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 652b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 653f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka shiftKeyState.onRelease(); 654889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka } 655889691eca1ad991a85fb721deb37ecba6a913762Tadashi G. Takaoka 6566c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka public void onPressSymbol() { 657f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 6589e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka Log.d(TAG, "onPressSymbol:" 659f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 660f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " symbolKeyState=" + mSymbolKeyState); 661b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka changeKeyboardMode(); 6626c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka mSymbolKeyState.onPress(); 663717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL; 6646c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka } 6656c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka 6666c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka public void onReleaseSymbol() { 667f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka if (DEBUG_STATE) 6689e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka Log.d(TAG, "onReleaseSymbol:" 669f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 670f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka + " symbolKeyState=" + mSymbolKeyState); 6719e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Snap back to the previous keyboard mode if the user chords the mode change key and 672717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // another key, then releases the mode change key. 673717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (mSwitchState == SWITCH_STATE_CHORDING_ALPHA) { 674b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka changeKeyboardMode(); 675717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 6766c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka mSymbolKeyState.onRelease(); 6776c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka } 6786c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka 6796c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka public void onOtherKeyPressed() { 68045911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka if (DEBUG_STATE) 68145911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka Log.d(TAG, "onOtherKeyPressed:" 68245911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 68345911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka + " shiftKeyState=" + mShiftKeyState 68445911256fd4e32880e33c42259b19e8d7af70cb1Tadashi G. Takaoka + " symbolKeyState=" + mSymbolKeyState); 685f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka mShiftKeyState.onOtherKeyPressed(); 6866c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka mSymbolKeyState.onOtherKeyPressed(); 6876c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka } 6886c92ee127df50509d364a2b6d428b223d2cbaa6eTadashi G. Takaoka 6895f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka public void onCancelInput() { 6905f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // Snap back to the previous keyboard mode if the user cancels sliding input. 691717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (getPointerCount() == 1) { 692717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL) { 693717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka changeKeyboardMode(); 694717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else if (mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE) { 695717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka toggleShift(); 696717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 697717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 6985f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka } 6995f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka 700b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka private void toggleShiftInSymbol() { 7017e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka if (isAlphabetMode()) 7027e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka return; 7038b00bc4f3281c229ee830f34a78c0ec287902c3fTadashi G. Takaoka final LatinKeyboard keyboard; 70460ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (mCurrentId.equals(mSymbolsKeyboardId) 70560ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka || !mCurrentId.equals(mSymbolsShiftedKeyboardId)) { 70660ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka keyboard = getKeyboard(mSymbolsShiftedKeyboardId); 7077e1f5a2d5a96c74691b3b09fa986efb7161e5a12Tadashi G. Takaoka } else { 70860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka keyboard = getKeyboard(mSymbolsKeyboardId); 709923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 710050c0462dc2ada5a5afecec5b6745693c5066b85Tadashi G. Takaoka setKeyboard(keyboard); 711923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 712923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project 713717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka public boolean isInMomentarySwitchState() { 714717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return mSwitchState == SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL 715717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka || mSwitchState == SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE; 7169e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 7179e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka 718cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka public boolean isVibrateAndSoundFeedbackRequired() { 719c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView == null || !mKeyboardView.isInSlidingKeyInput(); 720cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka } 721cb2469ae17e0ca8a94767008fef3945cb2a3b406Tadashi G. Takaoka 7229e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka private int getPointerCount() { 723c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView == null ? 0 : mKeyboardView.getPointerCount(); 7249e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 7259e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka 726f27364600c742509b48857e6b8f17312033e0dc7Tadashi G. Takaoka private void toggleKeyboardMode() { 72760ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (mCurrentId.equals(mMainKeyboardId)) { 72860ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka setKeyboard(getKeyboard(mSymbolsKeyboardId)); 729b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } else { 73060ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka setKeyboard(getKeyboard(mMainKeyboardId)); 731b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 732b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 733b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani 734c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka public boolean hasDistinctMultitouch() { 735c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView != null && mKeyboardView.hasDistinctMultitouch(); 736c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka } 737c8b9afe0378e3f33c3f83271bd1df9678a70c2a2Tadashi G. Takaoka 738717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static boolean isSpaceCharacter(int c) { 739717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return c == Keyboard.CODE_SPACE || c == Keyboard.CODE_ENTER; 740717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 741717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka 742717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka private static boolean isQuoteCharacter(int c) { 743717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Apostrophe, quotation mark. 7440730bbfbf5e37bbcb5c287aeff71b304c833a36eJean Chalard if (c == Keyboard.CODE_SINGLE_QUOTE || c == Keyboard.CODE_DOUBLE_QUOTE) 745717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return true; 746717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u2018: Left single quotation mark 747717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u2019: Right single quotation mark 748717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201a: Single low-9 quotation mark 749717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201b: Single high-reversed-9 quotation mark 750717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201c: Left double quotation mark 751717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201d: Right double quotation mark 752717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201e: Double low-9 quotation mark 753717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u201f: Double high-reversed-9 quotation mark 754717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (c >= '\u2018' && c <= '\u201f') 755717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return true; 756717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u00ab: Left-pointing double angle quotation mark 757717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // \u00bb: Right-pointing double angle quotation mark 758717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (c == '\u00ab' || c == '\u00bb') 759717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return true; 760717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka return false; 761717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 762717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka 763b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani /** 7649e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka * Updates state machine to figure out when to automatically snap back to the previous mode. 765b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani */ 766717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka public void onKey(int code) { 7679e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka if (DEBUG_STATE) 768717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka Log.d(TAG, "onKey: code=" + code + " switchState=" + mSwitchState 7699e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka + " pointers=" + getPointerCount()); 770717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka switch (mSwitchState) { 771717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_MOMENTARY_ALPHA_AND_SYMBOL: 7729e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Only distinct multi touch devices can be in this state. 7735f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // On non-distinct multi touch devices, mode change key is handled by 7745f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // {@link LatinIME#onCodeInput}, not by {@link LatinIME#onPress} and 775717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // {@link LatinIME#onRelease}. So, on such devices, {@link #mSwitchState} starts 776717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // from {@link #SWITCH_STATE_SYMBOL_BEGIN}, or {@link #SWITCH_STATE_ALPHA}, not from 777717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // {@link #SWITCH_STATE_MOMENTARY}. 778717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (code == Keyboard.CODE_SWITCH_ALPHA_SYMBOL) { 7799e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Detected only the mode change key has been pressed, and then released. 78060ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka if (mCurrentId.equals(mMainKeyboardId)) { 781717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_ALPHA; 78260ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka } else { 78360ccbe16eea5ce9a874835850f257b3c88295022Tadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; 7849e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 7859e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } else if (getPointerCount() == 1) { 7869e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Snap back to the previous keyboard mode if the user pressed the mode change key 7879e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // and slid to other key, then released the finger. 7885f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // If the user cancels the sliding input, snapping back to the previous keyboard 7895f922caff80d5067c5af2bbbae2731ef25c9572aTadashi G. Takaoka // mode is handled by {@link #onCancelInput}. 7909e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka changeKeyboardMode(); 7919e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } else { 7929e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Chording input is being started. The keyboard mode will be snapped back to the 7939e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // previous mode in {@link onReleaseSymbol} when the mode change key is released. 794717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_CHORDING_ALPHA; 795717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } 796717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka break; 797717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_MOMENTARY_SYMBOL_AND_MORE: 798717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (code == Keyboard.CODE_SHIFT) { 799717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Detected only the shift key has been pressed on symbol layout, and then released. 800717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL_BEGIN; 801717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else if (getPointerCount() == 1) { 802717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Snap back to the previous keyboard mode if the user pressed the shift key on 803717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // symbol mode and slid to other key, then released the finger. 804717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka toggleShift(); 805717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL; 806717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka } else { 807717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // Chording input is being started. The keyboard mode will be snapped back to the 808717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka // previous mode in {@link onReleaseShift} when the shift key is released. 809717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_CHORDING_SYMBOL; 8109e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka } 8119e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka break; 812717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_SYMBOL_BEGIN: 813717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (!isSpaceCharacter(code) && code >= 0) { 814717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka mSwitchState = SWITCH_STATE_SYMBOL; 815b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 8160b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa // Snap back to alpha keyboard mode immediately if user types a quote character. 8170b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa if (isQuoteCharacter(code)) { 8180b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa changeKeyboardMode(); 8190b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa } 820b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka break; 821717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_SYMBOL: 822717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka case SWITCH_STATE_CHORDING_SYMBOL: 8239e91472285a1b903631f1e3c998f5aa1efd3e98eTadashi G. Takaoka // Snap back to alpha keyboard mode if user types one or more non-space/enter 8240b4757604de15bfe66c10e9cdf01da6d437c6082Ken Wakasa // characters followed by a space/enter or a quote character. 825717cef79ead5d63a01d09b47caab0a3d719c69dfTadashi G. Takaoka if (isSpaceCharacter(code) || isQuoteCharacter(code)) { 826b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka changeKeyboardMode(); 827b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka } 828b643dab73ab9527cc63d896cad81c0cdc92fe5f6Tadashi G. Takaoka break; 829b19668cfc17ad30afcc3c8c0407d47238ce1a90dAmith Yamasani } 830923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project } 831979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 832c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public LatinKeyboardView getKeyboardView() { 833c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka return mKeyboardView; 834979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 835979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 836c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355Tadashi G. Takaoka public View onCreateInputView() { 837f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka return createInputView(mThemeIndex, true); 838979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 839979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 840f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka private View createInputView(final int newThemeIndex, final boolean forceRecreate) { 841f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka if (mCurrentInputView != null && mThemeIndex == newThemeIndex && !forceRecreate) 842f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka return mCurrentInputView; 843f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka 844f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka if (mKeyboardView != null) { 845f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka mKeyboardView.closing(); 846f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka } 847f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka 8485a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka final int oldThemeIndex = mThemeIndex; 849f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka Utils.GCUtils.getInstance().reset(); 850f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka boolean tryGC = true; 851f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 852f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka try { 8535a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka setContextThemeWrapper(mInputMethodService, newThemeIndex); 8545a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka mCurrentInputView = LayoutInflater.from(mThemeContext).inflate( 85513a741999480343ccebd81ff6349b572bde17b07Tadashi G. Takaoka R.layout.input_view, null); 856f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka tryGC = false; 857f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka } catch (OutOfMemoryError e) { 858f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka Log.w(TAG, "load keyboard failed: " + e); 8595a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait( 8605a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka oldThemeIndex + "," + newThemeIndex, e); 861f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka } catch (InflateException e) { 862f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka Log.w(TAG, "load keyboard failed: " + e); 8635a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka tryGC = Utils.GCUtils.getInstance().tryGCOrWait( 8645a2d0630474d6df639e97ff48f5f48b220ca4ee9Tadashi G. Takaoka oldThemeIndex + "," + newThemeIndex, e); 865979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 866979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 867f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka 868070760dc5abdb9a850a94c509eeb9f486515af59Tadashi G. Takaoka mKeyboardView = (LatinKeyboardView) mCurrentInputView.findViewById(R.id.keyboard_view); 8695a7a696aff6718d4e0250c394a9d01cbf2a16916Tadashi G. Takaoka mKeyboardView.setKeyboardActionListener(mInputMethodService); 8705ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 8715ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // This always needs to be set since the accessibility state can 8725ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette // potentially change without the input view being re-created. 8735ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette AccessibleKeyboardViewProxy.setView(mKeyboardView); 8745ac4638f999db4fea8a9e24171dbceb640a10858Alan Viverette 875f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka return mCurrentInputView; 8768d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka } 8778d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka 878f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka private void postSetInputView(final View newInputView) { 879979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mInputMethodService.mHandler.post(new Runnable() { 8808d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka @Override 881979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public void run() { 882f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka if (newInputView != null) { 883f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka mInputMethodService.setInputView(newInputView); 884979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 885979f8690967ff5409fe18f5085858ccdb8e0ccf1satok mInputMethodService.updateInputViewShown(); 8868d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka } 8878d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka }); 888979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 889979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 8908d7ecc70a6572c288064e41235e4ae8ad5b1b47eTadashi G. Takaoka @Override 891979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 892979f8690967ff5409fe18f5085858ccdb8e0ccf1satok if (PREF_KEYBOARD_LAYOUT.equals(key)) { 8932ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa final int themeIndex = getKeyboardThemeIndex(mInputMethodService, sharedPreferences); 8942ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa postSetInputView(createInputView(themeIndex, false)); 8952ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa } else if (Settings.PREF_SHOW_SETTINGS_KEY.equals(key)) { 896f3cd2bb33d1688fd6de01787140a1ef2de4b7723Tadashi G. Takaoka postSetInputView(createInputView(mThemeIndex, true)); 897979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 898979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 899979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 9001b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka public void onAutoCorrectionStateChanged(boolean isAutoCorrection) { 9015e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka if (mIsAutoCorrectionActive != isAutoCorrection) { 9021b1f7f907f6c7d6e849c88ca06c3608bc84d7c5fTadashi G. Takaoka mIsAutoCorrectionActive = isAutoCorrection; 9035e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka final LatinKeyboard keyboard = getLatinKeyboard(); 9045e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka if (keyboard != null && keyboard.needsAutoCorrectionSpacebarLed()) { 9055e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka final Key invalidatedKey = keyboard.onAutoCorrectionStateChanged(isAutoCorrection); 9065e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka final LatinKeyboardView keyboardView = getKeyboardView(); 9075e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka if (keyboardView != null) 9085e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka keyboardView.invalidateKey(invalidatedKey); 9095e4e05afd2825bf7acb594fef5e7bd21c751dd63Tadashi G. Takaoka } 91041feaaadb758a8b31d3e436063b4b5faed104d4dsatok } 91141feaaadb758a8b31d3e436063b4b5faed104d4dsatok } 9121508c0e84f0cd93ab6f5d46fea5026e833f299bcKen Wakasa 9132ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa private static int getF2KeyMode(boolean settingsKeyEnabled, boolean noSettingsKey) { 9142ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa if (noSettingsKey) { 9152ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa // Never shows the Settings key 916cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka return KeyboardId.F2KEY_MODE_SHORTCUT_IME; 917cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka } 9182ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa 9192ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa if (settingsKeyEnabled) { 9202ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa return KeyboardId.F2KEY_MODE_SETTINGS; 9212ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa } else { 9222ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa // It should be alright to fall back to the Settings key on 7-inch layouts 9232ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa // even when the Settings key is not explicitly enabled. 9242ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa return KeyboardId.F2KEY_MODE_SHORTCUT_IME_OR_SETTINGS; 9252ba975afb9529a6574148596db190b939fbc3b3fKen Wakasa } 926cd96a691b14b384face577d907f6c1aa33b47233Tadashi G. Takaoka } 927923bf41f853a544fd0d71fbf7dc90359ec35981The Android Open Source Project} 928