KeyboardSwitcher.java revision 9502cc177cc53678c9ddcc01d4d046f69220e13b
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 17package com.android.inputmethod.keyboard; 18 19import com.android.inputmethod.latin.LatinIME; 20import com.android.inputmethod.latin.Settings; 21import com.android.inputmethod.latin.Utils; 22import com.android.inputmethod.latin.LatinImeLogger; 23import com.android.inputmethod.latin.R; 24import com.android.inputmethod.latin.SubtypeSwitcher; 25 26import android.content.Context; 27import android.content.SharedPreferences; 28import android.content.res.Resources; 29import android.util.Log; 30import android.view.InflateException; 31import android.view.inputmethod.InputMethodManager; 32 33import java.lang.ref.SoftReference; 34import java.util.HashMap; 35import java.util.Locale; 36 37public class KeyboardSwitcher implements SharedPreferences.OnSharedPreferenceChangeListener { 38 private static final String TAG = "KeyboardSwitcher"; 39 private static final boolean DEBUG = false; 40 public static final boolean DEBUG_STATE = false; 41 42 // Changing DEFAULT_LAYOUT_ID also requires prefs_for_debug.xml to be matched with. 43 public static final String DEFAULT_LAYOUT_ID = "5"; 44 public static final String PREF_KEYBOARD_LAYOUT = "pref_keyboard_layout_20100902"; 45 private static final int[] THEMES = new int [] { 46 R.layout.input_basic, 47 R.layout.input_basic_highcontrast, 48 R.layout.input_stone_normal, 49 R.layout.input_stone_bold, 50 R.layout.input_gingerbread, 51 R.layout.input_honeycomb, // DEFAULT_LAYOUT_ID 52 }; 53 54 private static final int SYMBOLS_MODE_STATE_NONE = 0; 55 private static final int SYMBOLS_MODE_STATE_BEGIN = 1; 56 private static final int SYMBOLS_MODE_STATE_SYMBOL = 2; 57 58 private SubtypeSwitcher mSubtypeSwitcher; 59 private SharedPreferences mPrefs; 60 61 private LatinKeyboardView mInputView; 62 private LatinIME mInputMethodService; 63 64 private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); 65 private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); 66 67 private KeyboardId mSymbolsId; 68 private KeyboardId mSymbolsShiftedId; 69 70 private KeyboardId mCurrentId; 71 private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboardCache = 72 new HashMap<KeyboardId, SoftReference<LatinKeyboard>>(); 73 74 private int mMode = KeyboardId.MODE_TEXT; /* default value */ 75 private int mImeOptions; 76 private boolean mIsSymbols; 77 /** mIsAutoCompletionActive indicates that auto completed word will be input instead of 78 * what user actually typed. */ 79 private boolean mIsAutoCompletionActive; 80 private boolean mVoiceKeyEnabled; 81 private boolean mVoiceButtonOnPrimary; 82 private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; 83 84 // Indicates whether or not we have the settings key 85 private boolean mHasSettingsKey; 86 private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto; 87 private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW = 88 R.string.settings_key_mode_always_show; 89 // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to 90 // in the source code now. 91 // Default is SETTINGS_KEY_MODE_AUTO. 92 private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO; 93 94 private int mLayoutId; 95 96 private static final KeyboardSwitcher sInstance = new KeyboardSwitcher(); 97 98 public static KeyboardSwitcher getInstance() { 99 return sInstance; 100 } 101 102 private KeyboardSwitcher() { 103 } 104 105 public static void init(LatinIME ims, SharedPreferences prefs) { 106 sInstance.mInputMethodService = ims; 107 sInstance.mPrefs = prefs; 108 sInstance.mSubtypeSwitcher = SubtypeSwitcher.getInstance(); 109 110 sInstance.mLayoutId = Integer.valueOf( 111 prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID)); 112 prefs.registerOnSharedPreferenceChangeListener(sInstance); 113 } 114 115 private void makeSymbolsKeyboardIds() { 116 final Locale locale = mSubtypeSwitcher.getInputLocale(); 117 final int orientation = mInputMethodService.getResources().getConfiguration().orientation; 118 final int mode = mMode; 119 final int colorScheme = getColorScheme(); 120 final boolean hasSettingsKey = mHasSettingsKey; 121 final boolean voiceKeyEnabled = mVoiceKeyEnabled; 122 final boolean hasVoiceKey = voiceKeyEnabled && !mVoiceButtonOnPrimary; 123 final int imeOptions = mImeOptions; 124 // Note: This comment is only applied for phone number keyboard layout. 125 // On non-xlarge device, "@integer/key_switch_alpha_symbol" key code is used to switch 126 // between "phone keyboard" and "phone symbols keyboard". But on xlarge device, 127 // "@integer/key_shift" key code is used for that purpose in order to properly display 128 // "more" and "locked more" key labels. To achieve these behavior, we should initialize 129 // mSymbolsId and mSymbolsShiftedId to "phone keyboard" and "phone symbols keyboard" 130 // respectively here for xlarge device's layout switching. 131 mSymbolsId = new KeyboardId(locale, orientation, mode, 132 mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone : R.xml.kbd_symbols, 133 colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true); 134 mSymbolsShiftedId = new KeyboardId(locale, orientation, mode, 135 mode == KeyboardId.MODE_PHONE ? R.xml.kbd_phone_symbols : R.xml.kbd_symbols_shift, 136 colorScheme, hasSettingsKey, voiceKeyEnabled, hasVoiceKey, imeOptions, true); 137 } 138 139 private boolean hasVoiceKey(boolean isSymbols) { 140 return mVoiceKeyEnabled && (isSymbols != mVoiceButtonOnPrimary); 141 } 142 143 public void loadKeyboard(int mode, int imeOptions, boolean voiceKeyEnabled, 144 boolean voiceButtonOnPrimary) { 145 mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; 146 try { 147 loadKeyboardInternal(mode, imeOptions, voiceKeyEnabled, voiceButtonOnPrimary, 148 false); 149 } catch (RuntimeException e) { 150 Log.w(TAG, e); 151 LatinImeLogger.logOnException(mode + "," + imeOptions, e); 152 } 153 } 154 155 private void loadKeyboardInternal(int mode, int imeOptions, boolean voiceButtonEnabled, 156 boolean voiceButtonOnPrimary, boolean isSymbols) { 157 if (mInputView == null) return; 158 mInputView.setPreviewEnabled(mInputMethodService.getPopupOn()); 159 160 mMode = mode; 161 mImeOptions = imeOptions; 162 mVoiceKeyEnabled = voiceButtonEnabled; 163 mVoiceButtonOnPrimary = voiceButtonOnPrimary; 164 mIsSymbols = isSymbols; 165 // Update the settings key state because number of enabled IMEs could have been changed 166 mHasSettingsKey = getSettingsKeyMode(mPrefs, mInputMethodService); 167 makeSymbolsKeyboardIds(); 168 169 KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols); 170 LatinKeyboard keyboard = getKeyboard(id); 171 172 mCurrentId = id; 173 mInputView.setKeyboard(keyboard); 174 } 175 176 private LatinKeyboard getKeyboard(KeyboardId id) { 177 final SoftReference<LatinKeyboard> ref = mKeyboardCache.get(id); 178 LatinKeyboard keyboard = (ref == null) ? null : ref.get(); 179 if (keyboard == null) { 180 final Locale savedLocale = mSubtypeSwitcher.changeSystemLocale( 181 mSubtypeSwitcher.getInputLocale()); 182 183 keyboard = new LatinKeyboard(mInputMethodService, id); 184 185 if (id.mEnableShiftLock) { 186 keyboard.enableShiftLock(); 187 } 188 189 mKeyboardCache.put(id, new SoftReference<LatinKeyboard>(keyboard)); 190 if (DEBUG) 191 Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": " 192 + ((ref == null) ? "LOAD" : "GCed") + " id=" + id); 193 194 mSubtypeSwitcher.changeSystemLocale(savedLocale); 195 } else if (DEBUG) { 196 Log.d(TAG, "keyboard cache size=" + mKeyboardCache.size() + ": HIT id=" + id); 197 } 198 199 keyboard.onAutoCompletionStateChanged(mIsAutoCompletionActive); 200 keyboard.setShifted(false); 201 return keyboard; 202 } 203 204 private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) { 205 final boolean hasVoiceKey = hasVoiceKey(isSymbols); 206 final int charColorId = getColorScheme(); 207 final int xmlId; 208 final boolean enableShiftLock; 209 210 if (isSymbols) { 211 if (mode == KeyboardId.MODE_PHONE) { 212 xmlId = R.xml.kbd_phone_symbols; 213 } else if (mode == KeyboardId.MODE_NUMBER) { 214 // Note: MODE_NUMBER keyboard layout has no "switch alpha symbol" key. 215 xmlId = R.xml.kbd_number; 216 } else { 217 xmlId = R.xml.kbd_symbols; 218 } 219 enableShiftLock = false; 220 } else { 221 if (mode == KeyboardId.MODE_PHONE) { 222 xmlId = R.xml.kbd_phone; 223 enableShiftLock = false; 224 } else if (mode == KeyboardId.MODE_NUMBER) { 225 xmlId = R.xml.kbd_number; 226 enableShiftLock = false; 227 } else { 228 xmlId = R.xml.kbd_qwerty; 229 enableShiftLock = true; 230 } 231 } 232 final int orientation = mInputMethodService.getResources().getConfiguration().orientation; 233 final Locale locale = mSubtypeSwitcher.getInputLocale(); 234 return new KeyboardId(locale, orientation, mode, xmlId, charColorId, 235 mHasSettingsKey, mVoiceKeyEnabled, hasVoiceKey, imeOptions, enableShiftLock); 236 } 237 238 public int getKeyboardMode() { 239 return mMode; 240 } 241 242 public boolean isAlphabetMode() { 243 return mCurrentId != null && mCurrentId.isAlphabetKeyboard(); 244 } 245 246 public boolean isInputViewShown() { 247 return mInputView != null && mInputView.isShown(); 248 } 249 250 public boolean isKeyboardAvailable() { 251 if (mInputView != null) 252 return mInputView.getLatinKeyboard() != null; 253 return false; 254 } 255 256 private LatinKeyboard getLatinKeyboard() { 257 if (mInputView != null) 258 return mInputView.getLatinKeyboard(); 259 return null; 260 } 261 262 public void setPreferredLetters(int[] frequencies) { 263 LatinKeyboard latinKeyboard = getLatinKeyboard(); 264 if (latinKeyboard != null) 265 latinKeyboard.setPreferredLetters(frequencies); 266 } 267 268 public void keyReleased() { 269 LatinKeyboard latinKeyboard = getLatinKeyboard(); 270 if (latinKeyboard != null) 271 latinKeyboard.keyReleased(); 272 } 273 274 public boolean isShiftedOrShiftLocked() { 275 LatinKeyboard latinKeyboard = getLatinKeyboard(); 276 if (latinKeyboard != null) 277 return latinKeyboard.isShiftedOrShiftLocked(); 278 return false; 279 } 280 281 public boolean isShiftLocked() { 282 LatinKeyboard latinKeyboard = getLatinKeyboard(); 283 if (latinKeyboard != null) 284 return latinKeyboard.isShiftLocked(); 285 return false; 286 } 287 288 public boolean isAutomaticTemporaryUpperCase() { 289 LatinKeyboard latinKeyboard = getLatinKeyboard(); 290 if (latinKeyboard != null) 291 return latinKeyboard.isAutomaticTemporaryUpperCase(); 292 return false; 293 } 294 295 public boolean isManualTemporaryUpperCase() { 296 LatinKeyboard latinKeyboard = getLatinKeyboard(); 297 if (latinKeyboard != null) 298 return latinKeyboard.isManualTemporaryUpperCase(); 299 return false; 300 } 301 302 private void setManualTemporaryUpperCase(boolean shifted) { 303 LatinKeyboard latinKeyboard = getLatinKeyboard(); 304 if (latinKeyboard != null) { 305 // On non-distinct multi touch panel device, we should also turn off the shift locked 306 // state when shift key is pressed to go to normal mode. 307 // On the other hand, on distinct multi touch panel device, turning off the shift locked 308 // state with shift key pressing is handled by onReleaseShift(). 309 if (!hasDistinctMultitouch() && !shifted && latinKeyboard.isShiftLocked()) { 310 latinKeyboard.setShiftLocked(false); 311 } 312 if (latinKeyboard.setShifted(shifted)) { 313 mInputView.invalidateAllKeys(); 314 } 315 } 316 } 317 318 private void setShiftLocked(boolean shiftLocked) { 319 LatinKeyboard latinKeyboard = getLatinKeyboard(); 320 if (latinKeyboard != null && latinKeyboard.setShiftLocked(shiftLocked)) { 321 mInputView.invalidateAllKeys(); 322 } 323 } 324 325 /** 326 * Toggle keyboard shift state triggered by user touch event. 327 */ 328 public void toggleShift() { 329 mInputMethodService.mHandler.cancelUpdateShiftState(); 330 if (DEBUG_STATE) 331 Log.d(TAG, "toggleShift:" 332 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 333 + " shiftKeyState=" + mShiftKeyState); 334 if (isAlphabetMode()) { 335 setManualTemporaryUpperCase(!isShiftedOrShiftLocked()); 336 } else { 337 toggleShiftInSymbol(); 338 } 339 } 340 341 public void toggleCapsLock() { 342 mInputMethodService.mHandler.cancelUpdateShiftState(); 343 if (DEBUG_STATE) 344 Log.d(TAG, "toggleCapsLock:" 345 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 346 + " shiftKeyState=" + mShiftKeyState); 347 if (isAlphabetMode()) { 348 if (isShiftLocked()) { 349 // Shift key is long pressed while caps lock state, we will toggle back to normal 350 // state. And mark as if shift key is released. 351 setShiftLocked(false); 352 mShiftKeyState.onRelease(); 353 } else { 354 setShiftLocked(true); 355 } 356 } 357 } 358 359 private void setAutomaticTemporaryUpperCase() { 360 LatinKeyboard latinKeyboard = getLatinKeyboard(); 361 if (latinKeyboard != null) { 362 latinKeyboard.setAutomaticTemporaryUpperCase(); 363 mInputView.invalidateAllKeys(); 364 } 365 } 366 367 /** 368 * Update keyboard shift state triggered by connected EditText status change. 369 */ 370 public void updateShiftState() { 371 final ShiftKeyState shiftKeyState = mShiftKeyState; 372 if (DEBUG_STATE) 373 Log.d(TAG, "updateShiftState:" 374 + " autoCaps=" + mInputMethodService.getCurrentAutoCapsState() 375 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 376 + " shiftKeyState=" + shiftKeyState); 377 if (isAlphabetMode()) { 378 if (!isShiftLocked() && !shiftKeyState.isIgnoring()) { 379 if (shiftKeyState.isReleasing() && mInputMethodService.getCurrentAutoCapsState()) { 380 // Only when shift key is releasing, automatic temporary upper case will be set. 381 setAutomaticTemporaryUpperCase(); 382 } else { 383 setManualTemporaryUpperCase(shiftKeyState.isMomentary()); 384 } 385 } 386 } else { 387 // In symbol keyboard mode, we should clear shift key state because only alphabet 388 // keyboard has shift key. 389 shiftKeyState.onRelease(); 390 } 391 } 392 393 public void changeKeyboardMode() { 394 if (DEBUG_STATE) 395 Log.d(TAG, "changeKeyboardMode:" 396 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 397 + " shiftKeyState=" + mShiftKeyState); 398 toggleKeyboardMode(); 399 if (isShiftLocked() && isAlphabetMode()) 400 setShiftLocked(true); 401 updateShiftState(); 402 } 403 404 public void onPressShift() { 405 if (!isKeyboardAvailable()) 406 return; 407 ShiftKeyState shiftKeyState = mShiftKeyState; 408 if (DEBUG_STATE) 409 Log.d(TAG, "onPressShift:" 410 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 411 + " shiftKeyState=" + shiftKeyState); 412 if (isAlphabetMode()) { 413 if (isShiftLocked()) { 414 // Shift key is pressed while caps lock state, we will treat this state as shifted 415 // caps lock state and mark as if shift key pressed while normal state. 416 shiftKeyState.onPress(); 417 setManualTemporaryUpperCase(true); 418 } else if (isAutomaticTemporaryUpperCase()) { 419 // Shift key is pressed while automatic temporary upper case, we have to move to 420 // manual temporary upper case. 421 shiftKeyState.onPress(); 422 setManualTemporaryUpperCase(true); 423 } else if (isShiftedOrShiftLocked()) { 424 // In manual upper case state, we just record shift key has been pressing while 425 // shifted state. 426 shiftKeyState.onPressOnShifted(); 427 } else { 428 // In base layout, chording or manual temporary upper case mode is started. 429 shiftKeyState.onPress(); 430 toggleShift(); 431 } 432 } else { 433 // In symbol mode, just toggle symbol and symbol more keyboard. 434 shiftKeyState.onPress(); 435 toggleShift(); 436 } 437 } 438 439 public void onReleaseShift() { 440 if (!isKeyboardAvailable()) 441 return; 442 ShiftKeyState shiftKeyState = mShiftKeyState; 443 if (DEBUG_STATE) 444 Log.d(TAG, "onReleaseShift:" 445 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 446 + " shiftKeyState=" + shiftKeyState); 447 if (isAlphabetMode()) { 448 if (shiftKeyState.isMomentary()) { 449 // After chording input while normal state. 450 toggleShift(); 451 } else if (isShiftLocked() && !shiftKeyState.isIgnoring()) { 452 // Shift has been pressed without chording while caps lock state. 453 toggleCapsLock(); 454 } else if (isShiftedOrShiftLocked() && shiftKeyState.isPressingOnShifted()) { 455 // Shift has been pressed without chording while shifted state. 456 toggleShift(); 457 } 458 } 459 shiftKeyState.onRelease(); 460 } 461 462 public void onPressSymbol() { 463 if (DEBUG_STATE) 464 Log.d(TAG, "onReleaseShift:" 465 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 466 + " symbolKeyState=" + mSymbolKeyState); 467 changeKeyboardMode(); 468 mSymbolKeyState.onPress(); 469 } 470 471 public void onReleaseSymbol() { 472 if (DEBUG_STATE) 473 Log.d(TAG, "onReleaseShift:" 474 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 475 + " symbolKeyState=" + mSymbolKeyState); 476 if (mSymbolKeyState.isMomentary()) 477 changeKeyboardMode(); 478 mSymbolKeyState.onRelease(); 479 } 480 481 public void onOtherKeyPressed() { 482 if (DEBUG_STATE) 483 Log.d(TAG, "onOtherKeyPressed:" 484 + " keyboard=" + getLatinKeyboard().getKeyboardShiftState() 485 + " shiftKeyState=" + mShiftKeyState 486 + " symbolKeyState=" + mSymbolKeyState); 487 mShiftKeyState.onOtherKeyPressed(); 488 mSymbolKeyState.onOtherKeyPressed(); 489 } 490 491 private void toggleShiftInSymbol() { 492 if (isAlphabetMode()) 493 return; 494 final LatinKeyboard keyboard; 495 if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) { 496 mCurrentId = mSymbolsShiftedId; 497 keyboard = getKeyboard(mCurrentId); 498 // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To 499 // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true). 500 // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is 501 // called. 502 keyboard.setShiftLocked(true); 503 } else { 504 mCurrentId = mSymbolsId; 505 keyboard = getKeyboard(mCurrentId); 506 // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the 507 // indicator, we need to call enableShiftLock() and setShiftLocked(false). 508 keyboard.setShifted(false); 509 } 510 mInputView.setKeyboard(keyboard); 511 } 512 513 private void toggleKeyboardMode() { 514 loadKeyboardInternal(mMode, mImeOptions, mVoiceKeyEnabled, mVoiceButtonOnPrimary, 515 !mIsSymbols); 516 if (mIsSymbols) { 517 mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN; 518 } else { 519 mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; 520 } 521 } 522 523 public boolean hasDistinctMultitouch() { 524 return mInputView != null && mInputView.hasDistinctMultitouch(); 525 } 526 527 /** 528 * Updates state machine to figure out when to automatically switch back to alpha mode. 529 */ 530 public void onKey(int key) { 531 // Switch back to alpha mode if user types one or more non-space/enter 532 // characters followed by a space/enter 533 switch (mSymbolsModeState) { 534 case SYMBOLS_MODE_STATE_BEGIN: 535 if (key != Keyboard.CODE_SPACE && key != Keyboard.CODE_ENTER && key > 0) { 536 mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL; 537 } 538 break; 539 case SYMBOLS_MODE_STATE_SYMBOL: 540 if (key == Keyboard.CODE_ENTER || key == Keyboard.CODE_SPACE) { 541 changeKeyboardMode(); 542 } 543 break; 544 } 545 } 546 547 public LatinKeyboardView getInputView() { 548 return mInputView; 549 } 550 551 public LatinKeyboardView onCreateInputView() { 552 createInputViewInternal(mLayoutId, true); 553 return mInputView; 554 } 555 556 private void createInputViewInternal(int newLayout, boolean forceReset) { 557 if (mLayoutId != newLayout || mInputView == null || forceReset) { 558 if (mInputView != null) { 559 mInputView.closing(); 560 } 561 if (THEMES.length <= newLayout) { 562 newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID); 563 } 564 565 Utils.GCUtils.getInstance().reset(); 566 boolean tryGC = true; 567 for (int i = 0; i < Utils.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 568 try { 569 mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater( 570 ).inflate(THEMES[newLayout], null); 571 tryGC = false; 572 } catch (OutOfMemoryError e) { 573 Log.w(TAG, "load keyboard failed: " + e); 574 tryGC = Utils.GCUtils.getInstance().tryGCOrWait( 575 mLayoutId + "," + newLayout, e); 576 } catch (InflateException e) { 577 Log.w(TAG, "load keyboard failed: " + e); 578 tryGC = Utils.GCUtils.getInstance().tryGCOrWait( 579 mLayoutId + "," + newLayout, e); 580 } 581 } 582 mInputView.setOnKeyboardActionListener(mInputMethodService); 583 mLayoutId = newLayout; 584 } 585 } 586 587 private void postSetInputView() { 588 mInputMethodService.mHandler.post(new Runnable() { 589 @Override 590 public void run() { 591 if (mInputView != null) { 592 mInputMethodService.setInputView(mInputView); 593 } 594 mInputMethodService.updateInputViewShown(); 595 } 596 }); 597 } 598 599 @Override 600 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 601 if (PREF_KEYBOARD_LAYOUT.equals(key)) { 602 final int layoutId = Integer.valueOf( 603 sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)); 604 createInputViewInternal(layoutId, false); 605 postSetInputView(); 606 } else if (Settings.PREF_SETTINGS_KEY.equals(key)) { 607 mHasSettingsKey = getSettingsKeyMode(sharedPreferences, mInputMethodService); 608 createInputViewInternal(mLayoutId, true); 609 postSetInputView(); 610 } 611 } 612 613 private int getColorScheme() { 614 return (mInputView != null) 615 ? mInputView.getColorScheme() : KeyboardView.COLOR_SCHEME_WHITE; 616 } 617 618 public void onAutoCompletionStateChanged(boolean isAutoCompletion) { 619 if (isAutoCompletion != mIsAutoCompletionActive) { 620 LatinKeyboardView keyboardView = getInputView(); 621 mIsAutoCompletionActive = isAutoCompletion; 622 keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard()) 623 .onAutoCompletionStateChanged(isAutoCompletion)); 624 } 625 } 626 627 private static boolean getSettingsKeyMode(SharedPreferences prefs, Context context) { 628 Resources resources = context.getResources(); 629 final boolean showSettingsKeyOption = resources.getBoolean( 630 R.bool.config_enable_show_settings_key_option); 631 if (showSettingsKeyOption) { 632 final String settingsKeyMode = prefs.getString(Settings.PREF_SETTINGS_KEY, 633 resources.getString(DEFAULT_SETTINGS_KEY_MODE)); 634 // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or 635 // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system 636 if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW)) 637 || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO)) 638 && Utils.hasMultipleEnabledIMEsOrSubtypes( 639 ((InputMethodManager) context.getSystemService( 640 Context.INPUT_METHOD_SERVICE))))) { 641 return true; 642 } 643 } 644 return false; 645 } 646} 647