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

Commit 6cfdf037 authored by Yohei Yukawa's avatar Yohei Yukawa
Browse files

Replace IMMS.SettingsObserver with SecureSettingsChangeCallback

This CL mechanically extracts out IMMS.SettingsObserver as a utility
interface named SecureSettingsChangeCallback.

There must be no observable behavior change.

Bug: 342027196
Test: presubmit
Flag: EXEMPT refactor
Change-Id: I27f94ca795f3035b5132a28fbbec669122d42b87
parent 18357123
Loading
Loading
Loading
Loading
+56 −81
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ import android.app.ActivityManagerInternal;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentProvider;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -80,7 +79,6 @@ import android.content.pm.PackageManagerInternal;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.content.res.Resources;
import android.database.ContentObserver;
import android.hardware.input.InputManager;
import android.inputmethodservice.InputMethodService;
import android.media.AudioManagerInternal;
@@ -195,7 +193,6 @@ import java.lang.annotation.Target;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
@@ -349,8 +346,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
    @GuardedBy("ImfLock.class")
    private UserDataRepository mUserDataRepository;

    @MultiUserUnawareField
    final SettingsObserver mSettingsObserver;
    final WindowManagerInternal mWindowManagerInternal;
    private final ActivityManagerInternal mActivityManagerInternal;
    final PackageManagerInternal mPackageManagerInternal;
@@ -570,52 +565,17 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
    @NonNull
    private final ImeTrackerService mImeTrackerService;

    class SettingsObserver extends ContentObserver {

        /**
         * <em>This constructor must be called within the lock.</em>
         */
        SettingsObserver(Handler handler) {
            super(handler);
        }

        void registerContentObserverForAllUsers() {
            ContentResolver resolver = mContext.getContentResolver();
            resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
                    Settings.Secure.DEFAULT_INPUT_METHOD), false, this, UserHandle.ALL);
            resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
                    Settings.Secure.ENABLED_INPUT_METHODS), false, this, UserHandle.ALL);
            resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
                    Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, UserHandle.ALL);
            resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
                    Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, UserHandle.ALL);
            resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
                    Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, UserHandle.ALL);
            resolver.registerContentObserverAsUser(Settings.Secure.getUriFor(
                    STYLUS_HANDWRITING_ENABLED), false, this, UserHandle.ALL);
        }

        @Override
        public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags,
                @UserIdInt int userId) {
            uris.forEach(uri -> onChangeInternal(uri, userId));
        }

        private void onChangeInternal(@NonNull Uri uri, @UserIdInt int userId) {
            final Uri showImeUri = Settings.Secure.getUriFor(
                    Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
            final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
                    Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
            final Uri stylusHandwritingEnabledUri = Settings.Secure.getUriFor(
                    STYLUS_HANDWRITING_ENABLED);
            synchronized (ImfLock.class) {
                if (!mConcurrentMultiUserModeEnabled && mCurrentUserId != userId) {
    @GuardedBy("ImfLock.class")
    private void onSecureSettingsChangedLocked(@NonNull String key, @UserIdInt int userId) {
        if (!mConcurrentMultiUserModeEnabled && userId != mCurrentUserId) {
            return;
        }

                if (showImeUri.equals(uri)) {
        switch (key) {
            case Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD: {
                mMenuController.updateKeyboardFromSettingsLocked();
                } else if (accessibilityRequestingNoImeUri.equals(uri)) {
                break;
            }
            case Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE: {
                final int accessibilitySoftKeyboardSetting = Settings.Secure.getIntForUser(
                        mContext.getContentResolver(),
                        Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, userId);
@@ -624,18 +584,23 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
                final var userData = getUserData(userId);
                if (mVisibilityStateComputer.getImePolicy().isA11yRequestNoSoftKeyboard()) {
                    hideCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
                                0 /* flags */, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE,
                                userId);
                            0 /* flags */, SoftInputShowHideReason.HIDE_SETTINGS_ON_CHANGE, userId);
                } else if (isShowRequestedForCurrentWindow(userId)) {
                    showCurrentInputLocked(userData.mImeBindingState.mFocusedWindow,
                            InputMethodManager.SHOW_IMPLICIT,
                            SoftInputShowHideReason.SHOW_SETTINGS_ON_CHANGE, userId);
                }
                } else if (stylusHandwritingEnabledUri.equals(uri)) {
                break;
            }
            case STYLUS_HANDWRITING_ENABLED: {
                InputMethodManager.invalidateLocalStylusHandwritingAvailabilityCaches();
                InputMethodManager
                        .invalidateLocalConnectionlessStylusHandwritingAvailabilityCaches();
                } else {
                break;
            }
            case Settings.Secure.DEFAULT_INPUT_METHOD:
            case Settings.Secure.ENABLED_INPUT_METHODS:
            case Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE: {
                boolean enabledChanged = false;
                String newEnabled = InputMethodSettingsRepository.get(userId)
                        .getEnabledInputMethodsStr();
@@ -645,7 +610,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
                    enabledChanged = true;
                }
                updateInputMethodsFromSettingsLocked(enabledChanged, userId);
                }
                break;
            }
        }
    }
@@ -1118,8 +1083,6 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
            }
            SystemLocaleWrapper.onStart(context, this::onActionLocaleChanged, mHandler);
            mImeTrackerService = new ImeTrackerService(mHandler);
            // Note: SettingsObserver doesn't register observers in its constructor.
            mSettingsObserver = new SettingsObserver(mHandler);
            mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
            mActivityManagerInternal = LocalServices.getService(ActivityManagerInternal.class);
            mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
