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

Commit b3fdffbb authored by Yohei Yukawa's avatar Yohei Yukawa Committed by Android (Google) Code Review
Browse files

Merge changes Iaf179d60,I315cf372,I21d3c5cc into nyc-dev

* changes:
  Use LocaleList for implicitly enabled subtypes.
  Add a utility method to filter locales.
  Mechanical refactoring in InputMethodUtilsTest.
parents 565f11f9 e985c240
Loading
Loading
Loading
Loading
+57 −38
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.text.TextUtils;
import android.text.TextUtils.SimpleStringSplitter;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.LocaleList;
import android.util.Pair;
import android.util.Printer;
import android.util.Slog;
@@ -486,18 +487,29 @@ public class InputMethodUtils {
        return NOT_A_SUBTYPE_ID;
    }

    private static final LocaleUtils.LocaleExtractor<InputMethodSubtype> sSubtypeToLocale =
            new LocaleUtils.LocaleExtractor<InputMethodSubtype>() {
                @Override
                public Locale get(InputMethodSubtype source) {
                    return source != null ? source.getLocaleObject() : null;
                }
            };

    @VisibleForTesting
    public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
            Resources res, InputMethodInfo imi) {
        final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
        final String systemLocale = res.getConfiguration().locale.toString();
        final LocaleList systemLocales = res.getConfiguration().getLocales();
        final String systemLocale = systemLocales.get(0).toString();
        if (TextUtils.isEmpty(systemLocale)) return new ArrayList<>();
        final String systemLanguage = res.getConfiguration().locale.getLanguage();
        final int numSubtypes = subtypes.size();

        // Handle overridesImplicitlyEnabledSubtype mechanism.
        final String systemLanguage = systemLocales.get(0).getLanguage();
        final HashMap<String, InputMethodSubtype> applicableModeAndSubtypesMap = new HashMap<>();
        final int N = subtypes.size();
        for (int i = 0; i < N; ++i) {
        for (int i = 0; i < numSubtypes; ++i) {
            // scan overriding implicitly enabled subtypes.
            InputMethodSubtype subtype = subtypes.get(i);
            final InputMethodSubtype subtype = subtypes.get(i);
            if (subtype.overridesImplicitlyEnabledSubtype()) {
                final String mode = subtype.getMode();
                if (!applicableModeAndSubtypesMap.containsKey(mode)) {
@@ -508,42 +520,46 @@ public class InputMethodUtils {
        if (applicableModeAndSubtypesMap.size() > 0) {
            return new ArrayList<>(applicableModeAndSubtypesMap.values());
        }
        for (int i = 0; i < N; ++i) {

        final ArrayList<InputMethodSubtype> keyboardSubtypes = new ArrayList<>();
        for (int i = 0; i < numSubtypes; ++i) {
            final InputMethodSubtype subtype = subtypes.get(i);
            final String locale = subtype.getLocale();
            if (TextUtils.equals(SUBTYPE_MODE_KEYBOARD, subtype.getMode())) {
                keyboardSubtypes.add(subtype);
            } else {
                final Locale locale = subtype.getLocaleObject();
                final String mode = subtype.getMode();
            final String language = getLanguageFromLocaleString(locale);
            // When system locale starts with subtype's locale, that subtype will be applicable
            // for system locale. We need to make sure the languages are the same, to prevent
            // locales like "fil" (Filipino) being matched by "fi" (Finnish).
            //
            // For instance, it's clearly applicable for cases like system locale = en_US and
            // subtype = en, but it is not necessarily considered applicable for cases like system
            // locale = en and subtype = en_US.
            //
            // We just call systemLocale.startsWith(locale) in this function because there is no
            // need to find applicable subtypes aggressively unlike
            // findLastResortApplicableSubtypeLocked.
            //
            // TODO: This check is broken. It won't take scripts into account and doesn't
            // account for the mandatory conversions performed by Locale#toString.
            if (language.equals(systemLanguage) && systemLocale.startsWith(locale)) {
                final InputMethodSubtype applicableSubtype = applicableModeAndSubtypesMap.get(mode);
                // TODO: Take secondary system locales into consideration.
                if (locale != null && locale.equals(systemLanguage)) {
                    final InputMethodSubtype applicableSubtype =
                            applicableModeAndSubtypesMap.get(mode);
                    // If more applicable subtypes are contained, skip.
                    if (applicableSubtype != null) {
                    if (systemLocale.equals(applicableSubtype.getLocale())) continue;
                        if (systemLocale.equals(applicableSubtype.getLocaleObject())) continue;
                        if (!systemLocale.equals(locale)) continue;
                    }
                    applicableModeAndSubtypesMap.put(mode, subtype);
                }
            }
        final InputMethodSubtype keyboardSubtype
                = applicableModeAndSubtypesMap.get(SUBTYPE_MODE_KEYBOARD);
        final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>(
                applicableModeAndSubtypesMap.values());
        if (keyboardSubtype != null && !keyboardSubtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
            for (int i = 0; i < N; ++i) {
                final InputMethodSubtype subtype = subtypes.get(i);
        }

        final ArrayList<InputMethodSubtype> applicableSubtypes = new ArrayList<>();
        LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales,
                applicableSubtypes);

        boolean hasAsciiCapableKeyboard = false;
        final int numApplicationSubtypes = applicableSubtypes.size();
        for (int i = 0; i < numApplicationSubtypes; ++i) {
            final InputMethodSubtype subtype = applicableSubtypes.get(i);
            if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
                hasAsciiCapableKeyboard = true;
                break;
            }
        }
        if (!hasAsciiCapableKeyboard) {
            final int numKeyboardSubtypes = keyboardSubtypes.size();
            for (int i = 0; i < numKeyboardSubtypes; ++i) {
                final InputMethodSubtype subtype = keyboardSubtypes.get(i);
                final String mode = subtype.getMode();
                if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
                        TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
@@ -551,13 +567,16 @@ public class InputMethodUtils {
                }
            }
        }
        if (keyboardSubtype == null) {

        if (applicableSubtypes.isEmpty()) {
            InputMethodSubtype lastResortKeyboardSubtype = findLastResortApplicableSubtypeLocked(
                    res, subtypes, SUBTYPE_MODE_KEYBOARD, systemLocale, true);
            if (lastResortKeyboardSubtype != null) {
                applicableSubtypes.add(lastResortKeyboardSubtype);
            }
        }

        applicableSubtypes.addAll(applicableModeAndSubtypesMap.values());
        return applicableSubtypes;
    }

+142 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.internal.inputmethod;

import com.android.internal.annotations.VisibleForTesting;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.text.TextUtils;
import android.util.LocaleList;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Objects;

public final class LocaleUtils {

    @VisibleForTesting
    public interface LocaleExtractor<T> {
        @Nullable
        Locale get(@Nullable T source);
    }

    @Nullable
    private static String getLanguage(@Nullable Locale locale) {
        if (locale == null) {
            return null;
        }
        return locale.getLanguage();
    }

    /**
     * Filters the given items based on language preferences.
     *
     * <p>For each language found in {@code preferredLanguages}, this method tries to copy at most
     * one best-match item from {@code source} to {@code dest}.  For example, if
     * {@code "en-GB", "ja", "en-AU", "fr-CA", "en-IN"} is specified to {@code preferredLanguages},
     * this method tries to copy at most one English locale, at most one Japanese, and at most one
     * French locale from {@code source} to {@code dest}.  Here the best matching English locale
     * will be searched from {@code source} as follows.
     * <ol>
     *     <li>The first instance in {@code sources} that exactly matches {@code "en-GB"}</li>
     *     <li>The first instance in {@code sources} that exactly matches {@code "en-AU"}</li>
     *     <li>The first instance in {@code sources} that exactly matches {@code "en-IN"}</li>
     *     <li>The first instance in {@code sources} that partially matches {@code "en"}</li>
     * </ol>
     * <p>Then this method iterates the same algorithm for Japanese then French.</p>
     *
     * @param sources Source items to be filtered.
     * @param extractor Type converter from the source items to {@link Locale} object.
     * @param preferredLanguages Ordered list of locales with which the input items will be
     * filtered.
     * @param dest Destination into which the filtered items will be added.
     * @param <T> Type of the data items.
     */
    @VisibleForTesting
    public static <T> void filterByLanguage(
            @NonNull List<T> sources,
            @NonNull LocaleExtractor<T> extractor,
            @NonNull LocaleList preferredLanguages,
            @NonNull ArrayList<T> dest) {
        final Locale[] availableLocales = new Locale[sources.size()];
        for (int i = 0; i < availableLocales.length; ++i) {
            availableLocales[i] = extractor.get(sources.get(i));
        }
        final Locale[] sortedPreferredLanguages = new Locale[preferredLanguages.size()];
        if (sortedPreferredLanguages.length > 0) {
            int nextIndex = 0;
            final int N = preferredLanguages.size();
            languageLoop:
            for (int i = 0; i < N; ++i) {
                final String language = getLanguage(preferredLanguages.get(i));
                for (int j = 0; j < nextIndex; ++j) {
                    if (TextUtils.equals(getLanguage(sortedPreferredLanguages[j]), language)) {
                        continue languageLoop;
                    }
                }
                for (int j = i; j < N; ++j) {
                    final Locale locale = preferredLanguages.get(j);
                    if (TextUtils.equals(language, getLanguage(locale))) {
                        sortedPreferredLanguages[nextIndex] = locale;
                        ++nextIndex;
                    }
                }
            }
        }


        for (int languageIndex = 0; languageIndex < sortedPreferredLanguages.length;) {
            // Finding the range.
            final String language = getLanguage(sortedPreferredLanguages[languageIndex]);
            int nextLanguageIndex = languageIndex;
            for (; nextLanguageIndex < sortedPreferredLanguages.length; ++nextLanguageIndex) {
                final Locale locale = sortedPreferredLanguages[nextLanguageIndex];
                if (!TextUtils.equals(getLanguage(locale), language)) {
                    break;
                }
            }

            // Check exact match
            boolean found = false;
            for (int i = languageIndex; !found && i < nextLanguageIndex; ++i) {
                final Locale locale = sortedPreferredLanguages[i];
                for (int j = 0; j < availableLocales.length; ++j) {
                    if (!Objects.equals(locale, availableLocales[j])) {
                        continue;
                    }
                    dest.add(sources.get(j));
                    found = true;
                    break;
                }
            }

            if (!found) {
                // No exact match.  Use language match.
                for (int j = 0; j < availableLocales.length; ++j) {
                    if (!TextUtils.equals(language, getLanguage(availableLocales[j]))) {
                        continue;
                    }
                    dest.add(sources.get(j));
                    break;
                }
            }
            languageIndex = nextLanguageIndex;
        }
    }
}
 No newline at end of file
+50 −36
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.pm.ApplicationInfo;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Parcel;
import android.test.InstrumentationTestCase;
import android.test.suitebuilder.annotation.SmallTest;
@@ -36,6 +37,10 @@ import java.util.List;
import java.util.Locale;
import java.util.Objects;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.isIn;
import static org.hamcrest.Matchers.not;

public class InputMethodUtilsTest extends InstrumentationTestCase {
    private static final boolean IS_AUX = true;
    private static final boolean IS_DEFAULT = true;
@@ -186,6 +191,9 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
        final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
        final InputMethodSubtype nonAutoEnIN = createDummyInputMethodSubtype("en_IN",
                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
        final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
@@ -233,9 +241,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_EN_US))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_EN_US), imi);
            assertEquals(1, result.size());
            verifyEquality(autoSubtype, result.get(0));
        }
@@ -257,9 +263,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_EN_US))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_EN_US), imi);
            verifyEquality(nonAutoEnUS, result.get(0));
        }

