1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 5 * use this file except in compliance with the License. You may obtain a copy of 6 * the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 13 * License for the specific language governing permissions and limitations under 14 * the License. 15 */ 16 17 package com.android.inputmethod.latin; 18 19 import android.content.SharedPreferences; 20 import android.content.res.Configuration; 21 import android.content.res.Resources; 22 import android.preference.PreferenceManager; 23 import android.view.InflateException; 24 25 import java.lang.ref.SoftReference; 26 import java.util.Arrays; 27 import java.util.HashMap; 28 import java.util.Locale; 29 30 public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener { 31 32 public static final int MODE_NONE = 0; 33 public static final int MODE_TEXT = 1; 34 public static final int MODE_SYMBOLS = 2; 35 public static final int MODE_PHONE = 3; 36 public static final int MODE_URL = 4; 37 public static final int MODE_EMAIL = 5; 38 public static final int MODE_IM = 6; 39 public static final int MODE_WEB = 7; 40 41 // Main keyboard layouts without the settings key 42 public static final int KEYBOARDMODE_NORMAL = R.id.mode_normal; 43 public static final int KEYBOARDMODE_URL = R.id.mode_url; 44 public static final int KEYBOARDMODE_EMAIL = R.id.mode_email; 45 public static final int KEYBOARDMODE_IM = R.id.mode_im; 46 public static final int KEYBOARDMODE_WEB = R.id.mode_webentry; 47 // Main keyboard layouts with the settings key 48 public static final int KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY = 49 R.id.mode_normal_with_settings_key; 50 public static final int KEYBOARDMODE_URL_WITH_SETTINGS_KEY = 51 R.id.mode_url_with_settings_key; 52 public static final int KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY = 53 R.id.mode_email_with_settings_key; 54 public static final int KEYBOARDMODE_IM_WITH_SETTINGS_KEY = 55 R.id.mode_im_with_settings_key; 56 public static final int KEYBOARDMODE_WEB_WITH_SETTINGS_KEY = 57 R.id.mode_webentry_with_settings_key; 58 59 // Symbols keyboard layout without the settings key 60 public static final int KEYBOARDMODE_SYMBOLS = R.id.mode_symbols; 61 // Symbols keyboard layout with the settings key 62 public static final int KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY = 63 R.id.mode_symbols_with_settings_key; 64 65 public static final String DEFAULT_LAYOUT_ID = "4"; 66 public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902"; 67 private static final int[] THEMES = new int [] { 68 R.layout.input_basic, R.layout.input_basic_highcontrast, R.layout.input_stone_normal, 69 R.layout.input_stone_bold, R.layout.input_gingerbread}; 70 71 // Ids for each characters' color in the keyboard 72 private static final int CHAR_THEME_COLOR_WHITE = 0; 73 private static final int CHAR_THEME_COLOR_BLACK = 1; 74 75 // Tables which contains resource ids for each character theme color 76 private static final int[] KBD_PHONE = new int[] {R.xml.kbd_phone, R.xml.kbd_phone_black}; 77 private static final int[] KBD_PHONE_SYMBOLS = new int[] { 78 R.xml.kbd_phone_symbols, R.xml.kbd_phone_symbols_black}; 79 private static final int[] KBD_SYMBOLS = new int[] { 80 R.xml.kbd_symbols, R.xml.kbd_symbols_black}; 81 private static final int[] KBD_SYMBOLS_SHIFT = new int[] { 82 R.xml.kbd_symbols_shift, R.xml.kbd_symbols_shift_black}; 83 private static final int[] KBD_QWERTY = new int[] {R.xml.kbd_qwerty, R.xml.kbd_qwerty_black}; 84 85 private LatinKeyboardView mInputView; 86 private static final int[] ALPHABET_MODES = { 87 KEYBOARDMODE_NORMAL, 88 KEYBOARDMODE_URL, 89 KEYBOARDMODE_EMAIL, 90 KEYBOARDMODE_IM, 91 KEYBOARDMODE_WEB, 92 KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY, 93 KEYBOARDMODE_URL_WITH_SETTINGS_KEY, 94 KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY, 95 KEYBOARDMODE_IM_WITH_SETTINGS_KEY, 96 KEYBOARDMODE_WEB_WITH_SETTINGS_KEY }; 97 98 private LatinIME mInputMethodService; 99 100 private KeyboardId mSymbolsId; 101 private KeyboardId mSymbolsShiftedId; 102 103 private KeyboardId mCurrentId; 104 private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboards = 105 new HashMap<KeyboardId, SoftReference<LatinKeyboard>>(); 106 107 private int mMode = MODE_NONE; /** One of the MODE_XXX values */ 108 private int mImeOptions; 109 private boolean mIsSymbols; 110 /** mIsAutoCompletionActive indicates that auto completed word will be input instead of 111 * what user actually typed. */ 112 private boolean mIsAutoCompletionActive; 113 private boolean mHasVoice; 114 private boolean mVoiceOnPrimary; 115 private boolean mPreferSymbols; 116 117 private static final int AUTO_MODE_SWITCH_STATE_ALPHA = 0; 118 private static final int AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN = 1; 119 private static final int AUTO_MODE_SWITCH_STATE_SYMBOL = 2; 120 // The following states are used only on the distinct multi-touch panel devices. 121 private static final int AUTO_MODE_SWITCH_STATE_MOMENTARY = 3; 122 private static final int AUTO_MODE_SWITCH_STATE_CHORDING = 4; 123 private int mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; 124 125 // Indicates whether or not we have the settings key 126 private boolean mHasSettingsKey; 127 private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto; 128 private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW = R.string.settings_key_mode_always_show; 129 // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to 130 // in the source code now. 131 // Default is SETTINGS_KEY_MODE_AUTO. 132 private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO; 133 134 private int mLastDisplayWidth; 135 private LanguageSwitcher mLanguageSwitcher; 136 private Locale mInputLocale; 137 138 private int mLayoutId; 139 140 private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); 141 getInstance()142 public static KeyboardSwitcher getInstance() { 143 return sInstance; 144 } 145 KeyboardSwitcher()146 private KeyboardSwitcher() { 147 // Intentional empty constructor for singleton. 148 } 149 init(LatinIME ims)150 public static void init(LatinIME ims) { 151 sInstance.mInputMethodService = ims; 152 153 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ims); 154 sInstance.mLayoutId = Integer.valueOf( 155 prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID)); 156 sInstance.updateSettingsKeyState(prefs); 157 prefs.registerOnSharedPreferenceChangeListener(sInstance); 158 159 sInstance.mSymbolsId = sInstance.makeSymbolsId(false); 160 sInstance.mSymbolsShiftedId = sInstance.makeSymbolsShiftedId(false); 161 } 162 163 /** 164 * Sets the input locale, when there are multiple locales for input. 165 * If no locale switching is required, then the locale should be set to null. 166 * @param locale the current input locale, or null for default locale with no locale 167 * button. 168 */ setLanguageSwitcher(LanguageSwitcher languageSwitcher)169 public void setLanguageSwitcher(LanguageSwitcher languageSwitcher) { 170 mLanguageSwitcher = languageSwitcher; 171 mInputLocale = mLanguageSwitcher.getInputLocale(); 172 } 173 makeSymbolsId(boolean hasVoice)174 private KeyboardId makeSymbolsId(boolean hasVoice) { 175 return new KeyboardId(KBD_SYMBOLS[getCharColorId()], mHasSettingsKey ? 176 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 177 false, hasVoice); 178 } 179 makeSymbolsShiftedId(boolean hasVoice)180 private KeyboardId makeSymbolsShiftedId(boolean hasVoice) { 181 return new KeyboardId(KBD_SYMBOLS_SHIFT[getCharColorId()], mHasSettingsKey ? 182 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 183 false, hasVoice); 184 } 185 makeKeyboards(boolean forceCreate)186 public void makeKeyboards(boolean forceCreate) { 187 mSymbolsId = makeSymbolsId(mHasVoice && !mVoiceOnPrimary); 188 mSymbolsShiftedId = makeSymbolsShiftedId(mHasVoice && !mVoiceOnPrimary); 189 190 if (forceCreate) mKeyboards.clear(); 191 // Configuration change is coming after the keyboard gets recreated. So don't rely on that. 192 // If keyboards have already been made, check if we have a screen width change and 193 // create the keyboard layouts again at the correct orientation 194 int displayWidth = mInputMethodService.getMaxWidth(); 195 if (displayWidth == mLastDisplayWidth) return; 196 mLastDisplayWidth = displayWidth; 197 if (!forceCreate) mKeyboards.clear(); 198 } 199 200 /** 201 * Represents the parameters necessary to construct a new LatinKeyboard, 202 * which also serve as a unique identifier for each keyboard type. 203 */ 204 private static class KeyboardId { 205 // TODO: should have locale and portrait/landscape orientation? 206 public final int mXml; 207 public final int mKeyboardMode; /** A KEYBOARDMODE_XXX value */ 208 public final boolean mEnableShiftLock; 209 public final boolean mHasVoice; 210 211 private final int mHashCode; 212 KeyboardId(int xml, int mode, boolean enableShiftLock, boolean hasVoice)213 public KeyboardId(int xml, int mode, boolean enableShiftLock, boolean hasVoice) { 214 this.mXml = xml; 215 this.mKeyboardMode = mode; 216 this.mEnableShiftLock = enableShiftLock; 217 this.mHasVoice = hasVoice; 218 219 this.mHashCode = Arrays.hashCode(new Object[] { 220 xml, mode, enableShiftLock, hasVoice 221 }); 222 } 223 KeyboardId(int xml, boolean hasVoice)224 public KeyboardId(int xml, boolean hasVoice) { 225 this(xml, 0, false, hasVoice); 226 } 227 228 @Override equals(Object other)229 public boolean equals(Object other) { 230 return other instanceof KeyboardId && equals((KeyboardId) other); 231 } 232 equals(KeyboardId other)233 private boolean equals(KeyboardId other) { 234 return other.mXml == this.mXml 235 && other.mKeyboardMode == this.mKeyboardMode 236 && other.mEnableShiftLock == this.mEnableShiftLock 237 && other.mHasVoice == this.mHasVoice; 238 } 239 240 @Override hashCode()241 public int hashCode() { 242 return mHashCode; 243 } 244 } 245 setVoiceMode(boolean enableVoice, boolean voiceOnPrimary)246 public void setVoiceMode(boolean enableVoice, boolean voiceOnPrimary) { 247 if (enableVoice != mHasVoice || voiceOnPrimary != mVoiceOnPrimary) { 248 mKeyboards.clear(); 249 } 250 mHasVoice = enableVoice; 251 mVoiceOnPrimary = voiceOnPrimary; 252 setKeyboardMode(mMode, mImeOptions, mHasVoice, mIsSymbols); 253 } 254 hasVoiceButton(boolean isSymbols)255 private boolean hasVoiceButton(boolean isSymbols) { 256 return mHasVoice && (isSymbols != mVoiceOnPrimary); 257 } 258 setKeyboardMode(int mode, int imeOptions, boolean enableVoice)259 public void setKeyboardMode(int mode, int imeOptions, boolean enableVoice) { 260 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; 261 mPreferSymbols = mode == MODE_SYMBOLS; 262 if (mode == MODE_SYMBOLS) { 263 mode = MODE_TEXT; 264 } 265 try { 266 setKeyboardMode(mode, imeOptions, enableVoice, mPreferSymbols); 267 } catch (RuntimeException e) { 268 LatinImeLogger.logOnException(mode + "," + imeOptions + "," + mPreferSymbols, e); 269 } 270 } 271 setKeyboardMode(int mode, int imeOptions, boolean enableVoice, boolean isSymbols)272 private void setKeyboardMode(int mode, int imeOptions, boolean enableVoice, boolean isSymbols) { 273 if (mInputView == null) return; 274 mMode = mode; 275 mImeOptions = imeOptions; 276 if (enableVoice != mHasVoice) { 277 // TODO clean up this unnecessary recursive call. 278 setVoiceMode(enableVoice, mVoiceOnPrimary); 279 } 280 mIsSymbols = isSymbols; 281 282 mInputView.setPreviewEnabled(mInputMethodService.getPopupOn()); 283 KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols); 284 LatinKeyboard keyboard = null; 285 keyboard = getKeyboard(id); 286 287 if (mode == MODE_PHONE) { 288 mInputView.setPhoneKeyboard(keyboard); 289 } 290 291 mCurrentId = id; 292 mInputView.setKeyboard(keyboard); 293 keyboard.setShifted(false); 294 keyboard.setShiftLocked(keyboard.isShiftLocked()); 295 keyboard.setImeOptions(mInputMethodService.getResources(), mMode, imeOptions); 296 keyboard.setColorOfSymbolIcons(mIsAutoCompletionActive, isBlackSym()); 297 // Update the settings key state because number of enabled IMEs could have been changed 298 updateSettingsKeyState(PreferenceManager.getDefaultSharedPreferences(mInputMethodService)); 299 } 300 getKeyboard(KeyboardId id)301 private LatinKeyboard getKeyboard(KeyboardId id) { 302 SoftReference<LatinKeyboard> ref = mKeyboards.get(id); 303 LatinKeyboard keyboard = (ref == null) ? null : ref.get(); 304 if (keyboard == null) { 305 Resources orig = mInputMethodService.getResources(); 306 Configuration conf = orig.getConfiguration(); 307 Locale saveLocale = conf.locale; 308 conf.locale = mInputLocale; 309 orig.updateConfiguration(conf, null); 310 keyboard = new LatinKeyboard(mInputMethodService, id.mXml, id.mKeyboardMode); 311 keyboard.setVoiceMode(hasVoiceButton(id.mXml == R.xml.kbd_symbols 312 || id.mXml == R.xml.kbd_symbols_black), mHasVoice); 313 keyboard.setLanguageSwitcher(mLanguageSwitcher, mIsAutoCompletionActive, isBlackSym()); 314 315 if (id.mEnableShiftLock) { 316 keyboard.enableShiftLock(); 317 } 318 mKeyboards.put(id, new SoftReference<LatinKeyboard>(keyboard)); 319 320 conf.locale = saveLocale; 321 orig.updateConfiguration(conf, null); 322 } 323 return keyboard; 324 } 325 getKeyboardId(int mode, int imeOptions, boolean isSymbols)326 private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) { 327 boolean hasVoice = hasVoiceButton(isSymbols); 328 int charColorId = getCharColorId(); 329 // TODO: generalize for any KeyboardId 330 int keyboardRowsResId = KBD_QWERTY[charColorId]; 331 if (isSymbols) { 332 if (mode == MODE_PHONE) { 333 return new KeyboardId(KBD_PHONE_SYMBOLS[charColorId], hasVoice); 334 } else { 335 return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ? 336 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 337 false, hasVoice); 338 } 339 } 340 switch (mode) { 341 case MODE_NONE: 342 LatinImeLogger.logOnWarning( 343 "getKeyboardId:" + mode + "," + imeOptions + "," + isSymbols); 344 /* fall through */ 345 case MODE_TEXT: 346 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 347 KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY : KEYBOARDMODE_NORMAL, 348 true, hasVoice); 349 case MODE_SYMBOLS: 350 return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ? 351 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 352 false, hasVoice); 353 case MODE_PHONE: 354 return new KeyboardId(KBD_PHONE[charColorId], hasVoice); 355 case MODE_URL: 356 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 357 KEYBOARDMODE_URL_WITH_SETTINGS_KEY : KEYBOARDMODE_URL, true, hasVoice); 358 case MODE_EMAIL: 359 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 360 KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY : KEYBOARDMODE_EMAIL, true, hasVoice); 361 case MODE_IM: 362 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 363 KEYBOARDMODE_IM_WITH_SETTINGS_KEY : KEYBOARDMODE_IM, true, hasVoice); 364 case MODE_WEB: 365 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 366 KEYBOARDMODE_WEB_WITH_SETTINGS_KEY : KEYBOARDMODE_WEB, true, hasVoice); 367 } 368 return null; 369 } 370 getKeyboardMode()371 public int getKeyboardMode() { 372 return mMode; 373 } 374 isAlphabetMode()375 public boolean isAlphabetMode() { 376 if (mCurrentId == null) { 377 return false; 378 } 379 int currentMode = mCurrentId.mKeyboardMode; 380 for (Integer mode : ALPHABET_MODES) { 381 if (currentMode == mode) { 382 return true; 383 } 384 } 385 return false; 386 } 387 setShifted(boolean shifted)388 public void setShifted(boolean shifted) { 389 if (mInputView != null) { 390 mInputView.setShifted(shifted); 391 } 392 } 393 setShiftLocked(boolean shiftLocked)394 public void setShiftLocked(boolean shiftLocked) { 395 if (mInputView != null) { 396 mInputView.setShiftLocked(shiftLocked); 397 } 398 } 399 toggleShift()400 public void toggleShift() { 401 if (isAlphabetMode()) 402 return; 403 if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) { 404 LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId); 405 mCurrentId = mSymbolsShiftedId; 406 mInputView.setKeyboard(symbolsShiftedKeyboard); 407 // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To 408 // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true). 409 // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is 410 // called. 411 symbolsShiftedKeyboard.enableShiftLock(); 412 symbolsShiftedKeyboard.setShiftLocked(true); 413 symbolsShiftedKeyboard.setImeOptions(mInputMethodService.getResources(), 414 mMode, mImeOptions); 415 } else { 416 LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId); 417 mCurrentId = mSymbolsId; 418 mInputView.setKeyboard(symbolsKeyboard); 419 // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the 420 // indicator, we need to call enableShiftLock() and setShiftLocked(false). 421 symbolsKeyboard.enableShiftLock(); 422 symbolsKeyboard.setShifted(false); 423 symbolsKeyboard.setImeOptions(mInputMethodService.getResources(), mMode, mImeOptions); 424 } 425 } 426 onCancelInput()427 public void onCancelInput() { 428 // Snap back to the previous keyboard mode if the user cancels sliding input. 429 if (mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY && getPointerCount() == 1) 430 mInputMethodService.changeKeyboardMode(); 431 } 432 toggleSymbols()433 public void toggleSymbols() { 434 setKeyboardMode(mMode, mImeOptions, mHasVoice, !mIsSymbols); 435 if (mIsSymbols && !mPreferSymbols) { 436 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; 437 } else { 438 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; 439 } 440 } 441 hasDistinctMultitouch()442 public boolean hasDistinctMultitouch() { 443 return mInputView != null && mInputView.hasDistinctMultitouch(); 444 } 445 setAutoModeSwitchStateMomentary()446 public void setAutoModeSwitchStateMomentary() { 447 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_MOMENTARY; 448 } 449 isInMomentaryAutoModeSwitchState()450 public boolean isInMomentaryAutoModeSwitchState() { 451 return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_MOMENTARY; 452 } 453 isInChordingAutoModeSwitchState()454 public boolean isInChordingAutoModeSwitchState() { 455 return mAutoModeSwitchState == AUTO_MODE_SWITCH_STATE_CHORDING; 456 } 457 isVibrateAndSoundFeedbackRequired()458 public boolean isVibrateAndSoundFeedbackRequired() { 459 return mInputView != null && !mInputView.isInSlidingKeyInput(); 460 } 461 getPointerCount()462 private int getPointerCount() { 463 return mInputView == null ? 0 : mInputView.getPointerCount(); 464 } 465 466 /** 467 * Updates state machine to figure out when to automatically snap back to the previous mode. 468 */ onKey(int key)469 public void onKey(int key) { 470 // Switch back to alpha mode if user types one or more non-space/enter characters 471 // followed by a space/enter 472 switch (mAutoModeSwitchState) { 473 case AUTO_MODE_SWITCH_STATE_MOMENTARY: 474 // Only distinct multi touch devices can be in this state. 475 // On non-distinct multi touch devices, mode change key is handled by {@link onKey}, 476 // not by {@link onPress} and {@link onRelease}. So, on such devices, 477 // {@link mAutoModeSwitchState} starts from {@link AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN}, 478 // or {@link AUTO_MODE_SWITCH_STATE_ALPHA}, not from 479 // {@link AUTO_MODE_SWITCH_STATE_MOMENTARY}. 480 if (key == LatinKeyboard.KEYCODE_MODE_CHANGE) { 481 // Detected only the mode change key has been pressed, and then released. 482 if (mIsSymbols) { 483 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN; 484 } else { 485 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_ALPHA; 486 } 487 } else if (getPointerCount() == 1) { 488 // Snap back to the previous keyboard mode if the user pressed the mode change key 489 // and slid to other key, then released the finger. 490 // If the user cancels the sliding input, snapping back to the previous keyboard 491 // mode is handled by {@link #onCancelInput}. 492 mInputMethodService.changeKeyboardMode(); 493 } else { 494 // Chording input is being started. The keyboard mode will be snapped back to the 495 // previous mode in {@link onReleaseSymbol} when the mode change key is released. 496 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_CHORDING; 497 } 498 break; 499 case AUTO_MODE_SWITCH_STATE_SYMBOL_BEGIN: 500 if (key != LatinIME.KEYCODE_SPACE && key != LatinIME.KEYCODE_ENTER && key >= 0) { 501 mAutoModeSwitchState = AUTO_MODE_SWITCH_STATE_SYMBOL; 502 } 503 break; 504 case AUTO_MODE_SWITCH_STATE_SYMBOL: 505 // Snap back to alpha keyboard mode if user types one or more non-space/enter 506 // characters followed by a space/enter. 507 if (key == LatinIME.KEYCODE_ENTER || key == LatinIME.KEYCODE_SPACE) { 508 mInputMethodService.changeKeyboardMode(); 509 } 510 break; 511 } 512 } 513 getInputView()514 public LatinKeyboardView getInputView() { 515 return mInputView; 516 } 517 recreateInputView()518 public void recreateInputView() { 519 changeLatinKeyboardView(mLayoutId, true); 520 } 521 changeLatinKeyboardView(int newLayout, boolean forceReset)522 private void changeLatinKeyboardView(int newLayout, boolean forceReset) { 523 if (mLayoutId != newLayout || mInputView == null || forceReset) { 524 if (mInputView != null) { 525 mInputView.closing(); 526 } 527 if (THEMES.length <= newLayout) { 528 newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID); 529 } 530 531 LatinIMEUtil.GCUtils.getInstance().reset(); 532 boolean tryGC = true; 533 for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 534 try { 535 mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater( 536 ).inflate(THEMES[newLayout], null); 537 tryGC = false; 538 } catch (OutOfMemoryError e) { 539 tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait( 540 mLayoutId + "," + newLayout, e); 541 } catch (InflateException e) { 542 tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait( 543 mLayoutId + "," + newLayout, e); 544 } 545 } 546 mInputView.setOnKeyboardActionListener(mInputMethodService); 547 mLayoutId = newLayout; 548 } 549 mInputMethodService.mHandler.post(new Runnable() { 550 public void run() { 551 if (mInputView != null) { 552 mInputMethodService.setInputView(mInputView); 553 } 554 mInputMethodService.updateInputViewShown(); 555 }}); 556 } 557 onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)558 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 559 if (PREF_KEYBOARD_LAYOUT.equals(key)) { 560 changeLatinKeyboardView( 561 Integer.valueOf(sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)), false); 562 } else if (LatinIMESettings.PREF_SETTINGS_KEY.equals(key)) { 563 updateSettingsKeyState(sharedPreferences); 564 recreateInputView(); 565 } 566 } 567 isBlackSym()568 public boolean isBlackSym () { 569 if (mInputView != null && mInputView.getSymbolColorScheme() == 1) { 570 return true; 571 } 572 return false; 573 } 574 getCharColorId()575 private int getCharColorId () { 576 if (isBlackSym()) { 577 return CHAR_THEME_COLOR_BLACK; 578 } else { 579 return CHAR_THEME_COLOR_WHITE; 580 } 581 } 582 onAutoCompletionStateChanged(boolean isAutoCompletion)583 public void onAutoCompletionStateChanged(boolean isAutoCompletion) { 584 if (isAutoCompletion != mIsAutoCompletionActive) { 585 LatinKeyboardView keyboardView = getInputView(); 586 mIsAutoCompletionActive = isAutoCompletion; 587 keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard()) 588 .onAutoCompletionStateChanged(isAutoCompletion)); 589 } 590 } 591 updateSettingsKeyState(SharedPreferences prefs)592 private void updateSettingsKeyState(SharedPreferences prefs) { 593 Resources resources = mInputMethodService.getResources(); 594 final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY, 595 resources.getString(DEFAULT_SETTINGS_KEY_MODE)); 596 // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or 597 // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system 598 if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW)) 599 || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO)) 600 && LatinIMEUtil.hasMultipleEnabledIMEs(mInputMethodService))) { 601 mHasSettingsKey = true; 602 } else { 603 mHasSettingsKey = false; 604 } 605 } 606 } 607