Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +10 −15 Original line number Diff line number Diff line Loading @@ -741,7 +741,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ int mImeWindowVis; private LocaleList mLastSystemLocales; private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor(); private final String mSlotIme; Loading Loading @@ -1199,9 +1198,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (Intent.ACTION_USER_ADDED.equals(action) || Intent.ACTION_USER_REMOVED.equals(action)) { updateCurrentProfileIds(); return; } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) { onActionLocaleChanged(); } else { Slog.w(TAG, "Unexpected intent " + intent); } Loading Loading @@ -1240,20 +1236,19 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub * * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all * the users. We should ignore this event if this is about any background user's locale.</p> * * <p>Caution: This method must not be called when system is not ready.</p> */ void onActionLocaleChanged() { void onActionLocaleChanged(@NonNull LocaleList prevLocales, @NonNull LocaleList newLocales) { if (DEBUG) { Slog.d(TAG, "onActionLocaleChanged prev=" + prevLocales + " new=" + newLocales); } synchronized (ImfLock.class) { final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales(); if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) { if (!mSystemReady) { return; } buildInputMethodListLocked(true); // If the locale is changed, needs to reset the default ime resetDefaultImeLocked(mContext); updateFromSettingsLocked(true); mLastSystemLocales = possibleNewLocale; } } Loading Loading @@ -1681,6 +1676,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub true /* allowIo */); thread.start(); mHandler = Handler.createAsync(thread.getLooper(), this); SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler); mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null ? serviceThreadForTesting.getLooper() : Looper.getMainLooper()); // Note: SettingsObserver doesn't register observers in its constructor. Loading Loading @@ -1838,7 +1834,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // Even in such cases, IMMS works fine because it will find the most applicable // IME for that user. final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId); mLastSystemLocales = mRes.getConfiguration().getLocales(); // The mSystemReady flag is set during boot phase, // and user switch would not happen at that time. Loading Loading @@ -1890,7 +1885,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } if (!mSystemReady) { mSystemReady = true; mLastSystemLocales = mRes.getConfiguration().getLocales(); final int currentUserId = mSettings.getCurrentUserId(); mSettings.switchCurrentUser(currentUserId, !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId)); Loading Loading @@ -1930,7 +1924,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub final IntentFilter broadcastFilterForSystemUser = new IntentFilter(); broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED); broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED); broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED); mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(), broadcastFilterForSystemUser); Loading Loading @@ -4078,7 +4071,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub && !TextUtils.isEmpty(mCurrentSubtype.getLocale())) { locale = mCurrentSubtype.getLocale(); } else { locale = mRes.getConfiguration().locale.toString(); locale = SystemLocaleWrapper.get(mSettings.getCurrentUserId()).get(0) .toString(); } for (int i = 0; i < enabledCount; ++i) { final InputMethodInfo imi = enabled.get(i); Loading Loading @@ -5434,7 +5428,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) { mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0); } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) { final String locale = mRes.getConfiguration().locale.toString(); final String locale = SystemLocaleWrapper.get(mSettings.getCurrentUserId()) .get(0).toString(); mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtypeLocked( explicitlyOrImplicitlyEnabledSubtypes, SubtypeUtils.SUBTYPE_MODE_KEYBOARD, locale, true); Loading services/core/java/com/android/server/inputmethod/InputMethodUtils.java +3 −5 Original line number Diff line number Diff line Loading @@ -219,7 +219,6 @@ final class InputMethodUtils { @NonNull private Context mUserAwareContext; private Resources mRes; private ContentResolver mResolver; private final ArrayMap<String, InputMethodInfo> mMethodMap; Loading Loading @@ -282,7 +281,6 @@ final class InputMethodUtils { mUserAwareContext = context.getUserId() == userId ? context : context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); mRes = mUserAwareContext.getResources(); mResolver = mUserAwareContext.getContentResolver(); } Loading Loading @@ -399,7 +397,7 @@ final class InputMethodUtils { getEnabledInputMethodSubtypeListLocked(imi); if (allowsImplicitlyEnabledSubtypes && enabledSubtypes.isEmpty()) { enabledSubtypes = SubtypeUtils.getImplicitlyApplicableSubtypesLocked( mRes.getConfiguration().getLocales(), imi); SystemLocaleWrapper.get(mCurrentUserId), imi); } return InputMethodSubtype.sort(imi, enabledSubtypes); } Loading Loading @@ -648,7 +646,7 @@ final class InputMethodUtils { private String getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(List<Pair<String, ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) { final LocaleList localeList = mRes.getConfiguration().getLocales(); final LocaleList localeList = SystemLocaleWrapper.get(mCurrentUserId); for (Pair<String, ArrayList<String>> enabledIme: enabledImes) { if (enabledIme.first.equals(imeId)) { final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second; Loading Loading @@ -851,7 +849,7 @@ final class InputMethodUtils { if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) { return explicitlyOrImplicitlyEnabledSubtypes.get(0); } final String locale = mRes.getConfiguration().locale.toString(); final String locale = SystemLocaleWrapper.get(mCurrentUserId).get(0).toString(); final InputMethodSubtype subtype = SubtypeUtils.findLastResortApplicableSubtypeLocked( explicitlyOrImplicitlyEnabledSubtypes, SubtypeUtils.SUBTYPE_MODE_KEYBOARD, locale, true); Loading services/core/java/com/android/server/inputmethod/SystemLocaleWrapper.java 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.server.inputmethod; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.LocaleList; import java.util.Locale; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; /** * A set of thread-safe utility methods for the system locals. */ final class SystemLocaleWrapper { /** * Not intended to be instantiated. */ private SystemLocaleWrapper() { } private static final AtomicReference<LocaleList> sSystemLocale = new AtomicReference<>(new LocaleList(Locale.getDefault())); /** * Returns {@link LocaleList} for the specified user. * * <p>Note: If you call this method twice, it is possible that the second value is different * from the first value. The caller is responsible for taking care of such cases.</p> * * @param userId the ID of the user to query about. * @return {@link LocaleList} associated with the user. */ @AnyThread @NonNull static LocaleList get(@UserIdInt int userId) { // Currently system locale is not per-user. // TODO(b/30119489): Make this per-user. return sSystemLocale.get(); } /** * Callback for the locale change event. When this gets filed, {@link #get(int)} is already * updated to return the new value. */ interface Callback { void onLocaleChanged(@NonNull LocaleList prevLocales, @NonNull LocaleList newLocales); } /** * Called when {@link InputMethodManagerService} is about to start. * * @param context {@link Context} to be used. * @param callback {@link Callback} for the locale change events. */ @AnyThread static void onStart(@NonNull Context context, @NonNull Callback callback, @NonNull Handler handler) { sSystemLocale.set(context.getResources().getConfiguration().getLocales()); context.registerReceiver(new LocaleChangeListener(context, callback), new IntentFilter(Intent.ACTION_LOCALE_CHANGED), null, handler); } private static final class LocaleChangeListener extends BroadcastReceiver { @NonNull private final Context mContext; @NonNull private final Callback mCallback; LocaleChangeListener(@NonNull Context context, @NonNull Callback callback) { mContext = context; mCallback = callback; } @Override public void onReceive(Context context, Intent intent) { if (!Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { return; } final LocaleList newLocales = mContext.getResources().getConfiguration().getLocales(); final LocaleList prevLocales = sSystemLocale.getAndSet(newLocales); if (!Objects.equals(newLocales, prevLocales)) { mCallback.onLocaleChanged(prevLocales, newLocales); } } } } Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +10 −15 Original line number Diff line number Diff line Loading @@ -741,7 +741,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub */ int mImeWindowVis; private LocaleList mLastSystemLocales; private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor(); private final String mSlotIme; Loading Loading @@ -1199,9 +1198,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (Intent.ACTION_USER_ADDED.equals(action) || Intent.ACTION_USER_REMOVED.equals(action)) { updateCurrentProfileIds(); return; } else if (Intent.ACTION_LOCALE_CHANGED.equals(action)) { onActionLocaleChanged(); } else { Slog.w(TAG, "Unexpected intent " + intent); } Loading Loading @@ -1240,20 +1236,19 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub * * <p>Note: For historical reasons, {@link Intent#ACTION_LOCALE_CHANGED} has been sent to all * the users. We should ignore this event if this is about any background user's locale.</p> * * <p>Caution: This method must not be called when system is not ready.</p> */ void onActionLocaleChanged() { void onActionLocaleChanged(@NonNull LocaleList prevLocales, @NonNull LocaleList newLocales) { if (DEBUG) { Slog.d(TAG, "onActionLocaleChanged prev=" + prevLocales + " new=" + newLocales); } synchronized (ImfLock.class) { final LocaleList possibleNewLocale = mRes.getConfiguration().getLocales(); if (possibleNewLocale != null && possibleNewLocale.equals(mLastSystemLocales)) { if (!mSystemReady) { return; } buildInputMethodListLocked(true); // If the locale is changed, needs to reset the default ime resetDefaultImeLocked(mContext); updateFromSettingsLocked(true); mLastSystemLocales = possibleNewLocale; } } Loading Loading @@ -1681,6 +1676,7 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub true /* allowIo */); thread.start(); mHandler = Handler.createAsync(thread.getLooper(), this); SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler); mImeTrackerService = new ImeTrackerService(serviceThreadForTesting != null ? serviceThreadForTesting.getLooper() : Looper.getMainLooper()); // Note: SettingsObserver doesn't register observers in its constructor. Loading Loading @@ -1838,7 +1834,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub // Even in such cases, IMMS works fine because it will find the most applicable // IME for that user. final boolean initialUserSwitch = TextUtils.isEmpty(defaultImiId); mLastSystemLocales = mRes.getConfiguration().getLocales(); // The mSystemReady flag is set during boot phase, // and user switch would not happen at that time. Loading Loading @@ -1890,7 +1885,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub } if (!mSystemReady) { mSystemReady = true; mLastSystemLocales = mRes.getConfiguration().getLocales(); final int currentUserId = mSettings.getCurrentUserId(); mSettings.switchCurrentUser(currentUserId, !mUserManagerInternal.isUserUnlockingOrUnlocked(currentUserId)); Loading Loading @@ -1930,7 +1924,6 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub final IntentFilter broadcastFilterForSystemUser = new IntentFilter(); broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_ADDED); broadcastFilterForSystemUser.addAction(Intent.ACTION_USER_REMOVED); broadcastFilterForSystemUser.addAction(Intent.ACTION_LOCALE_CHANGED); mContext.registerReceiver(new ImmsBroadcastReceiverForSystemUser(), broadcastFilterForSystemUser); Loading Loading @@ -4078,7 +4071,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub && !TextUtils.isEmpty(mCurrentSubtype.getLocale())) { locale = mCurrentSubtype.getLocale(); } else { locale = mRes.getConfiguration().locale.toString(); locale = SystemLocaleWrapper.get(mSettings.getCurrentUserId()).get(0) .toString(); } for (int i = 0; i < enabledCount; ++i) { final InputMethodInfo imi = enabled.get(i); Loading Loading @@ -5434,7 +5428,8 @@ public final class InputMethodManagerService extends IInputMethodManager.Stub if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) { mCurrentSubtype = explicitlyOrImplicitlyEnabledSubtypes.get(0); } else if (explicitlyOrImplicitlyEnabledSubtypes.size() > 1) { final String locale = mRes.getConfiguration().locale.toString(); final String locale = SystemLocaleWrapper.get(mSettings.getCurrentUserId()) .get(0).toString(); mCurrentSubtype = SubtypeUtils.findLastResortApplicableSubtypeLocked( explicitlyOrImplicitlyEnabledSubtypes, SubtypeUtils.SUBTYPE_MODE_KEYBOARD, locale, true); Loading
services/core/java/com/android/server/inputmethod/InputMethodUtils.java +3 −5 Original line number Diff line number Diff line Loading @@ -219,7 +219,6 @@ final class InputMethodUtils { @NonNull private Context mUserAwareContext; private Resources mRes; private ContentResolver mResolver; private final ArrayMap<String, InputMethodInfo> mMethodMap; Loading Loading @@ -282,7 +281,6 @@ final class InputMethodUtils { mUserAwareContext = context.getUserId() == userId ? context : context.createContextAsUser(UserHandle.of(userId), 0 /* flags */); mRes = mUserAwareContext.getResources(); mResolver = mUserAwareContext.getContentResolver(); } Loading Loading @@ -399,7 +397,7 @@ final class InputMethodUtils { getEnabledInputMethodSubtypeListLocked(imi); if (allowsImplicitlyEnabledSubtypes && enabledSubtypes.isEmpty()) { enabledSubtypes = SubtypeUtils.getImplicitlyApplicableSubtypesLocked( mRes.getConfiguration().getLocales(), imi); SystemLocaleWrapper.get(mCurrentUserId), imi); } return InputMethodSubtype.sort(imi, enabledSubtypes); } Loading Loading @@ -648,7 +646,7 @@ final class InputMethodUtils { private String getEnabledSubtypeHashCodeForInputMethodAndSubtypeLocked(List<Pair<String, ArrayList<String>>> enabledImes, String imeId, String subtypeHashCode) { final LocaleList localeList = mRes.getConfiguration().getLocales(); final LocaleList localeList = SystemLocaleWrapper.get(mCurrentUserId); for (Pair<String, ArrayList<String>> enabledIme: enabledImes) { if (enabledIme.first.equals(imeId)) { final ArrayList<String> explicitlyEnabledSubtypes = enabledIme.second; Loading Loading @@ -851,7 +849,7 @@ final class InputMethodUtils { if (explicitlyOrImplicitlyEnabledSubtypes.size() == 1) { return explicitlyOrImplicitlyEnabledSubtypes.get(0); } final String locale = mRes.getConfiguration().locale.toString(); final String locale = SystemLocaleWrapper.get(mCurrentUserId).get(0).toString(); final InputMethodSubtype subtype = SubtypeUtils.findLastResortApplicableSubtypeLocked( explicitlyOrImplicitlyEnabledSubtypes, SubtypeUtils.SUBTYPE_MODE_KEYBOARD, locale, true); Loading
services/core/java/com/android/server/inputmethod/SystemLocaleWrapper.java 0 → 100644 +108 −0 Original line number Diff line number Diff line /* * Copyright (C) 2023 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.server.inputmethod; import android.annotation.AnyThread; import android.annotation.NonNull; import android.annotation.UserIdInt; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; import android.os.LocaleList; import java.util.Locale; import java.util.Objects; import java.util.concurrent.atomic.AtomicReference; /** * A set of thread-safe utility methods for the system locals. */ final class SystemLocaleWrapper { /** * Not intended to be instantiated. */ private SystemLocaleWrapper() { } private static final AtomicReference<LocaleList> sSystemLocale = new AtomicReference<>(new LocaleList(Locale.getDefault())); /** * Returns {@link LocaleList} for the specified user. * * <p>Note: If you call this method twice, it is possible that the second value is different * from the first value. The caller is responsible for taking care of such cases.</p> * * @param userId the ID of the user to query about. * @return {@link LocaleList} associated with the user. */ @AnyThread @NonNull static LocaleList get(@UserIdInt int userId) { // Currently system locale is not per-user. // TODO(b/30119489): Make this per-user. return sSystemLocale.get(); } /** * Callback for the locale change event. When this gets filed, {@link #get(int)} is already * updated to return the new value. */ interface Callback { void onLocaleChanged(@NonNull LocaleList prevLocales, @NonNull LocaleList newLocales); } /** * Called when {@link InputMethodManagerService} is about to start. * * @param context {@link Context} to be used. * @param callback {@link Callback} for the locale change events. */ @AnyThread static void onStart(@NonNull Context context, @NonNull Callback callback, @NonNull Handler handler) { sSystemLocale.set(context.getResources().getConfiguration().getLocales()); context.registerReceiver(new LocaleChangeListener(context, callback), new IntentFilter(Intent.ACTION_LOCALE_CHANGED), null, handler); } private static final class LocaleChangeListener extends BroadcastReceiver { @NonNull private final Context mContext; @NonNull private final Callback mCallback; LocaleChangeListener(@NonNull Context context, @NonNull Callback callback) { mContext = context; mCallback = callback; } @Override public void onReceive(Context context, Intent intent) { if (!Intent.ACTION_LOCALE_CHANGED.equals(intent.getAction())) { return; } final LocaleList newLocales = mContext.getResources().getConfiguration().getLocales(); final LocaleList prevLocales = sSystemLocale.getAndSet(newLocales); if (!Objects.equals(newLocales, prevLocales)) { mCallback.onLocaleChanged(prevLocales, newLocales); } } } }