Loading services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +56 −81 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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(); Loading @@ -645,7 +610,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. enabledChanged = true; } updateInputMethodsFromSettingsLocked(enabledChanged, userId); } break; } } } Loading Loading @@ -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); Loading Loading @@ -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); Loading services/core/java/com/android/server/inputmethod/SecureSettingsChangeCallback.java 0 → 100644 +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); } } } Loading
services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +56 −81 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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; Loading Loading @@ -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); Loading @@ -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(); Loading @@ -645,7 +610,7 @@ public final class InputMethodManagerService implements IInputMethodManagerImpl. enabledChanged = true; } updateInputMethodsFromSettingsLocked(enabledChanged, userId); } break; } } } Loading Loading @@ -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); Loading Loading @@ -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); Loading
services/core/java/com/android/server/inputmethod/SecureSettingsChangeCallback.java 0 → 100644 +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); } } }