diff options
9 files changed, 127 insertions, 1 deletions
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java index 33960c058baa..145dbf21699e 100644 --- a/core/java/android/hardware/input/InputSettings.java +++ b/core/java/android/hardware/input/InputSettings.java @@ -16,6 +16,8 @@ package android.hardware.input; +import static com.android.hardware.input.Flags.keyboardA11yBounceKeysFlag; + import android.Manifest; import android.annotation.FloatRange; import android.annotation.NonNull; @@ -58,6 +60,11 @@ public class InputSettings { */ public static final float DEFAULT_MAXIMUM_OBSCURING_OPACITY_FOR_TOUCH = .8f; + /** + * The maximum allowed Accessibility bounce keys threshold. + * @hide + */ + public static final int MAX_ACCESSIBILITY_BOUNCE_KEYS_THRESHOLD_MILLIS = 5000; private InputSettings() { } @@ -328,4 +335,70 @@ public class InputSettings { .getBoolean(com.android.internal.R.bool.config_enableStylusPointerIcon) || InputProperties.force_enable_stylus_pointer_icon().orElse(false); } + + /** + * Whether Accessibility bounce keys is enabled. + * + * <p> + * ‘Bounce keys’ is an accessibility feature to aid users who have physical disabilities, + * that allows the user to configure the device to ignore rapid, repeated keypresses of the + * same key. + * </p> + * + * @hide + */ + public static boolean isAccessibilityBounceKeysEnabled(@NonNull Context context) { + return getAccessibilityBounceKeysThreshold(context) != 0; + } + + /** + * Get Accessibility bounce keys threshold duration in milliseconds. + * + * <p> + * ‘Bounce keys’ is an accessibility feature to aid users who have physical disabilities, + * that allows the user to configure the device to ignore rapid, repeated keypresses of the + * same key. + * </p> + * + * @hide + */ + public static int getAccessibilityBounceKeysThreshold(@NonNull Context context) { + if (!keyboardA11yBounceKeysFlag()) { + return 0; + } + return Settings.System.getIntForUser(context.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS, 0, UserHandle.USER_CURRENT); + } + + /** + * Set Accessibility bounce keys threshold duration in milliseconds. + * @param thresholdTimeMillis time duration for which a key down will be ignored after a + * previous key up for the same key on the same device between 0 and + * {@link MAX_ACCESSIBILITY_BOUNCE_KEYS_THRESHOLD_MILLIS} + * + * <p> + * ‘Bounce keys’ is an accessibility feature to aid users who have physical disabilities, + * that allows the user to configure the device to ignore rapid, repeated keypresses of the + * same key. + * </p> + * + * @hide + */ + @RequiresPermission(Manifest.permission.WRITE_SETTINGS) + public static void setAccessibilityBounceKeysThreshold(@NonNull Context context, + int thresholdTimeMillis) { + if (!keyboardA11yBounceKeysFlag()) { + return; + } + if (thresholdTimeMillis < 0 + || thresholdTimeMillis > MAX_ACCESSIBILITY_BOUNCE_KEYS_THRESHOLD_MILLIS) { + throw new IllegalArgumentException( + "Provided Bounce keys threshold should be in range [0, " + + MAX_ACCESSIBILITY_BOUNCE_KEYS_THRESHOLD_MILLIS + "]"); + } + Settings.System.putIntForUser(context.getContentResolver(), + Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS, thresholdTimeMillis, + UserHandle.USER_CURRENT); + } + } diff --git a/core/java/android/hardware/input/input_framework.aconfig b/core/java/android/hardware/input/input_framework.aconfig index 97c45a76ade9..362fe78b14b8 100644 --- a/core/java/android/hardware/input/input_framework.aconfig +++ b/core/java/android/hardware/input/input_framework.aconfig @@ -17,6 +17,12 @@ flag { bug: "294546335" } +flag { + namespace: "input_native" + name: "keyboard_a11y_bounce_keys_flag" + description: "Controls if the bounce keys accessibility feature for physical keyboard is available to the user" + bug: "294546335" +} flag { namespace: "input_native" diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 9c27f19b349a..2ed994b503c9 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -7791,6 +7791,16 @@ public final class Settings { public static final String SHOW_IME_WITH_HARD_KEYBOARD = "show_ime_with_hard_keyboard"; /** + * Whether to enable bounce keys for Physical Keyboard accessibility. + * + * If set to non-zero value, any key press on physical keyboard within the provided + * threshold duration (in milliseconds) of the same key, will be ignored. + * + * @hide + */ + public static final String ACCESSIBILITY_BOUNCE_KEYS = "accessibility_bounce_keys"; + + /** * Whether stylus button presses are disabled. This is a boolean that * determines if stylus buttons are ignored. * @@ -12126,6 +12136,7 @@ public final class Settings { CLONE_TO_MANAGED_PROFILE.add(LOCATION_CHANGER); CLONE_TO_MANAGED_PROFILE.add(LOCATION_MODE); CLONE_TO_MANAGED_PROFILE.add(SHOW_IME_WITH_HARD_KEYBOARD); + CLONE_TO_MANAGED_PROFILE.add(ACCESSIBILITY_BOUNCE_KEYS); CLONE_TO_MANAGED_PROFILE.add(NOTIFICATION_BUBBLES); } diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java index 5c09b1692453..460d9f040e68 100644 --- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java +++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java @@ -73,6 +73,7 @@ public class SecureSettings { Settings.Secure.TTS_ENABLED_PLUGINS, Settings.Secure.TTS_DEFAULT_LOCALE, Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD, + Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS, Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, // moved to global Settings.Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, // moved to global Settings.Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, // moved to global diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java index b0169a115ec5..6c48110ef10b 100644 --- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java +++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java @@ -119,6 +119,7 @@ public class SecureSettingsValidators { VALIDATORS.put(Secure.TTS_ENABLED_PLUGINS, new PackageNameListValidator(" ")); VALIDATORS.put(Secure.TTS_DEFAULT_LOCALE, TTS_LIST_VALIDATOR); VALIDATORS.put(Secure.SHOW_IME_WITH_HARD_KEYBOARD, BOOLEAN_VALIDATOR); + VALIDATORS.put(Secure.ACCESSIBILITY_BOUNCE_KEYS, ANY_INTEGER_VALIDATOR); VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, BOOLEAN_VALIDATOR); VALIDATORS.put(Secure.WIFI_NETWORKS_AVAILABLE_REPEAT_DELAY, NON_NEGATIVE_INTEGER_VALIDATOR); VALIDATORS.put(Secure.WIFI_NUM_OPEN_NETWORKS_KEPT, NON_NEGATIVE_INTEGER_VALIDATOR); diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java index 3fc9594965a2..972f85793556 100644 --- a/services/core/java/com/android/server/input/InputManagerService.java +++ b/services/core/java/com/android/server/input/InputManagerService.java @@ -3504,6 +3504,13 @@ public class InputManagerService extends IInputManager.Stub wm.addView(view, lp); } + /** + * Sets Accessibility bounce keys threshold in milliseconds. + */ + public void setAccessibilityBounceKeysThreshold(int thresholdTimeMs) { + mNative.setAccessibilityBounceKeysThreshold(thresholdTimeMs); + } + interface KeyboardBacklightControllerInterface { default void incrementKeyboardBacklight(int deviceId) {} default void decrementKeyboardBacklight(int deviceId) {} diff --git a/services/core/java/com/android/server/input/InputSettingsObserver.java b/services/core/java/com/android/server/input/InputSettingsObserver.java index 8e0289ef1b43..0012eab11277 100644 --- a/services/core/java/com/android/server/input/InputSettingsObserver.java +++ b/services/core/java/com/android/server/input/InputSettingsObserver.java @@ -85,7 +85,9 @@ class InputSettingsObserver extends ContentObserver { Map.entry(Settings.Secure.getUriFor(Settings.Secure.KEY_REPEAT_DELAY_MS), (reason) -> updateKeyRepeatInfo()), Map.entry(Settings.System.getUriFor(Settings.System.SHOW_ROTARY_INPUT), - (reason) -> updateShowRotaryInput())); + (reason) -> updateShowRotaryInput()), + Map.entry(Settings.System.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS), + (reason) -> updateAccessibilityBounceKeys())); } /** @@ -216,4 +218,9 @@ class InputSettingsObserver extends ContentObserver { } mNative.setMaximumObscuringOpacityForTouch(opacity); } + + private void updateAccessibilityBounceKeys() { + mService.setAccessibilityBounceKeysThreshold( + InputSettings.getAccessibilityBounceKeysThreshold(mContext)); + } } diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java index 620cde59fb52..49bbe9a7655c 100644 --- a/services/core/java/com/android/server/input/NativeInputManagerService.java +++ b/services/core/java/com/android/server/input/NativeInputManagerService.java @@ -246,6 +246,11 @@ interface NativeInputManagerService { */ void sysfsNodeChanged(String sysfsNodePath); + /** + * Notify if Accessibility bounce keys threshold is changed from InputSettings. + */ + void setAccessibilityBounceKeysThreshold(int thresholdTimeMs); + /** The native implementation of InputManagerService methods. */ class NativeImpl implements NativeInputManagerService { /** Pointer to native input manager service object, used by native code. */ @@ -500,5 +505,8 @@ interface NativeInputManagerService { @Override public native void sysfsNodeChanged(String sysfsNodePath); + + @Override + public native void setAccessibilityBounceKeysThreshold(int thresholdTimeMs); } } diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 6f65965b8aa8..bc05e77171bd 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -88,6 +88,7 @@ namespace input_flags = com::android::input::flags; namespace android { static const bool ENABLE_POINTER_CHOREOGRAPHER = input_flags::enable_pointer_choreographer(); +static const bool ENABLE_INPUT_FILTER_RUST = input_flags::enable_input_filter_rust_impl(); // The exponent used to calculate the pointer speed scaling factor. // The scaling factor is calculated as 2 ^ (speed * exponent), @@ -2737,6 +2738,15 @@ static void nativeSetStylusPointerIconEnabled(JNIEnv* env, jobject nativeImplObj im->setStylusPointerIconEnabled(enabled); } +static void nativeSetAccessibilityBounceKeysThreshold(JNIEnv* env, jobject nativeImplObj, + jint thresholdTimeMs) { + NativeInputManager* im = getNativeInputManager(env, nativeImplObj); + if (ENABLE_INPUT_FILTER_RUST) { + im->getInputManager()->getInputFilter().setAccessibilityBounceKeysThreshold( + static_cast<nsecs_t>(thresholdTimeMs) * 1000000); + } +} + // ---------------------------------------------------------------------------- static const JNINativeMethod gInputManagerMethods[] = { @@ -2836,6 +2846,8 @@ static const JNINativeMethod gInputManagerMethods[] = { (void*)nativeSetStylusButtonMotionEventsEnabled}, {"getMouseCursorPosition", "()[F", (void*)nativeGetMouseCursorPosition}, {"setStylusPointerIconEnabled", "(Z)V", (void*)nativeSetStylusPointerIconEnabled}, + {"setAccessibilityBounceKeysThreshold", "(I)V", + (void*)nativeSetAccessibilityBounceKeysThreshold}, }; #define FIND_CLASS(var, className) \ |