Add Sticky keys A11Y feature flag and Setting

DD: go/pk_accessibility
Bug: 294546335
Test: None
Change-Id: Ib7812876b7201188704c21ad05150ecc92ed0b05
diff --git a/core/java/android/hardware/input/InputSettings.java b/core/java/android/hardware/input/InputSettings.java
index 145dbf2..cb9c333 100644
--- a/core/java/android/hardware/input/InputSettings.java
+++ b/core/java/android/hardware/input/InputSettings.java
@@ -17,6 +17,7 @@
 package android.hardware.input;
 
 import static com.android.hardware.input.Flags.keyboardA11yBounceKeysFlag;
+import static com.android.hardware.input.Flags.keyboardA11yStickyKeysFlag;
 
 import android.Manifest;
 import android.annotation.FloatRange;
@@ -401,4 +402,49 @@
                 UserHandle.USER_CURRENT);
     }
 
+    /**
+     * Whether Accessibility sticky keys is enabled.
+     *
+     * <p>
+     * 'Sticky keys' is an accessibility feature that assists users who have physical
+     * disabilities or help users reduce repetitive strain injury. It serializes keystrokes
+     * instead of pressing multiple keys at a time, allowing the user to press and release a
+     * modifier key, such as Shift, Ctrl, Alt, or any other modifier key, and have it remain
+     * active until any other key is pressed.
+     * </p>
+     *
+     * @hide
+     */
+    public static boolean isAccessibilityStickyKeysEnabled(@NonNull Context context) {
+        if (!keyboardA11yStickyKeysFlag()) {
+            return false;
+        }
+        return Settings.System.getIntForUser(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_STICKY_KEYS, 0, UserHandle.USER_CURRENT) != 0;
+    }
+
+    /**
+     * Set Accessibility sticky keys feature enabled/disabled.
+     *
+     *  <p>
+     * 'Sticky keys' is an accessibility feature that assists users who have physical
+     * disabilities or help users reduce repetitive strain injury. It serializes keystrokes
+     * instead of pressing multiple keys at a time, allowing the user to press and release a
+     * modifier key, such as Shift, Ctrl, Alt, or any other modifier key, and have it remain
+     * active until any other key is pressed.
+     * </p>
+     *
+     * @hide
+     */
+    @RequiresPermission(Manifest.permission.WRITE_SETTINGS)
+    public static void setAccessibilityStickyKeysEnabled(@NonNull Context context,
+            boolean enabled) {
+        if (!keyboardA11yStickyKeysFlag()) {
+            return;
+        }
+        Settings.System.putIntForUser(context.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_STICKY_KEYS, enabled ? 1 : 0,
+                UserHandle.USER_CURRENT);
+    }
+
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2cc56d8..290ae4a 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7801,6 +7801,15 @@
         public static final String ACCESSIBILITY_BOUNCE_KEYS = "accessibility_bounce_keys";
 
         /**
+         * Whether to enable sticky keys for Physical Keyboard accessibility.
+         *
+         * This is a boolean value that determines if Sticky keys feature is enabled.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_STICKY_KEYS = "accessibility_sticky_keys";
+
+        /**
          * Whether stylus button presses are disabled. This is a boolean that
          * determines if stylus buttons are ignored.
          *
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index ec456e0..2167a8a 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -74,6 +74,7 @@
         Settings.Secure.TTS_DEFAULT_LOCALE,
         Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD,
         Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS,
+        Settings.Secure.ACCESSIBILITY_STICKY_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 5ad14ce..868623f 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -120,6 +120,7 @@
         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.ACCESSIBILITY_STICKY_KEYS, BOOLEAN_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 972f857..24e23003 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -3511,6 +3511,13 @@
         mNative.setAccessibilityBounceKeysThreshold(thresholdTimeMs);
     }
 
+    /**
+     * Sets whether Accessibility sticky keys is enabled.
+     */
+    public void setAccessibilityStickyKeysEnabled(boolean enabled) {
+        mNative.setAccessibilityStickyKeysEnabled(enabled);
+    }
+
     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 0012eab1..c9668a2 100644
--- a/services/core/java/com/android/server/input/InputSettingsObserver.java
+++ b/services/core/java/com/android/server/input/InputSettingsObserver.java
@@ -87,7 +87,9 @@
                 Map.entry(Settings.System.getUriFor(Settings.System.SHOW_ROTARY_INPUT),
                         (reason) -> updateShowRotaryInput()),
                 Map.entry(Settings.System.getUriFor(Settings.Secure.ACCESSIBILITY_BOUNCE_KEYS),
-                        (reason) -> updateAccessibilityBounceKeys()));
+                        (reason) -> updateAccessibilityBounceKeys()),
+                Map.entry(Settings.System.getUriFor(Settings.Secure.ACCESSIBILITY_STICKY_KEYS),
+                        (reason) -> updateAccessibilityStickyKeys()));
     }
 
     /**
@@ -223,4 +225,9 @@
         mService.setAccessibilityBounceKeysThreshold(
                 InputSettings.getAccessibilityBounceKeysThreshold(mContext));
     }
+
+    private void updateAccessibilityStickyKeys() {
+        mService.setAccessibilityStickyKeysEnabled(
+                InputSettings.isAccessibilityStickyKeysEnabled(mContext));
+    }
 }
diff --git a/services/core/java/com/android/server/input/NativeInputManagerService.java b/services/core/java/com/android/server/input/NativeInputManagerService.java
index 49bbe9a..829b660 100644
--- a/services/core/java/com/android/server/input/NativeInputManagerService.java
+++ b/services/core/java/com/android/server/input/NativeInputManagerService.java
@@ -251,6 +251,11 @@
      */
     void setAccessibilityBounceKeysThreshold(int thresholdTimeMs);
 
+    /**
+     * Notify if Accessibility sticky keys is enabled/disabled from InputSettings.
+     */
+    void setAccessibilityStickyKeysEnabled(boolean enabled);
+
     /** The native implementation of InputManagerService methods. */
     class NativeImpl implements NativeInputManagerService {
         /** Pointer to native input manager service object, used by native code. */
@@ -508,5 +513,8 @@
 
         @Override
         public native void setAccessibilityBounceKeysThreshold(int thresholdTimeMs);
+
+        @Override
+        public native void setAccessibilityStickyKeysEnabled(boolean enabled);
     }
 }
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index bc05e77..0dd0564 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -2747,6 +2747,14 @@
     }
 }
 
+static void nativeSetAccessibilityStickyKeysEnabled(JNIEnv* env, jobject nativeImplObj,
+                                                    jboolean enabled) {
+    NativeInputManager* im = getNativeInputManager(env, nativeImplObj);
+    if (ENABLE_INPUT_FILTER_RUST) {
+        im->getInputManager()->getInputFilter().setAccessibilityStickyKeysEnabled(enabled);
+    }
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gInputManagerMethods[] = {
@@ -2848,6 +2856,8 @@
         {"setStylusPointerIconEnabled", "(Z)V", (void*)nativeSetStylusPointerIconEnabled},
         {"setAccessibilityBounceKeysThreshold", "(I)V",
          (void*)nativeSetAccessibilityBounceKeysThreshold},
+        {"setAccessibilityStickyKeysEnabled", "(Z)V",
+         (void*)nativeSetAccessibilityStickyKeysEnabled},
 };
 
 #define FIND_CLASS(var, className) \