@@ -279,9 +283,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_EN_GB))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_EN_GB), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoEnGB, result.get(0));
        }
@@ -303,9 +305,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_FR))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_FR), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoFrCA, result.get(0));
        }
@@ -323,9 +323,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_FR_CA))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_FR_CA), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoFrCA, result.get(0));
        }
@@ -344,9 +342,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_JA_JP))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_JA_JP), imi);
            assertEquals(3, result.size());
            verifyEquality(nonAutoJa, result.get(0));
            verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
@@ -364,9 +360,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_FIL_PH))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_FIL_PH), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoFil, result.get(0));
        }
@@ -384,9 +378,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_FI))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_FI), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoJa, result.get(0));
        }
@@ -402,9 +394,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_IN))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_IN), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoIn, result.get(0));
        }
@@ -418,9 +408,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_ID))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_ID), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoIn, result.get(0));
        }
@@ -434,9 +422,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_IN))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_IN), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoId, result.get(0));
        }
@@ -450,12 +436,36 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            createTargetContextWithLocales(new LocaleList(LOCALE_ID))
                                    .getResources(),
                            imi);
                            getResourcesForLocales(LOCALE_ID), imi);
            assertEquals(1, result.size());
            verifyEquality(nonAutoId, result.get(0));
        }

        // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and the system
        // provides multiple locales, we try to enable multiple subtypes.
        {
            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
            subtypes.add(nonAutoEnUS);
            subtypes.add(nonAutoFrCA);
            subtypes.add(nonAutoIn);
            subtypes.add(nonAutoJa);
            subtypes.add(nonAutoFil);
            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
            final InputMethodInfo imi = createDummyInputMethodInfo(
                    "com.android.apps.inputmethod.latin",
                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
                    subtypes);
            final ArrayList<InputMethodSubtype> result =
                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
                            getResourcesForLocales(LOCALE_FR, LOCALE_EN_US, LOCALE_JA_JP), imi);
            assertThat(nonAutoFrCA, isIn(result));
            assertThat(nonAutoEnUS, isIn(result));
            assertThat(nonAutoJa, isIn(result));
            assertThat(nonAutoIn, not(isIn(result)));
            assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
            assertThat(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, not(isIn(result)));
        }
    }

    @SmallTest
