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

Commit aad32e06 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Replace IMMS.SettingsObserver with SecureSettingsChangeCallback" into main

parents 55d6abc3 6cfdf037
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);
        }
    }
}