@@ -1389,7 +1352,19 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl.
                }, "Lazily initialize IMMS#mImeDrawsImeNavBarRes");

                mMyPackageMonitor.register(mContext, UserHandle.ALL, mIoHandler);
                mSettingsObserver.registerContentObserverForAllUsers();
                SecureSettingsChangeCallback.register(mHandler, mContext.getContentResolver(),
                        new String[] {
                                Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
                                Settings.Secure.DEFAULT_INPUT_METHOD,
                                Settings.Secure.ENABLED_INPUT_METHODS,
                                Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE,
                                Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
                                Settings.Secure.STYLUS_HANDWRITING_ENABLED,
                        }, (key, flags, userId) -> {
                            synchronized (ImfLock.class) {
                                onSecureSettingsChangedLocked(key, userId);
                            }
                        });

                final IntentFilter broadcastFilterForAllUsers = new IntentFilter();
                broadcastFilterForAllUsers.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
+78 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 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.NonNull;
import android.annotation.UserIdInt;
import android.content.ContentResolver;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.ArrayMap;

import java.util.Collection;

/**
 * A wrapper interface to monitor the given set of {@link Settings.Secure}.
 */
@FunctionalInterface
interface SecureSettingsChangeCallback {
    /**
     * Called back when the value associated with {@code key} is updated.
     *
     * @param key a key defined in {@link Settings.Secure}
     * @param flags flags defined in {@link ContentResolver.NotifyFlags}
     * @param userId the user ID with which the value is associated
     */
    void onChange(@NonNull String key, @ContentResolver.NotifyFlags int flags,
            @UserIdInt int userId);

    /**
     * Registers {@link SecureSettingsChangeCallback} to the given set of {@link Settings.Secure}.
     *
     * @param handler  {@link Handler} to be used to call back {@link #onChange(String, int, int)}
     * @param resolver {@link ContentResolver} with which {@link Settings.Secure} will be retrieved
     * @param keys     A set of {@link Settings.Secure} to be monitored
     * @param callback {@link SecureSettingsChangeCallback} to be called back
     */
    @NonNull
    static void register(@NonNull Handler handler, @NonNull ContentResolver resolver,
            @NonNull String[] keys, @NonNull SecureSettingsChangeCallback callback) {
        final ArrayMap<Uri, String> uriMapper = new ArrayMap<>();
        for (String key : keys) {
            uriMapper.put(Settings.Secure.getUriFor(key), key);
        }
        final ContentObserver observer = new ContentObserver(handler) {
            @Override
            public void onChange(boolean selfChange, @NonNull Collection<Uri> uris, int flags,
                    @UserIdInt int userId) {
                uris.forEach(uri -> {
                    final String key = uriMapper.get(uri);
                    if (key != null) {
                        callback.onChange(key, flags, userId);
                    }
                });
            }
        };
        for (Uri uri : uriMapper.keySet()) {
            resolver.registerContentObserverAsUser(uri, false /* notifyForDescendants */, observer,
                    UserHandle.ALL);
        }
    }
}