@@ -638,6 +648,10 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
                .createConfigurationContext(resourceConfiguration);
    }

    private Resources getResourcesForLocales(Locale... locales) {
        return createTargetContextWithLocales(new LocaleList(locales)).getResources();
    }

    private String[] getPackageNames(final ArrayList<InputMethodInfo> imis) {
        final String[] packageNames = new String[imis.size()];
        for (int i = 0; i < imis.size(); ++i) {
+194 −0

File added.

Preview size limit exceeded, changes collapsed.

+7 −7
Original line number Diff line number Diff line
@@ -95,6 +95,7 @@ import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.AtomicFile;
import android.util.EventLog;
import android.util.LocaleList;
import android.util.LruCache;
import android.util.Pair;
import android.util.PrintWriterPrinter;
@@ -135,7 +136,6 @@ import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

/**
 * This class provides a system service that manages input methods.
@@ -446,7 +446,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
    private View mSwitchingDialogTitleView;
    private InputMethodInfo[] mIms;
    private int[] mSubtypeIds;
    private Locale mLastSystemLocale;
    private LocaleList mLastSystemLocales;
    private boolean mShowImeWithHardKeyboard;
    private boolean mAccessibilityRequestingNoSoftKeyboard;
    private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
@@ -949,15 +949,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
            // not system ready
            return;
        }
        final Locale newLocale = mRes.getConfiguration().locale;
        final LocaleList newLocales = mRes.getConfiguration().getLocales();
        if (!updateOnlyWhenLocaleChanged
                || (newLocale != null && !newLocale.equals(mLastSystemLocale))) {
                || (newLocales != null && !newLocales.equals(mLastSystemLocales))) {
            if (!updateOnlyWhenLocaleChanged) {
                hideCurrentInputLocked(0, null);
                resetCurrentMethodAndClient(InputMethodClient.UNBIND_REASON_RESET_IME);
            }
            if (DEBUG) {
                Slog.i(TAG, "Locale has been changed to " + newLocale);
                Slog.i(TAG, "LocaleList has been changed to " + newLocales);
            }
            buildInputMethodListLocked(resetDefaultEnabledIme);
            if (!updateOnlyWhenLocaleChanged) {
@@ -972,7 +972,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                resetDefaultImeLocked(mContext);
            }
            updateFromSettingsLocked(true);
            mLastSystemLocale = newLocale;
            mLastSystemLocales = newLocales;
            if (!updateOnlyWhenLocaleChanged) {
                try {
                    startInputInnerLocked();
@@ -1079,7 +1079,7 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
                            mSettings.getEnabledInputMethodListLocked(),
                            mSettings.getCurrentUserId(), mContext.getBasePackageName());
                }
                mLastSystemLocale = mRes.getConfiguration().locale;
                mLastSystemLocales = mRes.getConfiguration().getLocales();
                try {
                    startInputInnerLocked();
                } catch (RuntimeException e) {