summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodManagerService.java25
-rw-r--r--services/core/java/com/android/server/inputmethod/InputMethodUtils.java8
-rw-r--r--services/core/java/com/android/server/inputmethod/SystemLocaleWrapper.java108
3 files changed, 121 insertions, 20 deletions
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 879040622d2f..0cd2ba247a14 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -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;
@@ -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);
}
@@ -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;
}
}
@@ -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.
@@ -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.
@@ -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));
@@ -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);
@@ -4070,7 +4063,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);
@@ -5425,7 +5419,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);
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
index 831a2a2df2cd..c661c864b3ee 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodUtils.java
@@ -219,7 +219,6 @@ final class InputMethodUtils {
@NonNull
private Context mUserAwareContext;
- private Resources mRes;
private ContentResolver mResolver;
private final ArrayMap<String, InputMethodInfo> mMethodMap;
@@ -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();
}
@@ -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);
}
@@ -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;
@@ -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);
diff --git a/services/core/java/com/android/server/inputmethod/SystemLocaleWrapper.java b/services/core/java/com/android/server/inputmethod/SystemLocaleWrapper.java
new file mode 100644
index 000000000000..0f1b7119f8ce
--- /dev/null
+++ b/services/core/java/com/android/server/inputmethod/SystemLocaleWrapper.java
@@ -0,0 +1,108 @@
+/*
+ * 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);
+ }
+ }
+ }
+}