diff --git a/java/src/com/android/inputmethod/latin/LatinIME.java b/java/src/com/android/inputmethod/latin/LatinIME.java index 55af62ee4..c2d9f965f 100644 --- a/java/src/com/android/inputmethod/latin/LatinIME.java +++ b/java/src/com/android/inputmethod/latin/LatinIME.java @@ -54,7 +54,9 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.annotations.UsedForTesting; +import com.android.inputmethod.compat.EditorInfoCompatUtils; import com.android.inputmethod.compat.InputMethodServiceCompatUtils; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils; import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater; import com.android.inputmethod.dictionarypack.DictionaryPackConstants; @@ -176,8 +178,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen private static final int MSG_WAIT_FOR_DICTIONARY_LOAD = 8; private static final int MSG_DEALLOCATE_MEMORY = 9; private static final int MSG_RESUME_SUGGESTIONS_FOR_START_INPUT = 10; + private static final int MSG_SWITCH_LANGUAGE_AUTOMATICALLY = 11; // Update this when adding new messages - private static final int MSG_LAST = MSG_RESUME_SUGGESTIONS_FOR_START_INPUT; + private static final int MSG_LAST = MSG_SWITCH_LANGUAGE_AUTOMATICALLY; private static final int ARG1_NOT_GESTURE_INPUT = 0; private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; @@ -271,6 +274,9 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen case MSG_DEALLOCATE_MEMORY: latinIme.deallocateMemory(); break; + case MSG_SWITCH_LANGUAGE_AUTOMATICALLY: + latinIme.switchLanguage((InputMethodSubtype)msg.obj); + break; } } @@ -389,6 +395,10 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen obtainMessage(MSG_UPDATE_TAIL_BATCH_INPUT_COMPLETED, suggestedWords).sendToTarget(); } + public void postSwitchLanguage(final InputMethodSubtype subtype) { + obtainMessage(MSG_SWITCH_LANGUAGE_AUTOMATICALLY, subtype).sendToTarget(); + } + // Working variables for the following methods. private boolean mIsOrientationChanging; private boolean mPendingSuccessiveImsCallback; @@ -795,6 +805,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) { super.onStartInput(editorInfo, restarting); + + // If the primary hint language does not match the current subtype language, then try + // to switch to the primary hint language. + // TODO: Support all the locales in EditorInfo#hintLocales. + final Locale primaryHintLocale = EditorInfoCompatUtils.getPrimaryHintLocale(editorInfo); + if (primaryHintLocale == null) { + return; + } + final InputMethodSubtype newSubtype = mRichImm.findSubtypeByLocale(primaryHintLocale); + if (newSubtype == null || newSubtype.equals(mRichImm.getCurrentSubtype().getRawSubtype())) { + return; + } + mHandler.postSwitchLanguage(newSubtype); } @SuppressWarnings("deprecation") @@ -1301,6 +1324,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen return mOptionsDialog != null && mOptionsDialog.isShowing(); } + public void switchLanguage(final InputMethodSubtype subtype) { + final IBinder token = getWindow().getWindow().getAttributes().token; + mRichImm.setInputMethodAndSubtype(token, subtype); + } + // TODO: Revise the language switch key behavior to make it much smarter and more reasonable. public void switchToNextSubtype() { final IBinder token = getWindow().getWindow().getAttributes().token; diff --git a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java index ef946c8bc..3beb51d68 100644 --- a/java/src/com/android/inputmethod/latin/RichInputMethodManager.java +++ b/java/src/com/android/inputmethod/latin/RichInputMethodManager.java @@ -32,6 +32,7 @@ import android.view.inputmethod.InputMethodSubtype; import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; +import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils; import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils; @@ -428,6 +429,46 @@ public class RichInputMethodManager { return null; } + public InputMethodSubtype findSubtypeByLocale(final Locale locale) { + // Find the best subtype based on a straightforward matching algorithm. + // TODO: Use LocaleList#getFirstMatch() instead. + final List subtypes = + getMyEnabledInputMethodSubtypeList(true /* allowsImplicitlySelectedSubtypes */); + final int count = subtypes.size(); + for (int i = 0; i < count; ++i) { + final InputMethodSubtype subtype = subtypes.get(i); + final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); + if (subtypeLocale.equals(locale)) { + return subtype; + } + } + for (int i = 0; i < count; ++i) { + final InputMethodSubtype subtype = subtypes.get(i); + final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); + if (subtypeLocale.getLanguage().equals(locale.getLanguage()) && + subtypeLocale.getCountry().equals(locale.getCountry()) && + subtypeLocale.getVariant().equals(locale.getVariant())) { + return subtype; + } + } + for (int i = 0; i < count; ++i) { + final InputMethodSubtype subtype = subtypes.get(i); + final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); + if (subtypeLocale.getLanguage().equals(locale.getLanguage()) && + subtypeLocale.getCountry().equals(locale.getCountry())) { + return subtype; + } + } + for (int i = 0; i < count; ++i) { + final InputMethodSubtype subtype = subtypes.get(i); + final Locale subtypeLocale = InputMethodSubtypeCompatUtils.getLocaleObject(subtype); + if (subtypeLocale.getLanguage().equals(locale.getLanguage())) { + return subtype; + } + } + return null; + } + public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) { mImmWrapper.mImm.setInputMethodAndSubtype( token, getInputMethodIdOfThisIme(), subtype);