Loading api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2819,6 +2819,7 @@ package android.accessibilityservice { field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; field public static final int SHOW_MODE_AUTO = 0; // 0x0 field public static final int SHOW_MODE_HIDDEN = 1; // 0x1 field public static final int SHOW_MODE_WITH_HARD_KEYBOARD = 2; // 0x2 } public static abstract class AccessibilityService.GestureResultCallback { core/java/android/accessibilityservice/AccessibilityService.java +82 −22 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; Loading Loading @@ -398,13 +397,49 @@ public abstract class AccessibilityService extends Service { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "SHOW_MODE_" }, value = { SHOW_MODE_AUTO, SHOW_MODE_HIDDEN SHOW_MODE_HIDDEN, SHOW_MODE_WITH_HARD_KEYBOARD }) public @interface SoftKeyboardShowMode {} /** * Allow the system to control when the soft keyboard is shown. * @see SoftKeyboardController */ public static final int SHOW_MODE_AUTO = 0; /** * Never show the soft keyboard. * @see SoftKeyboardController */ public static final int SHOW_MODE_HIDDEN = 1; /** * Allow the soft keyboard to be shown, even if a hard keyboard is connected * @see SoftKeyboardController */ public static final int SHOW_MODE_WITH_HARD_KEYBOARD = 2; /** * Mask used to cover the show modes supported in public API * @hide */ public static final int SHOW_MODE_MASK = 0x03; /** * Bit used to hold the old value of the hard IME setting to restore when a service is shut * down. * @hide */ public static final int SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE = 0x20000000; /** * Bit for show mode setting to indicate that the user has overridden the hard keyboard * behavior. * @hide */ public static final int SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN = 0x40000000; private int mConnectionId = AccessibilityInteractionClient.NO_ID; private AccessibilityServiceInfo mInfo; Loading Loading @@ -1147,7 +1182,27 @@ public abstract class AccessibilityService extends Service { } /** * Used to control and query the soft keyboard show mode. * Used to control, query, and listen for changes to the soft keyboard show mode. * <p> * Accessibility services may request to override the decisions normally made about whether or * not the soft keyboard is shown. * <p> * If multiple services make conflicting requests, the last request is honored. A service may * register a listener to find out if the mode has changed under it. * <p> * If the user takes action to override the behavior behavior requested by an accessibility * service, the user's request takes precendence, the show mode will be reset to * {@link AccessibilityService#SHOW_MODE_AUTO}, and services will no longer be able to control * that aspect of the soft keyboard's behavior. * <p> * Note: Because soft keyboards are independent apps, the framework does not have total control * over their behavior. They may choose to show themselves, or not, without regard to requests * made here. So the framework will make a best effort to deliver the behavior requested, but * cannot guarantee success. * * @see AccessibilityService#SHOW_MODE_AUTO * @see AccessibilityService#SHOW_MODE_HIDDEN * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD */ public static final class SoftKeyboardController { private final AccessibilityService mService; Loading Loading @@ -1217,7 +1272,8 @@ public abstract class AccessibilityService extends Service { * @param listener the listener to remove, must be non-null * @return {@code true} if the listener was removed, {@code false} otherwise */ public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) { public boolean removeOnShowModeChangedListener( @NonNull OnShowModeChangedListener listener) { if (mListeners == null) { return false; } Loading Loading @@ -1289,32 +1345,32 @@ public abstract class AccessibilityService extends Service { } /** * Returns the show mode of the soft keyboard. The default show mode is * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is * focused. An AccessibilityService can also request the show mode * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. * Returns the show mode of the soft keyboard. * * @return the current soft keyboard show mode * * @see AccessibilityService#SHOW_MODE_AUTO * @see AccessibilityService#SHOW_MODE_HIDDEN * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD */ @SoftKeyboardShowMode public int getShowMode() { final IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance().getConnection( mService.mConnectionId); if (connection != null) { try { return Settings.Secure.getInt(mService.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); } catch (Settings.SettingNotFoundException e) { Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e); // The settings hasn't been changed yet, so it's value is null. Return the default. return 0; return connection.getSoftKeyboardShowMode(); } catch (RemoteException re) { Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re); re.rethrowFromSystemServer(); } } return SHOW_MODE_AUTO; } /** * Sets the soft keyboard show mode. The default show mode is * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is * focused. An AccessibilityService can also request the show mode * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The * The lastto this method will be honored, regardless of any previous calls (including those * made by other AccessibilityServices). * Sets the soft keyboard show mode. * <p> * <strong>Note:</strong> If the service is not yet connected (e.g. * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the Loading @@ -1322,6 +1378,10 @@ public abstract class AccessibilityService extends Service { * * @param showMode the new show mode for the soft keyboard * @return {@code true} on success * * @see AccessibilityService#SHOW_MODE_AUTO * @see AccessibilityService#SHOW_MODE_HIDDEN * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD */ public boolean setShowMode(@SoftKeyboardShowMode int showMode) { final IAccessibilityServiceConnection connection = Loading core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,8 @@ interface IAccessibilityServiceConnection { boolean setSoftKeyboardShowMode(int showMode); int getSoftKeyboardShowMode(); void setSoftKeyboardCallbackEnabled(boolean enabled); boolean isAccessibilityButtonAvailable(); Loading core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java +4 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon return false; } public int getSoftKeyboardShowMode() { return 0; } public void setSoftKeyboardCallbackEnabled(boolean enabled) {} public boolean isAccessibilityButtonAvailable() { Loading services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +157 −48 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package com.android.server.accessibility; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_WITH_HARD_KEYBOARD; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN; import android.Manifest; import android.accessibilityservice.AccessibilityService; Loading Loading @@ -1807,7 +1813,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub updateDisplayDaltonizerLocked(userState); updateDisplayInversionLocked(userState); updateMagnificationLocked(userState); updateSoftKeyboardShowModeLocked(userState); scheduleUpdateFingerprintGestureHandling(userState); scheduleUpdateInputFilter(userState); scheduleUpdateClientsIfNeededLocked(userState); Loading Loading @@ -2001,18 +2006,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return false; } private boolean readSoftKeyboardShowModeChangedLocked(UserState userState) { final int softKeyboardShowMode = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, userState.mUserId); if (softKeyboardShowMode != userState.mSoftKeyboardShowMode) { userState.mSoftKeyboardShowMode = softKeyboardShowMode; return true; } return false; } private void updateTouchExplorationLocked(UserState userState) { boolean enabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); final int serviceCount = userState.mBoundServices.size(); Loading Loading @@ -2211,34 +2204,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return false; } private void updateSoftKeyboardShowModeLocked(UserState userState) { final int userId = userState.mUserId; // Only check whether we need to reset the soft keyboard mode if it is not set to the // default. if ((userId == mCurrentUserId) && (userState.mSoftKeyboardShowMode != 0)) { // Check whether the last AccessibilityService that changed the soft keyboard mode to // something other than the default is still enabled and, if not, remove flag and // reset to the default soft keyboard behavior. boolean serviceChangingSoftKeyboardModeIsEnabled = userState.mEnabledServices.contains(userState.mServiceChangingSoftKeyboardMode); if (!serviceChangingSoftKeyboardModeIsEnabled) { final long identity = Binder.clearCallingIdentity(); try { Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, userState.mUserId); } finally { Binder.restoreCallingIdentity(identity); } userState.mSoftKeyboardShowMode = 0; userState.mServiceChangingSoftKeyboardMode = null; notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode); } } } private void updateFingerprintGestureHandling(UserState userState) { final List<AccessibilityServiceConnection> services; synchronized (mLock) { Loading Loading @@ -2473,6 +2438,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } private void putSecureIntForUser(String key, int value, int userid) { final long identity = Binder.clearCallingIdentity(); try { Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userid); } finally { Binder.restoreCallingIdentity(identity); } } class RemoteAccessibilityConnection implements DeathRecipient { private final int mUid; private final String mPackageName; Loading Loading @@ -3683,7 +3657,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public int mLastSentClientState = -1; public int mSoftKeyboardShowMode = 0; private int mSoftKeyboardShowMode = 0; public boolean mIsNavBarMagnificationAssignedToAccessibilityButton; public ComponentName mServiceAssignedToAccessibilityButton; Loading Loading @@ -3744,7 +3718,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mServiceAssignedToAccessibilityButton = null; mIsNavBarMagnificationAssignedToAccessibilityButton = false; mIsAutoclickEnabled = false; mSoftKeyboardShowMode = 0; } public void addServiceLocked(AccessibilityServiceConnection serviceConnection) { Loading @@ -3766,6 +3739,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public void removeServiceLocked(AccessibilityServiceConnection serviceConnection) { mBoundServices.remove(serviceConnection); serviceConnection.onRemoved(); if ((mServiceChangingSoftKeyboardMode != null) && (mServiceChangingSoftKeyboardMode.equals( serviceConnection.getServiceInfo().getComponentName()))) { setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null); } // It may be possible to bind a service twice, which confuses the map. Rebuild the map // to make sure we can still reach a service mComponentNameToServiceMap.clear(); Loading @@ -3792,6 +3770,134 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public Set<ComponentName> getBindingServicesLocked() { return mBindingServices; } public int getSoftKeyboardShowMode() { return mSoftKeyboardShowMode; } /** * Set the soft keyboard mode. This mode is a bit odd, as it spans multiple settings. * The ACCESSIBILITY_SOFT_KEYBOARD_MODE setting can be checked by the rest of the system * to see if it should suppress showing the IME. The SHOW_IME_WITH_HARD_KEYBOARD setting * setting can be changed by the user, and prevents the system from suppressing the soft * keyboard when the hard keyboard is connected. The hard keyboard setting needs to defer * to the user's preference, if they have supplied one. * * @param newMode The new mode * @param requester The service requesting the change, so we can undo it when the * service stops. Set to null if something other than a service is forcing * the change. * * @return Whether or not the soft keyboard mode equals the new mode after the call */ public boolean setSoftKeyboardModeLocked(int newMode, @Nullable ComponentName requester) { if ((newMode != SHOW_MODE_AUTO) && (newMode != SHOW_MODE_HIDDEN) && (newMode != SHOW_MODE_WITH_HARD_KEYBOARD)) { Slog.w(LOG_TAG, "Invalid soft keyboard mode"); return false; } if (mSoftKeyboardShowMode == newMode) return true; if (newMode == SHOW_MODE_WITH_HARD_KEYBOARD) { if (hasUserOverriddenHardKeyboardSettingLocked()) { // The user has specified a default for this setting return false; } // Save the original value. But don't do this if the value in settings is already // the new mode. That happens when we start up after a reboot, and we don't want // to overwrite the value we had from when we first started controlling the setting. if (getSoftKeyboardValueFromSettings() != SHOW_MODE_WITH_HARD_KEYBOARD) { setOriginalHardKeyboardValue( Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0); } putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1, mUserId); } else if (mSoftKeyboardShowMode == SHOW_MODE_WITH_HARD_KEYBOARD) { putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, getOriginalHardKeyboardValue() ? 1 : 0, mUserId); } saveSoftKeyboardValueToSettings(newMode); mSoftKeyboardShowMode = newMode; mServiceChangingSoftKeyboardMode = requester; notifySoftKeyboardShowModeChangedLocked(mSoftKeyboardShowMode); return true; } /** * If the settings are inconsistent with the internal state, make the internal state * match the settings. */ public void reconcileSoftKeyboardModeWithSettingsLocked() { final ContentResolver cr = mContext.getContentResolver(); final boolean showWithHardKeyboardSettings = Settings.Secure.getInt(cr, Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0; if (mSoftKeyboardShowMode == SHOW_MODE_WITH_HARD_KEYBOARD) { if (!showWithHardKeyboardSettings) { // The user has overridden the setting. Respect that and prevent further changes // to this behavior. setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null); setUserOverridesHardKeyboardSettingLocked(); } } // If the setting and the internal state are out of sync, set both to default if (getSoftKeyboardValueFromSettings() != mSoftKeyboardShowMode) { Slog.e(LOG_TAG, "Show IME setting inconsistent with internal state. Overwriting"); setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null); putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId); } } private void setUserOverridesHardKeyboardSettingLocked() { final int softKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, softKeyboardSetting | SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN, mUserId); } private boolean hasUserOverriddenHardKeyboardSettingLocked() { final int softKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); return (softKeyboardSetting & SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN) != 0; } private void setOriginalHardKeyboardValue(boolean originalHardKeyboardValue) { final int oldSoftKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); final int newSoftKeyboardSetting = oldSoftKeyboardSetting & (~SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE) | ((originalHardKeyboardValue) ? SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE : 0); putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, newSoftKeyboardSetting, mUserId); } private void saveSoftKeyboardValueToSettings(int softKeyboardShowMode) { final int oldSoftKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); final int newSoftKeyboardSetting = oldSoftKeyboardSetting & (~SHOW_MODE_MASK) | softKeyboardShowMode; putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, newSoftKeyboardSetting, mUserId); } private int getSoftKeyboardValueFromSettings() { return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO) & SHOW_MODE_MASK; } private boolean getOriginalHardKeyboardValue() { return (Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0) & SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE) != 0; } } private final class AccessibilityContentObserver extends ContentObserver { Loading Loading @@ -3829,6 +3935,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor( Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); Loading Loading @@ -3863,6 +3972,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mHighTextContrastUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( Loading Loading @@ -3906,11 +4017,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (readHighTextContrastEnabledSettingLocked(userState)) { onUserStateChangedLocked(userState); } } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)) { if (readSoftKeyboardShowModeChangedLocked(userState)) { notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode); onUserStateChangedLocked(userState); } } else if (mAccessibilitySoftKeyboardModeUri.equals(uri) || mShowImeWithHardKeyboardUri.equals(uri)) { userState.reconcileSoftKeyboardModeWithSettingsLocked(); } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) { if (readAccessibilityShortcutSettingLocked(userState)) { onUserStateChangedLocked(userState); Loading Loading
api/current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2819,6 +2819,7 @@ package android.accessibilityservice { field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice"; field public static final int SHOW_MODE_AUTO = 0; // 0x0 field public static final int SHOW_MODE_HIDDEN = 1; // 0x1 field public static final int SHOW_MODE_WITH_HARD_KEYBOARD = 2; // 0x2 } public static abstract class AccessibilityService.GestureResultCallback {
core/java/android/accessibilityservice/AccessibilityService.java +82 −22 Original line number Diff line number Diff line Loading @@ -31,7 +31,6 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.provider.Settings; import android.util.ArrayMap; import android.util.Log; import android.util.Slog; Loading Loading @@ -398,13 +397,49 @@ public abstract class AccessibilityService extends Service { @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = { "SHOW_MODE_" }, value = { SHOW_MODE_AUTO, SHOW_MODE_HIDDEN SHOW_MODE_HIDDEN, SHOW_MODE_WITH_HARD_KEYBOARD }) public @interface SoftKeyboardShowMode {} /** * Allow the system to control when the soft keyboard is shown. * @see SoftKeyboardController */ public static final int SHOW_MODE_AUTO = 0; /** * Never show the soft keyboard. * @see SoftKeyboardController */ public static final int SHOW_MODE_HIDDEN = 1; /** * Allow the soft keyboard to be shown, even if a hard keyboard is connected * @see SoftKeyboardController */ public static final int SHOW_MODE_WITH_HARD_KEYBOARD = 2; /** * Mask used to cover the show modes supported in public API * @hide */ public static final int SHOW_MODE_MASK = 0x03; /** * Bit used to hold the old value of the hard IME setting to restore when a service is shut * down. * @hide */ public static final int SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE = 0x20000000; /** * Bit for show mode setting to indicate that the user has overridden the hard keyboard * behavior. * @hide */ public static final int SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN = 0x40000000; private int mConnectionId = AccessibilityInteractionClient.NO_ID; private AccessibilityServiceInfo mInfo; Loading Loading @@ -1147,7 +1182,27 @@ public abstract class AccessibilityService extends Service { } /** * Used to control and query the soft keyboard show mode. * Used to control, query, and listen for changes to the soft keyboard show mode. * <p> * Accessibility services may request to override the decisions normally made about whether or * not the soft keyboard is shown. * <p> * If multiple services make conflicting requests, the last request is honored. A service may * register a listener to find out if the mode has changed under it. * <p> * If the user takes action to override the behavior behavior requested by an accessibility * service, the user's request takes precendence, the show mode will be reset to * {@link AccessibilityService#SHOW_MODE_AUTO}, and services will no longer be able to control * that aspect of the soft keyboard's behavior. * <p> * Note: Because soft keyboards are independent apps, the framework does not have total control * over their behavior. They may choose to show themselves, or not, without regard to requests * made here. So the framework will make a best effort to deliver the behavior requested, but * cannot guarantee success. * * @see AccessibilityService#SHOW_MODE_AUTO * @see AccessibilityService#SHOW_MODE_HIDDEN * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD */ public static final class SoftKeyboardController { private final AccessibilityService mService; Loading Loading @@ -1217,7 +1272,8 @@ public abstract class AccessibilityService extends Service { * @param listener the listener to remove, must be non-null * @return {@code true} if the listener was removed, {@code false} otherwise */ public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) { public boolean removeOnShowModeChangedListener( @NonNull OnShowModeChangedListener listener) { if (mListeners == null) { return false; } Loading Loading @@ -1289,32 +1345,32 @@ public abstract class AccessibilityService extends Service { } /** * Returns the show mode of the soft keyboard. The default show mode is * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is * focused. An AccessibilityService can also request the show mode * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. * Returns the show mode of the soft keyboard. * * @return the current soft keyboard show mode * * @see AccessibilityService#SHOW_MODE_AUTO * @see AccessibilityService#SHOW_MODE_HIDDEN * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD */ @SoftKeyboardShowMode public int getShowMode() { final IAccessibilityServiceConnection connection = AccessibilityInteractionClient.getInstance().getConnection( mService.mConnectionId); if (connection != null) { try { return Settings.Secure.getInt(mService.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); } catch (Settings.SettingNotFoundException e) { Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e); // The settings hasn't been changed yet, so it's value is null. Return the default. return 0; return connection.getSoftKeyboardShowMode(); } catch (RemoteException re) { Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re); re.rethrowFromSystemServer(); } } return SHOW_MODE_AUTO; } /** * Sets the soft keyboard show mode. The default show mode is * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is * focused. An AccessibilityService can also request the show mode * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The * The lastto this method will be honored, regardless of any previous calls (including those * made by other AccessibilityServices). * Sets the soft keyboard show mode. * <p> * <strong>Note:</strong> If the service is not yet connected (e.g. * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the Loading @@ -1322,6 +1378,10 @@ public abstract class AccessibilityService extends Service { * * @param showMode the new show mode for the soft keyboard * @return {@code true} on success * * @see AccessibilityService#SHOW_MODE_AUTO * @see AccessibilityService#SHOW_MODE_HIDDEN * @see AccessibilityService#SHOW_MODE_WITH_HARD_KEYBOARD */ public boolean setShowMode(@SoftKeyboardShowMode int showMode) { final IAccessibilityServiceConnection connection = Loading
core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -87,6 +87,8 @@ interface IAccessibilityServiceConnection { boolean setSoftKeyboardShowMode(int showMode); int getSoftKeyboardShowMode(); void setSoftKeyboardCallbackEnabled(boolean enabled); boolean isAccessibilityButtonAvailable(); Loading
core/tests/coretests/src/android/view/accessibility/AccessibilityServiceConnectionImpl.java +4 −0 Original line number Diff line number Diff line Loading @@ -119,6 +119,10 @@ public class AccessibilityServiceConnectionImpl extends IAccessibilityServiceCon return false; } public int getSoftKeyboardShowMode() { return 0; } public void setSoftKeyboardCallbackEnabled(boolean enabled) {} public boolean isAccessibilityButtonAvailable() { Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +157 −48 Original line number Diff line number Diff line Loading @@ -16,12 +16,18 @@ package com.android.server.accessibility; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_MASK; import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY; import static android.view.accessibility.AccessibilityEvent.WINDOWS_CHANGE_ACCESSIBILITY_FOCUSED; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS; import static com.android.internal.util.FunctionalUtils.ignoreRemoteException; import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_AUTO; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HIDDEN; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_WITH_HARD_KEYBOARD; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE; import static android.accessibilityservice.AccessibilityService.SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN; import android.Manifest; import android.accessibilityservice.AccessibilityService; Loading Loading @@ -1807,7 +1813,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub updateDisplayDaltonizerLocked(userState); updateDisplayInversionLocked(userState); updateMagnificationLocked(userState); updateSoftKeyboardShowModeLocked(userState); scheduleUpdateFingerprintGestureHandling(userState); scheduleUpdateInputFilter(userState); scheduleUpdateClientsIfNeededLocked(userState); Loading Loading @@ -2001,18 +2006,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return false; } private boolean readSoftKeyboardShowModeChangedLocked(UserState userState) { final int softKeyboardShowMode = Settings.Secure.getIntForUser( mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, userState.mUserId); if (softKeyboardShowMode != userState.mSoftKeyboardShowMode) { userState.mSoftKeyboardShowMode = softKeyboardShowMode; return true; } return false; } private void updateTouchExplorationLocked(UserState userState) { boolean enabled = mUiAutomationManager.isTouchExplorationEnabledLocked(); final int serviceCount = userState.mBoundServices.size(); Loading Loading @@ -2211,34 +2204,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return false; } private void updateSoftKeyboardShowModeLocked(UserState userState) { final int userId = userState.mUserId; // Only check whether we need to reset the soft keyboard mode if it is not set to the // default. if ((userId == mCurrentUserId) && (userState.mSoftKeyboardShowMode != 0)) { // Check whether the last AccessibilityService that changed the soft keyboard mode to // something other than the default is still enabled and, if not, remove flag and // reset to the default soft keyboard behavior. boolean serviceChangingSoftKeyboardModeIsEnabled = userState.mEnabledServices.contains(userState.mServiceChangingSoftKeyboardMode); if (!serviceChangingSoftKeyboardModeIsEnabled) { final long identity = Binder.clearCallingIdentity(); try { Settings.Secure.putIntForUser(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0, userState.mUserId); } finally { Binder.restoreCallingIdentity(identity); } userState.mSoftKeyboardShowMode = 0; userState.mServiceChangingSoftKeyboardMode = null; notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode); } } } private void updateFingerprintGestureHandling(UserState userState) { final List<AccessibilityServiceConnection> services; synchronized (mLock) { Loading Loading @@ -2473,6 +2438,15 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } private void putSecureIntForUser(String key, int value, int userid) { final long identity = Binder.clearCallingIdentity(); try { Settings.Secure.putIntForUser(mContext.getContentResolver(), key, value, userid); } finally { Binder.restoreCallingIdentity(identity); } } class RemoteAccessibilityConnection implements DeathRecipient { private final int mUid; private final String mPackageName; Loading Loading @@ -3683,7 +3657,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public int mLastSentClientState = -1; public int mSoftKeyboardShowMode = 0; private int mSoftKeyboardShowMode = 0; public boolean mIsNavBarMagnificationAssignedToAccessibilityButton; public ComponentName mServiceAssignedToAccessibilityButton; Loading Loading @@ -3744,7 +3718,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mServiceAssignedToAccessibilityButton = null; mIsNavBarMagnificationAssignedToAccessibilityButton = false; mIsAutoclickEnabled = false; mSoftKeyboardShowMode = 0; } public void addServiceLocked(AccessibilityServiceConnection serviceConnection) { Loading @@ -3766,6 +3739,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public void removeServiceLocked(AccessibilityServiceConnection serviceConnection) { mBoundServices.remove(serviceConnection); serviceConnection.onRemoved(); if ((mServiceChangingSoftKeyboardMode != null) && (mServiceChangingSoftKeyboardMode.equals( serviceConnection.getServiceInfo().getComponentName()))) { setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null); } // It may be possible to bind a service twice, which confuses the map. Rebuild the map // to make sure we can still reach a service mComponentNameToServiceMap.clear(); Loading @@ -3792,6 +3770,134 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub public Set<ComponentName> getBindingServicesLocked() { return mBindingServices; } public int getSoftKeyboardShowMode() { return mSoftKeyboardShowMode; } /** * Set the soft keyboard mode. This mode is a bit odd, as it spans multiple settings. * The ACCESSIBILITY_SOFT_KEYBOARD_MODE setting can be checked by the rest of the system * to see if it should suppress showing the IME. The SHOW_IME_WITH_HARD_KEYBOARD setting * setting can be changed by the user, and prevents the system from suppressing the soft * keyboard when the hard keyboard is connected. The hard keyboard setting needs to defer * to the user's preference, if they have supplied one. * * @param newMode The new mode * @param requester The service requesting the change, so we can undo it when the * service stops. Set to null if something other than a service is forcing * the change. * * @return Whether or not the soft keyboard mode equals the new mode after the call */ public boolean setSoftKeyboardModeLocked(int newMode, @Nullable ComponentName requester) { if ((newMode != SHOW_MODE_AUTO) && (newMode != SHOW_MODE_HIDDEN) && (newMode != SHOW_MODE_WITH_HARD_KEYBOARD)) { Slog.w(LOG_TAG, "Invalid soft keyboard mode"); return false; } if (mSoftKeyboardShowMode == newMode) return true; if (newMode == SHOW_MODE_WITH_HARD_KEYBOARD) { if (hasUserOverriddenHardKeyboardSettingLocked()) { // The user has specified a default for this setting return false; } // Save the original value. But don't do this if the value in settings is already // the new mode. That happens when we start up after a reboot, and we don't want // to overwrite the value we had from when we first started controlling the setting. if (getSoftKeyboardValueFromSettings() != SHOW_MODE_WITH_HARD_KEYBOARD) { setOriginalHardKeyboardValue( Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0); } putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 1, mUserId); } else if (mSoftKeyboardShowMode == SHOW_MODE_WITH_HARD_KEYBOARD) { putSecureIntForUser(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, getOriginalHardKeyboardValue() ? 1 : 0, mUserId); } saveSoftKeyboardValueToSettings(newMode); mSoftKeyboardShowMode = newMode; mServiceChangingSoftKeyboardMode = requester; notifySoftKeyboardShowModeChangedLocked(mSoftKeyboardShowMode); return true; } /** * If the settings are inconsistent with the internal state, make the internal state * match the settings. */ public void reconcileSoftKeyboardModeWithSettingsLocked() { final ContentResolver cr = mContext.getContentResolver(); final boolean showWithHardKeyboardSettings = Settings.Secure.getInt(cr, Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, 0) != 0; if (mSoftKeyboardShowMode == SHOW_MODE_WITH_HARD_KEYBOARD) { if (!showWithHardKeyboardSettings) { // The user has overridden the setting. Respect that and prevent further changes // to this behavior. setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null); setUserOverridesHardKeyboardSettingLocked(); } } // If the setting and the internal state are out of sync, set both to default if (getSoftKeyboardValueFromSettings() != mSoftKeyboardShowMode) { Slog.e(LOG_TAG, "Show IME setting inconsistent with internal state. Overwriting"); setSoftKeyboardModeLocked(SHOW_MODE_AUTO, null); putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO, mUserId); } } private void setUserOverridesHardKeyboardSettingLocked() { final int softKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, softKeyboardSetting | SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN, mUserId); } private boolean hasUserOverriddenHardKeyboardSettingLocked() { final int softKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); return (softKeyboardSetting & SHOW_MODE_HARD_KEYBOARD_OVERRIDDEN) != 0; } private void setOriginalHardKeyboardValue(boolean originalHardKeyboardValue) { final int oldSoftKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); final int newSoftKeyboardSetting = oldSoftKeyboardSetting & (~SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE) | ((originalHardKeyboardValue) ? SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE : 0); putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, newSoftKeyboardSetting, mUserId); } private void saveSoftKeyboardValueToSettings(int softKeyboardShowMode) { final int oldSoftKeyboardSetting = Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0); final int newSoftKeyboardSetting = oldSoftKeyboardSetting & (~SHOW_MODE_MASK) | softKeyboardShowMode; putSecureIntForUser(Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, newSoftKeyboardSetting, mUserId); } private int getSoftKeyboardValueFromSettings() { return Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, SHOW_MODE_AUTO) & SHOW_MODE_MASK; } private boolean getOriginalHardKeyboardValue() { return (Settings.Secure.getInt(mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0) & SHOW_MODE_HARD_KEYBOARD_ORIGINAL_VALUE) != 0; } } private final class AccessibilityContentObserver extends ContentObserver { Loading Loading @@ -3829,6 +3935,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE); private final Uri mShowImeWithHardKeyboardUri = Settings.Secure.getUriFor( Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD); private final Uri mAccessibilityShortcutServiceIdUri = Settings.Secure.getUriFor( Settings.Secure.ACCESSIBILITY_SHORTCUT_TARGET_SERVICE); Loading Loading @@ -3863,6 +3972,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mHighTextContrastUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mShowImeWithHardKeyboardUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( mAccessibilityShortcutServiceIdUri, false, this, UserHandle.USER_ALL); contentResolver.registerContentObserver( Loading Loading @@ -3906,11 +4017,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub if (readHighTextContrastEnabledSettingLocked(userState)) { onUserStateChangedLocked(userState); } } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)) { if (readSoftKeyboardShowModeChangedLocked(userState)) { notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode); onUserStateChangedLocked(userState); } } else if (mAccessibilitySoftKeyboardModeUri.equals(uri) || mShowImeWithHardKeyboardUri.equals(uri)) { userState.reconcileSoftKeyboardModeWithSettingsLocked(); } else if (mAccessibilityShortcutServiceIdUri.equals(uri)) { if (readAccessibilityShortcutSettingLocked(userState)) { onUserStateChangedLocked(userState); Loading