SubtypeSwitcher.java revision c150acc7c85ff2f5eeb5bd2c6ff288df4e46a355
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of 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, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.inputmethod.latin; 18 19import com.android.inputmethod.compat.InputMethodInfoCompatWrapper; 20import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; 21import com.android.inputmethod.compat.InputMethodSubtypeCompatWrapper; 22import com.android.inputmethod.deprecated.VoiceProxy; 23import com.android.inputmethod.keyboard.KeyboardSwitcher; 24import com.android.inputmethod.keyboard.LatinKeyboard; 25 26import android.content.Context; 27import android.content.Intent; 28import android.content.SharedPreferences; 29import android.content.pm.PackageManager; 30import android.content.res.Configuration; 31import android.content.res.Resources; 32import android.graphics.drawable.Drawable; 33import android.net.ConnectivityManager; 34import android.net.NetworkInfo; 35import android.os.AsyncTask; 36import android.os.IBinder; 37import android.text.TextUtils; 38import android.util.Log; 39 40import java.util.ArrayList; 41import java.util.Arrays; 42import java.util.List; 43import java.util.Locale; 44import java.util.Map; 45 46public class SubtypeSwitcher { 47 private static boolean DBG = LatinImeLogger.sDBG; 48 private static final String TAG = SubtypeSwitcher.class.getSimpleName(); 49 50 private static final char LOCALE_SEPARATER = '_'; 51 private static final String KEYBOARD_MODE = "keyboard"; 52 private static final String VOICE_MODE = "voice"; 53 private static final String SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY = 54 "requireNetworkConnectivity"; 55 public static final String USE_SPACEBAR_LANGUAGE_SWITCH_KEY = "use_spacebar_language_switch"; 56 57 private final TextUtils.SimpleStringSplitter mLocaleSplitter = 58 new TextUtils.SimpleStringSplitter(LOCALE_SEPARATER); 59 60 private static final SubtypeSwitcher sInstance = new SubtypeSwitcher(); 61 private /* final */ LatinIME mService; 62 private /* final */ InputMethodManagerCompatWrapper mImm; 63 private /* final */ Resources mResources; 64 private /* final */ ConnectivityManager mConnectivityManager; 65 private /* final */ boolean mConfigUseSpacebarLanguageSwitcher; 66 private /* final */ SharedPreferences mPrefs; 67 private final ArrayList<InputMethodSubtypeCompatWrapper> 68 mEnabledKeyboardSubtypesOfCurrentInputMethod = 69 new ArrayList<InputMethodSubtypeCompatWrapper>(); 70 private final ArrayList<String> mEnabledLanguagesOfCurrentInputMethod = new ArrayList<String>(); 71 private final LanguageBarInfo mLanguageBarInfo = new LanguageBarInfo(); 72 73 /*-----------------------------------------------------------*/ 74 // Variants which should be changed only by reload functions. 75 private boolean mNeedsToDisplayLanguage; 76 private boolean mIsSystemLanguageSameAsInputLanguage; 77 private InputMethodInfoCompatWrapper mShortcutInputMethodInfo; 78 private InputMethodSubtypeCompatWrapper mShortcutSubtype; 79 private List<InputMethodSubtypeCompatWrapper> mAllEnabledSubtypesOfCurrentInputMethod; 80 private InputMethodSubtypeCompatWrapper mCurrentSubtype; 81 private Locale mSystemLocale; 82 private Locale mInputLocale; 83 private String mInputLocaleStr; 84 private String mInputMethodId; 85 private VoiceProxy.VoiceInputWrapper mVoiceInputWrapper; 86 /*-----------------------------------------------------------*/ 87 88 private boolean mIsNetworkConnected; 89 90 public static SubtypeSwitcher getInstance() { 91 return sInstance; 92 } 93 94 public static void init(LatinIME service, SharedPreferences prefs) { 95 SubtypeLocale.init(service); 96 sInstance.initialize(service, prefs); 97 sInstance.updateAllParameters(); 98 } 99 100 private SubtypeSwitcher() { 101 // Intentional empty constructor for singleton. 102 } 103 104 private void initialize(LatinIME service, SharedPreferences prefs) { 105 mService = service; 106 mResources = service.getResources(); 107 mImm = InputMethodManagerCompatWrapper.getInstance(service); 108 mConnectivityManager = (ConnectivityManager) service.getSystemService( 109 Context.CONNECTIVITY_SERVICE); 110 mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); 111 mEnabledLanguagesOfCurrentInputMethod.clear(); 112 mSystemLocale = null; 113 mInputLocale = null; 114 mInputLocaleStr = null; 115 mCurrentSubtype = null; 116 mAllEnabledSubtypesOfCurrentInputMethod = null; 117 mVoiceInputWrapper = null; 118 mPrefs = prefs; 119 120 final NetworkInfo info = mConnectivityManager.getActiveNetworkInfo(); 121 mIsNetworkConnected = (info != null && info.isConnected()); 122 mInputMethodId = Utils.getInputMethodId(mImm, service.getPackageName()); 123 } 124 125 // Update all parameters stored in SubtypeSwitcher. 126 // Only configuration changed event is allowed to call this because this is heavy. 127 private void updateAllParameters() { 128 mSystemLocale = mResources.getConfiguration().locale; 129 updateSubtype(mImm.getCurrentInputMethodSubtype()); 130 updateParametersOnStartInputView(); 131 } 132 133 // Update parameters which are changed outside LatinIME. This parameters affect UI so they 134 // should be updated every time onStartInputview. 135 public void updateParametersOnStartInputView() { 136 mConfigUseSpacebarLanguageSwitcher = mPrefs.getBoolean(USE_SPACEBAR_LANGUAGE_SWITCH_KEY, 137 mService.getResources().getBoolean( 138 R.bool.config_use_spacebar_language_switcher)); 139 updateEnabledSubtypes(); 140 updateShortcutIME(); 141 } 142 143 // Reload enabledSubtypes from the framework. 144 private void updateEnabledSubtypes() { 145 final String currentMode = getCurrentSubtypeMode(); 146 boolean foundCurrentSubtypeBecameDisabled = true; 147 mAllEnabledSubtypesOfCurrentInputMethod = mImm.getEnabledInputMethodSubtypeList( 148 null, true); 149 mEnabledLanguagesOfCurrentInputMethod.clear(); 150 mEnabledKeyboardSubtypesOfCurrentInputMethod.clear(); 151 for (InputMethodSubtypeCompatWrapper ims : mAllEnabledSubtypesOfCurrentInputMethod) { 152 final String locale = ims.getLocale(); 153 final String mode = ims.getMode(); 154 mLocaleSplitter.setString(locale); 155 if (mLocaleSplitter.hasNext()) { 156 mEnabledLanguagesOfCurrentInputMethod.add(mLocaleSplitter.next()); 157 } 158 if (locale.equals(mInputLocaleStr) && mode.equals(currentMode)) { 159 foundCurrentSubtypeBecameDisabled = false; 160 } 161 if (KEYBOARD_MODE.equals(ims.getMode())) { 162 mEnabledKeyboardSubtypesOfCurrentInputMethod.add(ims); 163 } 164 } 165 mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1 166 && mIsSystemLanguageSameAsInputLanguage); 167 if (foundCurrentSubtypeBecameDisabled) { 168 if (DBG) { 169 Log.w(TAG, "Current subtype: " + mInputLocaleStr + ", " + currentMode); 170 Log.w(TAG, "Last subtype was disabled. Update to the current one."); 171 } 172 updateSubtype(mImm.getCurrentInputMethodSubtype()); 173 } else { 174 // mLanguageBarInfo.update() will be called in updateSubtype so there is no need 175 // to call this in the if-clause above. 176 mLanguageBarInfo.update(); 177 } 178 } 179 180 private void updateShortcutIME() { 181 if (DBG) { 182 Log.d(TAG, "Update shortcut IME from : " 183 + (mShortcutInputMethodInfo == null 184 ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " 185 + (mShortcutSubtype == null ? "<null>" : (mShortcutSubtype.getLocale() 186 + ", " + mShortcutSubtype.getMode()))); 187 } 188 // TODO: Update an icon for shortcut IME 189 final Map<InputMethodInfoCompatWrapper, List<InputMethodSubtypeCompatWrapper>> shortcuts = 190 mImm.getShortcutInputMethodsAndSubtypes(); 191 for (InputMethodInfoCompatWrapper imi : shortcuts.keySet()) { 192 List<InputMethodSubtypeCompatWrapper> subtypes = shortcuts.get(imi); 193 // TODO: Returns the first found IMI for now. Should handle all shortcuts as 194 // appropriate. 195 mShortcutInputMethodInfo = imi; 196 // TODO: Pick up the first found subtype for now. Should handle all subtypes 197 // as appropriate. 198 mShortcutSubtype = subtypes.size() > 0 ? subtypes.get(0) : null; 199 break; 200 } 201 if (DBG) { 202 Log.d(TAG, "Update shortcut IME to : " 203 + (mShortcutInputMethodInfo == null 204 ? "<null>" : mShortcutInputMethodInfo.getId()) + ", " 205 + (mShortcutSubtype == null ? "<null>" : (mShortcutSubtype.getLocale() 206 + ", " + mShortcutSubtype.getMode()))); 207 } 208 } 209 210 // Update the current subtype. LatinIME.onCurrentInputMethodSubtypeChanged calls this function. 211 public void updateSubtype(InputMethodSubtypeCompatWrapper newSubtype) { 212 final String newLocale; 213 final String newMode; 214 final String oldMode = getCurrentSubtypeMode(); 215 if (newSubtype == null) { 216 // Normally, newSubtype shouldn't be null. But just in case newSubtype was null, 217 // fallback to the default locale. 218 Log.w(TAG, "Couldn't get the current subtype."); 219 newLocale = "en_US"; 220 newMode = KEYBOARD_MODE; 221 } else { 222 newLocale = newSubtype.getLocale(); 223 newMode = newSubtype.getMode(); 224 } 225 if (DBG) { 226 Log.w(TAG, "Update subtype to:" + newLocale + "," + newMode 227 + ", from: " + mInputLocaleStr + ", " + oldMode); 228 } 229 boolean languageChanged = false; 230 if (!newLocale.equals(mInputLocaleStr)) { 231 if (mInputLocaleStr != null) { 232 languageChanged = true; 233 } 234 updateInputLocale(newLocale); 235 } 236 boolean modeChanged = false; 237 if (!newMode.equals(oldMode)) { 238 if (oldMode != null) { 239 modeChanged = true; 240 } 241 } 242 mCurrentSubtype = newSubtype; 243 244 // If the old mode is voice input, we need to reset or cancel its status. 245 // We cancel its status when we change mode, while we reset otherwise. 246 if (isKeyboardMode()) { 247 if (modeChanged) { 248 if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) { 249 mVoiceInputWrapper.cancel(); 250 } 251 } 252 if (modeChanged || languageChanged) { 253 updateShortcutIME(); 254 mService.onRefreshKeyboard(); 255 } 256 } else if (isVoiceMode() && mVoiceInputWrapper != null) { 257 if (VOICE_MODE.equals(oldMode)) { 258 mVoiceInputWrapper.reset(); 259 } 260 // If needsToShowWarningDialog is true, voice input need to show warning before 261 // show recognition view. 262 if (languageChanged || modeChanged 263 || VoiceProxy.getInstance().needsToShowWarningDialog()) { 264 triggerVoiceIME(); 265 } 266 } else { 267 Log.w(TAG, "Unknown subtype mode: " + newMode); 268 if (VOICE_MODE.equals(oldMode) && mVoiceInputWrapper != null) { 269 // We need to reset the voice input to release the resources and to reset its status 270 // as it is not the current input mode. 271 mVoiceInputWrapper.reset(); 272 } 273 } 274 mLanguageBarInfo.update(); 275 } 276 277 // Update the current input locale from Locale string. 278 private void updateInputLocale(String inputLocaleStr) { 279 // example: inputLocaleStr = "en_US" "en" "" 280 // "en_US" --> language: en & country: US 281 // "en" --> language: en 282 // "" --> the system locale 283 if (!TextUtils.isEmpty(inputLocaleStr)) { 284 mInputLocale = Utils.constructLocaleFromString(inputLocaleStr); 285 mInputLocaleStr = inputLocaleStr; 286 } else { 287 mInputLocale = mSystemLocale; 288 String country = mSystemLocale.getCountry(); 289 mInputLocaleStr = mSystemLocale.getLanguage() 290 + (TextUtils.isEmpty(country) ? "" : "_" + mSystemLocale.getLanguage()); 291 } 292 mIsSystemLanguageSameAsInputLanguage = getSystemLocale().getLanguage().equalsIgnoreCase( 293 getInputLocale().getLanguage()); 294 mNeedsToDisplayLanguage = !(getEnabledKeyboardLocaleCount() <= 1 295 && mIsSystemLanguageSameAsInputLanguage); 296 } 297 298 //////////////////////////// 299 // Shortcut IME functions // 300 //////////////////////////// 301 302 public void switchToShortcutIME() { 303 if (mShortcutInputMethodInfo == null) { 304 return; 305 } 306 307 final String imiId = mShortcutInputMethodInfo.getId(); 308 final InputMethodSubtypeCompatWrapper subtype = mShortcutSubtype; 309 switchToTargetIME(imiId, subtype); 310 } 311 312 private void switchToTargetIME( 313 final String imiId, final InputMethodSubtypeCompatWrapper subtype) { 314 final IBinder token = mService.getWindow().getWindow().getAttributes().token; 315 if (token == null) { 316 return; 317 } 318 new AsyncTask<Void, Void, Void>() { 319 @Override 320 protected Void doInBackground(Void... params) { 321 mImm.setInputMethodAndSubtype(token, imiId, subtype); 322 return null; 323 } 324 325 @Override 326 protected void onPostExecute(Void result) { 327 // Calls in this method need to be done in the same thread as the thread which 328 // called switchToShortcutIME(). 329 330 // Notify an event that the current subtype was changed. This event will be 331 // handled if "onCurrentInputMethodSubtypeChanged" can't be implemented 332 // when the API level is 10 or previous. 333 mService.notifyOnCurrentInputMethodSubtypeChanged(subtype); 334 } 335 }.execute(); 336 } 337 338 public Drawable getShortcutIcon() { 339 return getSubtypeIcon(mShortcutInputMethodInfo, mShortcutSubtype); 340 } 341 342 private Drawable getSubtypeIcon( 343 InputMethodInfoCompatWrapper imi, InputMethodSubtypeCompatWrapper subtype) { 344 final PackageManager pm = mService.getPackageManager(); 345 if (imi != null) { 346 final String imiPackageName = imi.getPackageName(); 347 if (DBG) { 348 Log.d(TAG, "Update icons of IME: " + imiPackageName + "," 349 + subtype.getLocale() + "," + subtype.getMode()); 350 } 351 if (subtype != null) { 352 return pm.getDrawable(imiPackageName, subtype.getIconResId(), 353 imi.getServiceInfo().applicationInfo); 354 } else if (imi.getSubtypeCount() > 0 && imi.getSubtypeAt(0) != null) { 355 return pm.getDrawable(imiPackageName, 356 imi.getSubtypeAt(0).getIconResId(), 357 imi.getServiceInfo().applicationInfo); 358 } else { 359 try { 360 return pm.getApplicationInfo(imiPackageName, 0).loadIcon(pm); 361 } catch (PackageManager.NameNotFoundException e) { 362 Log.w(TAG, "IME can't be found: " + imiPackageName); 363 } 364 } 365 } 366 return null; 367 } 368 369 private static boolean contains(String[] hay, String needle) { 370 for (String element : hay) { 371 if (element.equals(needle)) 372 return true; 373 } 374 return false; 375 } 376 377 public boolean isShortcutImeEnabled() { 378 if (mShortcutInputMethodInfo == null) 379 return false; 380 if (mShortcutSubtype == null) 381 return true; 382 // For compatibility, if the shortcut subtype is dummy, we assume the shortcut IME 383 // (built-in voice dummy subtype) is available. 384 if (!mShortcutSubtype.hasOriginalObject()) return true; 385 final boolean allowsImplicitlySelectedSubtypes = true; 386 for (final InputMethodSubtypeCompatWrapper enabledSubtype : 387 mImm.getEnabledInputMethodSubtypeList( 388 mShortcutInputMethodInfo, allowsImplicitlySelectedSubtypes)) { 389 if (enabledSubtype.equals(mShortcutSubtype)) { 390 return true; 391 } 392 } 393 return false; 394 } 395 396 public boolean isShortcutImeReady() { 397 if (mShortcutInputMethodInfo == null) 398 return false; 399 if (mShortcutSubtype == null) 400 return true; 401 if (contains(mShortcutSubtype.getExtraValue().split(","), 402 SUBTYPE_EXTRAVALUE_REQUIRE_NETWORK_CONNECTIVITY)) { 403 return mIsNetworkConnected; 404 } 405 return true; 406 } 407 408 public void onNetworkStateChanged(Intent intent) { 409 final boolean noConnection = intent.getBooleanExtra( 410 ConnectivityManager.EXTRA_NO_CONNECTIVITY, false); 411 mIsNetworkConnected = !noConnection; 412 413 final KeyboardSwitcher switcher = KeyboardSwitcher.getInstance(); 414 final LatinKeyboard keyboard = switcher.getLatinKeyboard(); 415 if (keyboard != null) { 416 keyboard.updateShortcutKey(isShortcutImeReady(), switcher.getKeyboardView()); 417 } 418 } 419 420 ////////////////////////////////// 421 // Language Switching functions // 422 ////////////////////////////////// 423 424 public int getEnabledKeyboardLocaleCount() { 425 return mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); 426 } 427 428 public boolean useSpacebarLanguageSwitcher() { 429 return mConfigUseSpacebarLanguageSwitcher; 430 } 431 432 public boolean needsToDisplayLanguage() { 433 return mNeedsToDisplayLanguage; 434 } 435 436 public Locale getInputLocale() { 437 return mInputLocale; 438 } 439 440 public String getInputLocaleStr() { 441 return mInputLocaleStr; 442 } 443 444 public String[] getEnabledLanguages() { 445 int enabledLanguageCount = mEnabledLanguagesOfCurrentInputMethod.size(); 446 // Workaround for explicitly specifying the voice language 447 if (enabledLanguageCount == 1) { 448 mEnabledLanguagesOfCurrentInputMethod.add(mEnabledLanguagesOfCurrentInputMethod 449 .get(0)); 450 ++enabledLanguageCount; 451 } 452 return mEnabledLanguagesOfCurrentInputMethod.toArray(new String[enabledLanguageCount]); 453 } 454 455 public Locale getSystemLocale() { 456 return mSystemLocale; 457 } 458 459 public boolean isSystemLanguageSameAsInputLanguage() { 460 return mIsSystemLanguageSameAsInputLanguage; 461 } 462 463 public void onConfigurationChanged(Configuration conf) { 464 final Locale systemLocale = conf.locale; 465 // If system configuration was changed, update all parameters. 466 if (!TextUtils.equals(systemLocale.toString(), mSystemLocale.toString())) { 467 updateAllParameters(); 468 } 469 } 470 471 public boolean isKeyboardMode() { 472 return KEYBOARD_MODE.equals(getCurrentSubtypeMode()); 473 } 474 475 476 /////////////////////////// 477 // Voice Input functions // 478 /////////////////////////// 479 480 public boolean setVoiceInputWrapper(VoiceProxy.VoiceInputWrapper vi) { 481 if (mVoiceInputWrapper == null && vi != null) { 482 mVoiceInputWrapper = vi; 483 if (isVoiceMode()) { 484 if (DBG) { 485 Log.d(TAG, "Set and call voice input.: " + getInputLocaleStr()); 486 } 487 triggerVoiceIME(); 488 return true; 489 } 490 } 491 return false; 492 } 493 494 public boolean isVoiceMode() { 495 return null == mCurrentSubtype ? false : VOICE_MODE.equals(getCurrentSubtypeMode()); 496 } 497 498 public boolean isDummyVoiceMode() { 499 return mCurrentSubtype != null && mCurrentSubtype.getOriginalObject() == null 500 && VOICE_MODE.equals(getCurrentSubtypeMode()); 501 } 502 503 private void triggerVoiceIME() { 504 if (!mService.isInputViewShown()) return; 505 VoiceProxy.getInstance().startListening(false, 506 KeyboardSwitcher.getInstance().getKeyboardView().getWindowToken()); 507 } 508 509 ////////////////////////////////////// 510 // Spacebar Language Switch support // 511 ////////////////////////////////////// 512 513 private class LanguageBarInfo { 514 private int mCurrentKeyboardSubtypeIndex; 515 private InputMethodSubtypeCompatWrapper mNextKeyboardSubtype; 516 private InputMethodSubtypeCompatWrapper mPreviousKeyboardSubtype; 517 private String mNextLanguage; 518 private String mPreviousLanguage; 519 public LanguageBarInfo() { 520 update(); 521 } 522 523 private String getNextLanguage() { 524 return mNextLanguage; 525 } 526 527 private String getPreviousLanguage() { 528 return mPreviousLanguage; 529 } 530 531 public InputMethodSubtypeCompatWrapper getNextKeyboardSubtype() { 532 return mNextKeyboardSubtype; 533 } 534 535 public InputMethodSubtypeCompatWrapper getPreviousKeyboardSubtype() { 536 return mPreviousKeyboardSubtype; 537 } 538 539 public void update() { 540 if (!mConfigUseSpacebarLanguageSwitcher 541 || mEnabledKeyboardSubtypesOfCurrentInputMethod == null 542 || mEnabledKeyboardSubtypesOfCurrentInputMethod.size() == 0) return; 543 mCurrentKeyboardSubtypeIndex = getCurrentIndex(); 544 mNextKeyboardSubtype = getNextKeyboardSubtypeInternal(mCurrentKeyboardSubtypeIndex); 545 Locale locale = Utils.constructLocaleFromString(mNextKeyboardSubtype.getLocale()); 546 mNextLanguage = getFullDisplayName(locale, true); 547 mPreviousKeyboardSubtype = getPreviousKeyboardSubtypeInternal( 548 mCurrentKeyboardSubtypeIndex); 549 locale = Utils.constructLocaleFromString(mPreviousKeyboardSubtype.getLocale()); 550 mPreviousLanguage = getFullDisplayName(locale, true); 551 } 552 553 private int normalize(int index) { 554 final int N = mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); 555 final int ret = index % N; 556 return ret < 0 ? ret + N : ret; 557 } 558 559 private int getCurrentIndex() { 560 final int N = mEnabledKeyboardSubtypesOfCurrentInputMethod.size(); 561 for (int i = 0; i < N; ++i) { 562 if (mEnabledKeyboardSubtypesOfCurrentInputMethod.get(i).equals(mCurrentSubtype)) { 563 return i; 564 } 565 } 566 return 0; 567 } 568 569 private InputMethodSubtypeCompatWrapper getNextKeyboardSubtypeInternal(int index) { 570 return mEnabledKeyboardSubtypesOfCurrentInputMethod.get(normalize(index + 1)); 571 } 572 573 private InputMethodSubtypeCompatWrapper getPreviousKeyboardSubtypeInternal(int index) { 574 return mEnabledKeyboardSubtypesOfCurrentInputMethod.get(normalize(index - 1)); 575 } 576 } 577 578 public static String getFullDisplayName(Locale locale, boolean returnsNameInThisLocale) { 579 if (returnsNameInThisLocale) { 580 return toTitleCase(SubtypeLocale.getFullDisplayName(locale)); 581 } else { 582 return toTitleCase(locale.getDisplayName()); 583 } 584 } 585 586 public static String getDisplayLanguage(Locale locale) { 587 return toTitleCase(SubtypeLocale.getFullDisplayName(locale)); 588 } 589 590 public static String getMiddleDisplayLanguage(Locale locale) { 591 return toTitleCase((Utils.constructLocaleFromString( 592 locale.getLanguage()).getDisplayLanguage(locale))); 593 } 594 595 public static String getShortDisplayLanguage(Locale locale) { 596 return toTitleCase(locale.getLanguage()); 597 } 598 599 private static String toTitleCase(String s) { 600 if (s.length() == 0) { 601 return s; 602 } 603 return Character.toUpperCase(s.charAt(0)) + s.substring(1); 604 } 605 606 public String getInputLanguageName() { 607 return getDisplayLanguage(getInputLocale()); 608 } 609 610 public String getNextInputLanguageName() { 611 return mLanguageBarInfo.getNextLanguage(); 612 } 613 614 public String getPreviousInputLanguageName() { 615 return mLanguageBarInfo.getPreviousLanguage(); 616 } 617 618 ///////////////////////////// 619 // Other utility functions // 620 ///////////////////////////// 621 622 public String getCurrentSubtypeExtraValue() { 623 // If null, return what an empty ExtraValue would return : the empty string. 624 return null != mCurrentSubtype ? mCurrentSubtype.getExtraValue() : ""; 625 } 626 627 public boolean currentSubtypeContainsExtraValueKey(String key) { 628 // If null, return what an empty ExtraValue would return : false. 629 return null != mCurrentSubtype ? mCurrentSubtype.containsExtraValueKey(key) : false; 630 } 631 632 public String getCurrentSubtypeExtraValueOf(String key) { 633 // If null, return what an empty ExtraValue would return : null. 634 return null != mCurrentSubtype ? mCurrentSubtype.getExtraValueOf(key) : null; 635 } 636 637 public String getCurrentSubtypeMode() { 638 return null != mCurrentSubtype ? mCurrentSubtype.getMode() : KEYBOARD_MODE; 639 } 640 641 642 public boolean isVoiceSupported(String locale) { 643 // Get the current list of supported locales and check the current locale against that 644 // list. We cache this value so as not to check it every time the user starts a voice 645 // input. Because this method is called by onStartInputView, this should mean that as 646 // long as the locale doesn't change while the user is keeping the IME open, the 647 // value should never be stale. 648 String supportedLocalesString = VoiceProxy.getSupportedLocalesString( 649 mService.getContentResolver()); 650 List<String> voiceInputSupportedLocales = Arrays.asList( 651 supportedLocalesString.split("\\s+")); 652 return voiceInputSupportedLocales.contains(locale); 653 } 654 655 private void changeToNextSubtype() { 656 final InputMethodSubtypeCompatWrapper subtype = 657 mLanguageBarInfo.getNextKeyboardSubtype(); 658 switchToTargetIME(mInputMethodId, subtype); 659 } 660 661 private void changeToPreviousSubtype() { 662 final InputMethodSubtypeCompatWrapper subtype = 663 mLanguageBarInfo.getPreviousKeyboardSubtype(); 664 switchToTargetIME(mInputMethodId, subtype); 665 } 666 667 public void toggleLanguage(boolean next) { 668 if (next) { 669 changeToNextSubtype(); 670 } else { 671 changeToPreviousSubtype(); 672 } 673 } 674} 675