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

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

Merge "Introduce SystemLocaleWrapper" into main

parents 9fb00362 e536a3a6
Loading
Loading
Loading
Loading
+10 −15
Original line number Diff line number Diff line
@@ -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);

@@ -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);
@@ -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);
+3 −5
Original line number Diff line number Diff line
@@ -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);
+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);
            }
        }
    }
}