Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 809c9321 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

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
parent 16645966
Loading
Loading
Loading
Loading
+29 −1
Original line number Diff line number Diff line
@@ -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;
+41 −0
Original line number Diff line number Diff line
@@ -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<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) {
        mImmWrapper.mImm.setInputMethodAndSubtype(
                token, getInputMethodIdOfThisIme(), subtype);