Experimental automatic language switching support.

With this CL, LatinIME switches the current subtype from its enabled
subtypes based on the first locale in EditorInfo#hintLocales.

This functionality is still experimental, and will be triggered only
when EditorInfo#hintLocales is specified by the application.

Bug: 22859862
Change-Id: Ibd0559b370d8aa0d50d1bada8ecfdac0ed8db898
This commit is contained in:
Yohei Yukawa 2016-01-22 02:10:35 -08:00
parent 16645966a9
commit 809c93214b
2 changed files with 70 additions and 1 deletions

View file

@ -54,7 +54,9 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.accessibility.AccessibilityUtils; import com.android.inputmethod.accessibility.AccessibilityUtils;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.EditorInfoCompatUtils;
import com.android.inputmethod.compat.InputMethodServiceCompatUtils; import com.android.inputmethod.compat.InputMethodServiceCompatUtils;
import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils; import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils;
import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater; import com.android.inputmethod.compat.ViewOutlineProviderCompatUtils.InsetsUpdater;
import com.android.inputmethod.dictionarypack.DictionaryPackConstants; 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_WAIT_FOR_DICTIONARY_LOAD = 8;
private static final int MSG_DEALLOCATE_MEMORY = 9; private static final int MSG_DEALLOCATE_MEMORY = 9;
private static final int MSG_RESUME_SUGGESTIONS_FOR_START_INPUT = 10; 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 // 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_NOT_GESTURE_INPUT = 0;
private static final int ARG1_DISMISS_GESTURE_FLOATING_PREVIEW_TEXT = 1; 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: case MSG_DEALLOCATE_MEMORY:
latinIme.deallocateMemory(); latinIme.deallocateMemory();
break; 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(); 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. // Working variables for the following methods.
private boolean mIsOrientationChanging; private boolean mIsOrientationChanging;
private boolean mPendingSuccessiveImsCallback; private boolean mPendingSuccessiveImsCallback;
@ -795,6 +805,19 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) { void onStartInputInternal(final EditorInfo editorInfo, final boolean restarting) {
super.onStartInput(editorInfo, 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") @SuppressWarnings("deprecation")
@ -1301,6 +1324,11 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
return mOptionsDialog != null && mOptionsDialog.isShowing(); 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. // TODO: Revise the language switch key behavior to make it much smarter and more reasonable.
public void switchToNextSubtype() { public void switchToNextSubtype() {
final IBinder token = getWindow().getWindow().getAttributes().token; final IBinder token = getWindow().getWindow().getAttributes().token;

View file

@ -32,6 +32,7 @@ import android.view.inputmethod.InputMethodSubtype;
import com.android.inputmethod.annotations.UsedForTesting; import com.android.inputmethod.annotations.UsedForTesting;
import com.android.inputmethod.compat.InputMethodManagerCompatWrapper; import com.android.inputmethod.compat.InputMethodManagerCompatWrapper;
import com.android.inputmethod.compat.InputMethodSubtypeCompatUtils;
import com.android.inputmethod.latin.settings.Settings; import com.android.inputmethod.latin.settings.Settings;
import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils; import com.android.inputmethod.latin.utils.AdditionalSubtypeUtils;
import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils; import com.android.inputmethod.latin.utils.LanguageOnSpacebarUtils;
@ -428,6 +429,46 @@ public class RichInputMethodManager {
return null; 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<InputMethodSubtype> 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) { public void setInputMethodAndSubtype(final IBinder token, final InputMethodSubtype subtype) {
mImmWrapper.mImm.setInputMethodAndSubtype( mImmWrapper.mImm.setInputMethodAndSubtype(
token, getInputMethodIdOfThisIme(), subtype); token, getInputMethodIdOfThisIme(), subtype);