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 static final int SYMBOLS_MODE_STATE_NONE = 0; 86 private static final int SYMBOLS_MODE_STATE_BEGIN = 1; 87 private static final int SYMBOLS_MODE_STATE_SYMBOL = 2; 88 89 private LatinKeyboardView mInputView; 90 private static final int[] ALPHABET_MODES = { 91 KEYBOARDMODE_NORMAL, 92 KEYBOARDMODE_URL, 93 KEYBOARDMODE_EMAIL, 94 KEYBOARDMODE_IM, 95 KEYBOARDMODE_WEB, 96 KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY, 97 KEYBOARDMODE_URL_WITH_SETTINGS_KEY, 98 KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY, 99 KEYBOARDMODE_IM_WITH_SETTINGS_KEY, 100 KEYBOARDMODE_WEB_WITH_SETTINGS_KEY }; 101 102 private final LatinIME mInputMethodService; 103 104 private KeyboardId mSymbolsId; 105 private KeyboardId mSymbolsShiftedId; 106 107 private KeyboardId mCurrentId; 108 private final HashMap<KeyboardId, SoftReference<LatinKeyboard>> mKeyboards; 109 110 private int mMode = MODE_NONE; /** One of the MODE_XXX values */ 111 private int mImeOptions; 112 private boolean mIsSymbols; 113 /** mIsAutoCompletionActive indicates that auto completed word will be input instead of 114 * what user actually typed. */ 115 private boolean mIsAutoCompletionActive; 116 private boolean mHasVoice; 117 private boolean mVoiceOnPrimary; 118 private boolean mPreferSymbols; 119 private int mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; 120 121 // Indicates whether or not we have the settings key 122 private boolean mHasSettingsKey; 123 private static final int SETTINGS_KEY_MODE_AUTO = R.string.settings_key_mode_auto; 124 private static final int SETTINGS_KEY_MODE_ALWAYS_SHOW = R.string.settings_key_mode_always_show; 125 // NOTE: No need to have SETTINGS_KEY_MODE_ALWAYS_HIDE here because it's not being referred to 126 // in the source code now. 127 // Default is SETTINGS_KEY_MODE_AUTO. 128 private static final int DEFAULT_SETTINGS_KEY_MODE = SETTINGS_KEY_MODE_AUTO; 129 130 private int mLastDisplayWidth; 131 private LanguageSwitcher mLanguageSwitcher; 132 private Locale mInputLocale; 133 134 private int mLayoutId; 135 136 public KeyboardSwitcher(LatinIME ims) { 137 mInputMethodService = ims; 138 139 final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ims); 140 mLayoutId = Integer.valueOf(prefs.getString(PREF_KEYBOARD_LAYOUT, DEFAULT_LAYOUT_ID)); 141 updateSettingsKeyState(prefs); 142 prefs.registerOnSharedPreferenceChangeListener(this); 143 144 mKeyboards = new HashMap<KeyboardId, SoftReference<LatinKeyboard>>(); 145 mSymbolsId = makeSymbolsId(false); 146 mSymbolsShiftedId = makeSymbolsShiftedId(false); 147 } 148 149 /** 150 * Sets the input locale, when there are multiple locales for input. 151 * If no locale switching is required, then the locale should be set to null. 152 * @param locale the current input locale, or null for default locale with no locale 153 * button. 154 */ 155 public void setLanguageSwitcher(LanguageSwitcher languageSwitcher) { 156 mLanguageSwitcher = languageSwitcher; 157 mInputLocale = mLanguageSwitcher.getInputLocale(); 158 } 159 160 private KeyboardId makeSymbolsId(boolean hasVoice) { 161 return new KeyboardId(KBD_SYMBOLS[getCharColorId()], mHasSettingsKey ? 162 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 163 false, hasVoice); 164 } 165 166 private KeyboardId makeSymbolsShiftedId(boolean hasVoice) { 167 return new KeyboardId(KBD_SYMBOLS_SHIFT[getCharColorId()], mHasSettingsKey ? 168 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 169 false, hasVoice); 170 } 171 172 public void makeKeyboards(boolean forceCreate) { 173 mSymbolsId = makeSymbolsId(mHasVoice && !mVoiceOnPrimary); 174 mSymbolsShiftedId = makeSymbolsShiftedId(mHasVoice && !mVoiceOnPrimary); 175 176 if (forceCreate) mKeyboards.clear(); 177 // Configuration change is coming after the keyboard gets recreated. So don't rely on that. 178 // If keyboards have already been made, check if we have a screen width change and 179 // create the keyboard layouts again at the correct orientation 180 int displayWidth = mInputMethodService.getMaxWidth(); 181 if (displayWidth == mLastDisplayWidth) return; 182 mLastDisplayWidth = displayWidth; 183 if (!forceCreate) mKeyboards.clear(); 184 } 185 186 /** 187 * Represents the parameters necessary to construct a new LatinKeyboard, 188 * which also serve as a unique identifier for each keyboard type. 189 */ 190 private static class KeyboardId { 191 // TODO: should have locale and portrait/landscape orientation? 192 public final int mXml; 193 public final int mKeyboardMode; /** A KEYBOARDMODE_XXX value */ 194 public final boolean mEnableShiftLock; 195 public final boolean mHasVoice; 196 197 private final int mHashCode; 198 199 public KeyboardId(int xml, int mode, boolean enableShiftLock, boolean hasVoice) { 200 this.mXml = xml; 201 this.mKeyboardMode = mode; 202 this.mEnableShiftLock = enableShiftLock; 203 this.mHasVoice = hasVoice; 204 205 this.mHashCode = Arrays.hashCode(new Object[] { 206 xml, mode, enableShiftLock, hasVoice 207 }); 208 } 209 210 public KeyboardId(int xml, boolean hasVoice) { 211 this(xml, 0, false, hasVoice); 212 } 213 214 @Override 215 public boolean equals(Object other) { 216 return other instanceof KeyboardId && equals((KeyboardId) other); 217 } 218 219 private boolean equals(KeyboardId other) { 220 return other.mXml == this.mXml 221 && other.mKeyboardMode == this.mKeyboardMode 222 && other.mEnableShiftLock == this.mEnableShiftLock 223 && other.mHasVoice == this.mHasVoice; 224 } 225 226 @Override 227 public int hashCode() { 228 return mHashCode; 229 } 230 } 231 232 public void setVoiceMode(boolean enableVoice, boolean voiceOnPrimary) { 233 if (enableVoice != mHasVoice || voiceOnPrimary != mVoiceOnPrimary) { 234 mKeyboards.clear(); 235 } 236 mHasVoice = enableVoice; 237 mVoiceOnPrimary = voiceOnPrimary; 238 setKeyboardMode(mMode, mImeOptions, mHasVoice, mIsSymbols); 239 } 240 241 private boolean hasVoiceButton(boolean isSymbols) { 242 return mHasVoice && (isSymbols != mVoiceOnPrimary); 243 } 244 245 public void setKeyboardMode(int mode, int imeOptions, boolean enableVoice) { 246 mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; 247 mPreferSymbols = mode == MODE_SYMBOLS; 248 if (mode == MODE_SYMBOLS) { 249 mode = MODE_TEXT; 250 } 251 try { 252 setKeyboardMode(mode, imeOptions, enableVoice, mPreferSymbols); 253 } catch (RuntimeException e) { 254 LatinImeLogger.logOnException(mode + "," + imeOptions + "," + mPreferSymbols, e); 255 } 256 } 257 258 private void setKeyboardMode(int mode, int imeOptions, boolean enableVoice, boolean isSymbols) { 259 if (mInputView == null) return; 260 mMode = mode; 261 mImeOptions = imeOptions; 262 if (enableVoice != mHasVoice) { 263 // TODO clean up this unnecessary recursive call. 264 setVoiceMode(enableVoice, mVoiceOnPrimary); 265 } 266 mIsSymbols = isSymbols; 267 268 mInputView.setPreviewEnabled(mInputMethodService.getPopupOn()); 269 KeyboardId id = getKeyboardId(mode, imeOptions, isSymbols); 270 LatinKeyboard keyboard = null; 271 keyboard = getKeyboard(id); 272 273 if (mode == MODE_PHONE) { 274 mInputView.setPhoneKeyboard(keyboard); 275 } 276 277 mCurrentId = id; 278 mInputView.setKeyboard(keyboard); 279 keyboard.setShifted(false); 280 keyboard.setShiftLocked(keyboard.isShiftLocked()); 281 keyboard.setImeOptions(mInputMethodService.getResources(), mMode, imeOptions); 282 keyboard.setColorOfSymbolIcons(mIsAutoCompletionActive, isBlackSym()); 283 // Update the settings key state because number of enabled IMEs could have been changed 284 updateSettingsKeyState(PreferenceManager.getDefaultSharedPreferences(mInputMethodService)); 285 } 286 287 private LatinKeyboard getKeyboard(KeyboardId id) { 288 SoftReference<LatinKeyboard> ref = mKeyboards.get(id); 289 LatinKeyboard keyboard = (ref == null) ? null : ref.get(); 290 if (keyboard == null) { 291 Resources orig = mInputMethodService.getResources(); 292 Configuration conf = orig.getConfiguration(); 293 Locale saveLocale = conf.locale; 294 conf.locale = mInputLocale; 295 orig.updateConfiguration(conf, null); 296 keyboard = new LatinKeyboard(mInputMethodService, id.mXml, id.mKeyboardMode); 297 keyboard.setVoiceMode(hasVoiceButton(id.mXml == R.xml.kbd_symbols 298 || id.mXml == R.xml.kbd_symbols_black), mHasVoice); 299 keyboard.setLanguageSwitcher(mLanguageSwitcher, mIsAutoCompletionActive, isBlackSym()); 300 301 if (id.mEnableShiftLock) { 302 keyboard.enableShiftLock(); 303 } 304 mKeyboards.put(id, new SoftReference<LatinKeyboard>(keyboard)); 305 306 conf.locale = saveLocale; 307 orig.updateConfiguration(conf, null); 308 } 309 return keyboard; 310 } 311 312 private KeyboardId getKeyboardId(int mode, int imeOptions, boolean isSymbols) { 313 boolean hasVoice = hasVoiceButton(isSymbols); 314 int charColorId = getCharColorId(); 315 // TODO: generalize for any KeyboardId 316 int keyboardRowsResId = KBD_QWERTY[charColorId]; 317 if (isSymbols) { 318 if (mode == MODE_PHONE) { 319 return new KeyboardId(KBD_PHONE_SYMBOLS[charColorId], hasVoice); 320 } else { 321 return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ? 322 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 323 false, hasVoice); 324 } 325 } 326 switch (mode) { 327 case MODE_NONE: 328 LatinImeLogger.logOnWarning( 329 "getKeyboardId:" + mode + "," + imeOptions + "," + isSymbols); 330 /* fall through */ 331 case MODE_TEXT: 332 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 333 KEYBOARDMODE_NORMAL_WITH_SETTINGS_KEY : KEYBOARDMODE_NORMAL, 334 true, hasVoice); 335 case MODE_SYMBOLS: 336 return new KeyboardId(KBD_SYMBOLS[charColorId], mHasSettingsKey ? 337 KEYBOARDMODE_SYMBOLS_WITH_SETTINGS_KEY : KEYBOARDMODE_SYMBOLS, 338 false, hasVoice); 339 case MODE_PHONE: 340 return new KeyboardId(KBD_PHONE[charColorId], hasVoice); 341 case MODE_URL: 342 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 343 KEYBOARDMODE_URL_WITH_SETTINGS_KEY : KEYBOARDMODE_URL, true, hasVoice); 344 case MODE_EMAIL: 345 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 346 KEYBOARDMODE_EMAIL_WITH_SETTINGS_KEY : KEYBOARDMODE_EMAIL, true, hasVoice); 347 case MODE_IM: 348 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 349 KEYBOARDMODE_IM_WITH_SETTINGS_KEY : KEYBOARDMODE_IM, true, hasVoice); 350 case MODE_WEB: 351 return new KeyboardId(keyboardRowsResId, mHasSettingsKey ? 352 KEYBOARDMODE_WEB_WITH_SETTINGS_KEY : KEYBOARDMODE_WEB, true, hasVoice); 353 } 354 return null; 355 } 356 357 public int getKeyboardMode() { 358 return mMode; 359 } 360 361 public boolean isAlphabetMode() { 362 if (mCurrentId == null) { 363 return false; 364 } 365 int currentMode = mCurrentId.mKeyboardMode; 366 for (Integer mode : ALPHABET_MODES) { 367 if (currentMode == mode) { 368 return true; 369 } 370 } 371 return false; 372 } 373 374 public void setShifted(boolean shifted) { 375 if (mInputView != null) { 376 mInputView.setShifted(shifted); 377 } 378 } 379 380 public void setShiftLocked(boolean shiftLocked) { 381 if (mInputView != null) { 382 mInputView.setShiftLocked(shiftLocked); 383 } 384 } 385 386 public void toggleShift() { 387 if (isAlphabetMode()) 388 return; 389 if (mCurrentId.equals(mSymbolsId) || !mCurrentId.equals(mSymbolsShiftedId)) { 390 LatinKeyboard symbolsShiftedKeyboard = getKeyboard(mSymbolsShiftedId); 391 mCurrentId = mSymbolsShiftedId; 392 mInputView.setKeyboard(symbolsShiftedKeyboard); 393 // Symbol shifted keyboard has an ALT key that has a caps lock style indicator. To 394 // enable the indicator, we need to call enableShiftLock() and setShiftLocked(true). 395 // Thus we can keep the ALT key's Key.on value true while LatinKey.onRelease() is 396 // called. 397 symbolsShiftedKeyboard.enableShiftLock(); 398 symbolsShiftedKeyboard.setShiftLocked(true); 399 symbolsShiftedKeyboard.setImeOptions(mInputMethodService.getResources(), 400 mMode, mImeOptions); 401 } else { 402 LatinKeyboard symbolsKeyboard = getKeyboard(mSymbolsId); 403 mCurrentId = mSymbolsId; 404 mInputView.setKeyboard(symbolsKeyboard); 405 // Symbol keyboard has an ALT key that has a caps lock style indicator. To disable the 406 // indicator, we need to call enableShiftLock() and setShiftLocked(false). 407 symbolsKeyboard.enableShiftLock(); 408 symbolsKeyboard.setShifted(false); 409 symbolsKeyboard.setImeOptions(mInputMethodService.getResources(), mMode, mImeOptions); 410 } 411 } 412 413 public void toggleSymbols() { 414 setKeyboardMode(mMode, mImeOptions, mHasVoice, !mIsSymbols); 415 if (mIsSymbols && !mPreferSymbols) { 416 mSymbolsModeState = SYMBOLS_MODE_STATE_BEGIN; 417 } else { 418 mSymbolsModeState = SYMBOLS_MODE_STATE_NONE; 419 } 420 } 421 422 public boolean hasDistinctMultitouch() { 423 return mInputView != null && mInputView.hasDistinctMultitouch(); 424 } 425 426 /** 427 * Updates state machine to figure out when to automatically switch back to alpha mode. 428 * Returns true if the keyboard needs to switch back 429 */ 430 public boolean onKey(int key) { 431 // Switch back to alpha mode if user types one or more non-space/enter characters 432 // followed by a space/enter 433 switch (mSymbolsModeState) { 434 case SYMBOLS_MODE_STATE_BEGIN: 435 if (key != LatinIME.KEYCODE_SPACE && key != LatinIME.KEYCODE_ENTER && key > 0) { 436 mSymbolsModeState = SYMBOLS_MODE_STATE_SYMBOL; 437 } 438 break; 439 case SYMBOLS_MODE_STATE_SYMBOL: 440 if (key == LatinIME.KEYCODE_ENTER || key == LatinIME.KEYCODE_SPACE) return true; 441 break; 442 } 443 return false; 444 } 445 446 public LatinKeyboardView getInputView() { 447 return mInputView; 448 } 449 450 public void recreateInputView() { 451 changeLatinKeyboardView(mLayoutId, true); 452 } 453 454 private void changeLatinKeyboardView(int newLayout, boolean forceReset) { 455 if (mLayoutId != newLayout || mInputView == null || forceReset) { 456 if (mInputView != null) { 457 mInputView.closing(); 458 } 459 if (THEMES.length <= newLayout) { 460 newLayout = Integer.valueOf(DEFAULT_LAYOUT_ID); 461 } 462 463 LatinIMEUtil.GCUtils.getInstance().reset(); 464 boolean tryGC = true; 465 for (int i = 0; i < LatinIMEUtil.GCUtils.GC_TRY_LOOP_MAX && tryGC; ++i) { 466 try { 467 mInputView = (LatinKeyboardView) mInputMethodService.getLayoutInflater( 468 ).inflate(THEMES[newLayout], null); 469 tryGC = false; 470 } catch (OutOfMemoryError e) { 471 tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait( 472 mLayoutId + "," + newLayout, e); 473 } catch (InflateException e) { 474 tryGC = LatinIMEUtil.GCUtils.getInstance().tryGCOrWait( 475 mLayoutId + "," + newLayout, e); 476 } 477 } 478 mInputView.setOnKeyboardActionListener(mInputMethodService); 479 mLayoutId = newLayout; 480 } 481 mInputMethodService.mHandler.post(new Runnable() { 482 public void run() { 483 if (mInputView != null) { 484 mInputMethodService.setInputView(mInputView); 485 } 486 mInputMethodService.updateInputViewShown(); 487 }}); 488 } 489 490 public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { 491 if (PREF_KEYBOARD_LAYOUT.equals(key)) { 492 changeLatinKeyboardView( 493 Integer.valueOf(sharedPreferences.getString(key, DEFAULT_LAYOUT_ID)), false); 494 } else if (LatinIMESettings.PREF_SETTINGS_KEY.equals(key)) { 495 updateSettingsKeyState(sharedPreferences); 496 recreateInputView(); 497 } 498 } 499 500 public boolean isBlackSym () { 501 if (mInputView != null && mInputView.getSymbolColorScheme() == 1) { 502 return true; 503 } 504 return false; 505 } 506 507 private int getCharColorId () { 508 if (isBlackSym()) { 509 return CHAR_THEME_COLOR_BLACK; 510 } else { 511 return CHAR_THEME_COLOR_WHITE; 512 } 513 } 514 515 public void onAutoCompletionStateChanged(boolean isAutoCompletion) { 516 if (isAutoCompletion != mIsAutoCompletionActive) { 517 LatinKeyboardView keyboardView = getInputView(); 518 mIsAutoCompletionActive = isAutoCompletion; 519 keyboardView.invalidateKey(((LatinKeyboard) keyboardView.getKeyboard()) 520 .onAutoCompletionStateChanged(isAutoCompletion)); 521 } 522 } 523 524 private void updateSettingsKeyState(SharedPreferences prefs) { 525 Resources resources = mInputMethodService.getResources(); 526 final String settingsKeyMode = prefs.getString(LatinIMESettings.PREF_SETTINGS_KEY, 527 resources.getString(DEFAULT_SETTINGS_KEY_MODE)); 528 // We show the settings key when 1) SETTINGS_KEY_MODE_ALWAYS_SHOW or 529 // 2) SETTINGS_KEY_MODE_AUTO and there are two or more enabled IMEs on the system 530 if (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_ALWAYS_SHOW)) 531 || (settingsKeyMode.equals(resources.getString(SETTINGS_KEY_MODE_AUTO)) 532 && LatinIMEUtil.hasMultipleEnabledIMEs(mInputMethodService))) { 533 mHasSettingsKey = true; 534 } else { 535 mHasSettingsKey = false; 536 } 537 } 538 } 539