Add bounce keys input filter

DD: go/pk_accessibility
Bug: 294546335
Test: TEST=libinputflinger_rs_test; m $TEST && $ANDROID_HOST_OUT/nativetest64/$TEST/$TEST
Change-Id: Id38b3d0fc830d16327b36d1b4376c0a66b6551aa
diff --git a/services/inputflinger/rust/Android.bp b/services/inputflinger/rust/Android.bp
index 2775bcc..2803805 100644
--- a/services/inputflinger/rust/Android.bp
+++ b/services/inputflinger/rust/Android.bp
@@ -38,6 +38,7 @@
     rustlibs: [
         "libcxx",
         "com.android.server.inputflinger-rust",
+        "android.hardware.input.common-V1-rust",
         "libbinder_rs",
         "liblog_rust",
         "liblogger",
diff --git a/services/inputflinger/rust/bounce_keys_filter.rs b/services/inputflinger/rust/bounce_keys_filter.rs
new file mode 100644
index 0000000..894b881
--- /dev/null
+++ b/services/inputflinger/rust/bounce_keys_filter.rs
@@ -0,0 +1,289 @@
+/*
+ * Copyright 2023 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.
+ */
+
+//! Bounce keys input filter implementation.
+//! 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 key presses of the same key.
+use crate::input_filter::Filter;
+
+use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
+use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
+    DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
+};
+use log::debug;
+use std::collections::{HashMap, HashSet};
+
+#[derive(Debug)]
+struct LastUpKeyEvent {
+    keycode: i32,
+    event_time: i64,
+}
+
+#[derive(Debug)]
+struct BlockedEvent {
+    device_id: i32,
+    keycode: i32,
+}
+
+pub struct BounceKeysFilter {
+    next: Box<dyn Filter + Send + Sync>,
+    key_event_map: HashMap<i32, LastUpKeyEvent>,
+    blocked_events: Vec<BlockedEvent>,
+    external_devices: HashSet<i32>,
+    bounce_key_threshold_ns: i64,
+}
+
+impl BounceKeysFilter {
+    /// Create a new BounceKeysFilter instance.
+    pub fn new(
+        next: Box<dyn Filter + Send + Sync>,
+        bounce_key_threshold_ns: i64,
+    ) -> BounceKeysFilter {
+        Self {
+            next,
+            key_event_map: HashMap::new(),
+            blocked_events: Vec::new(),
+            external_devices: HashSet::new(),
+            bounce_key_threshold_ns,
+        }
+    }
+}
+
+impl Filter for BounceKeysFilter {
+    fn notify_key(&mut self, event: &KeyEvent) {
+        if !(self.external_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) {
+            self.next.notify_key(event);
+            return;
+        }
+        match event.action {
+            KeyEventAction::DOWN => match self.key_event_map.get(&event.deviceId) {
+                None => self.next.notify_key(event),
+                Some(last_up_event) => {
+                    if event.keyCode == last_up_event.keycode
+                        && event.eventTime < last_up_event.event_time + self.bounce_key_threshold_ns
+                    {
+                        self.blocked_events.push(BlockedEvent {
+                            device_id: event.deviceId,
+                            keycode: event.keyCode,
+                        });
+                        debug!("Event dropped because last up was too recent");
+                    } else {
+                        self.key_event_map.remove(&event.deviceId);
+                        self.next.notify_key(event);
+                    }
+                }
+            },
+            KeyEventAction::UP => {
+                self.key_event_map.insert(
+                    event.deviceId,
+                    LastUpKeyEvent { keycode: event.keyCode, event_time: event.eventTime },
+                );
+                if let Some(index) = self.blocked_events.iter().position(|blocked_event| {
+                    blocked_event.device_id == event.deviceId
+                        && blocked_event.keycode == event.keyCode
+                }) {
+                    self.blocked_events.remove(index);
+                    debug!("Event dropped because key down was already dropped");
+                } else {
+                    self.next.notify_key(event);
+                }
+            }
+            _ => (),
+        }
+    }
+
+    fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]) {
+        self.key_event_map.retain(|id, _| device_infos.iter().any(|x| *id == x.deviceId));
+        self.blocked_events.retain(|blocked_event| {
+            device_infos.iter().any(|x| blocked_event.device_id == x.deviceId)
+        });
+        self.external_devices.clear();
+        for device_info in device_infos {
+            if device_info.external {
+                self.external_devices.insert(device_info.deviceId);
+            }
+        }
+        self.next.notify_devices_changed(device_infos);
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::bounce_keys_filter::BounceKeysFilter;
+    use crate::input_filter::{test_filter::TestFilter, Filter};
+    use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
+    use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
+        DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction,
+    };
+
+    static BASE_KEY_EVENT: KeyEvent = KeyEvent {
+        id: 1,
+        deviceId: 1,
+        downTime: 0,
+        readTime: 0,
+        eventTime: 0,
+        source: Source::KEYBOARD,
+        displayId: 0,
+        policyFlags: 0,
+        action: KeyEventAction::DOWN,
+        flags: 0,
+        keyCode: 1,
+        scanCode: 0,
+        metaState: 0,
+    };
+
+    #[test]
+    fn test_is_notify_key_for_external_keyboard() {
+        let mut next = TestFilter::new();
+        let mut filter = setup_filter_with_external_device(
+            Box::new(next.clone()),
+            1,   /* device_id */
+            100, /* threshold */
+        );
+
+        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        let event = KeyEvent { action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        next.clear();
+        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert!(next.last_event().is_none());
+
+        let event = KeyEvent { eventTime: 100, action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert!(next.last_event().is_none());
+
+        let event = KeyEvent { eventTime: 200, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+    }
+
+    #[test]
+    fn test_is_notify_key_doesnt_block_for_internal_keyboard() {
+        let next = TestFilter::new();
+        let mut filter = setup_filter_with_internal_device(
+            Box::new(next.clone()),
+            1,   /* device_id */
+            100, /* threshold */
+        );
+
+        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        let event = KeyEvent { action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+    }
+
+    #[test]
+    fn test_is_notify_key_doesnt_block_for_external_stylus() {
+        let next = TestFilter::new();
+        let mut filter = setup_filter_with_external_device(
+            Box::new(next.clone()),
+            1,   /* device_id */
+            100, /* threshold */
+        );
+
+        let event =
+            KeyEvent { action: KeyEventAction::DOWN, source: Source::STYLUS, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        let event =
+            KeyEvent { action: KeyEventAction::UP, source: Source::STYLUS, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        let event =
+            KeyEvent { action: KeyEventAction::DOWN, source: Source::STYLUS, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+    }
+
+    #[test]
+    fn test_is_notify_key_for_multiple_external_keyboards() {
+        let mut next = TestFilter::new();
+        let mut filter = setup_filter_with_devices(
+            Box::new(next.clone()),
+            &[
+                DeviceInfo { deviceId: 1, external: true },
+                DeviceInfo { deviceId: 2, external: true },
+            ],
+            100, /* threshold */
+        );
+
+        let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        let event = KeyEvent { deviceId: 1, action: KeyEventAction::UP, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+
+        next.clear();
+        let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert!(next.last_event().is_none());
+
+        let event = KeyEvent { deviceId: 2, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT };
+        filter.notify_key(&event);
+        assert_eq!(next.last_event().unwrap(), event);
+    }
+
+    fn setup_filter_with_external_device(
+        next: Box<dyn Filter + Send + Sync>,
+        device_id: i32,
+        threshold: i64,
+    ) -> BounceKeysFilter {
+        setup_filter_with_devices(
+            next,
+            &[DeviceInfo { deviceId: device_id, external: true }],
+            threshold,
+        )
+    }
+
+    fn setup_filter_with_internal_device(
+        next: Box<dyn Filter + Send + Sync>,
+        device_id: i32,
+        threshold: i64,
+    ) -> BounceKeysFilter {
+        setup_filter_with_devices(
+            next,
+            &[DeviceInfo { deviceId: device_id, external: false }],
+            threshold,
+        )
+    }
+
+    fn setup_filter_with_devices(
+        next: Box<dyn Filter + Send + Sync>,
+        devices: &[DeviceInfo],
+        threshold: i64,
+    ) -> BounceKeysFilter {
+        let mut filter = BounceKeysFilter::new(next, threshold);
+        filter.notify_devices_changed(devices);
+        filter
+    }
+}
diff --git a/services/inputflinger/rust/input_filter.rs b/services/inputflinger/rust/input_filter.rs
index 5851877..340ff8e 100644
--- a/services/inputflinger/rust/input_filter.rs
+++ b/services/inputflinger/rust/input_filter.rs
@@ -16,17 +16,39 @@
 
 //! InputFilter manages all the filtering components that can intercept events, modify the events,
 //! block events, etc depending on the situation. This will be used support Accessibility features
-//! like Slow keys, Bounce keys, etc.
+//! like Sticky keys, Slow keys, Bounce keys, etc.
 
 use binder::{Interface, Strong};
 use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
+    DeviceInfo::DeviceInfo,
     IInputFilter::{IInputFilter, IInputFilterCallbacks::IInputFilterCallbacks},
+    InputFilterConfiguration::InputFilterConfiguration,
     KeyEvent::KeyEvent,
 };
 
+use crate::bounce_keys_filter::BounceKeysFilter;
+use log::{error, info};
+use std::sync::{Arc, Mutex, RwLock};
+
+/// Interface for all the sub input filters
+pub trait Filter {
+    fn notify_key(&mut self, event: &KeyEvent);
+    fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]);
+}
+
+struct InputFilterState {
+    first_filter: Box<dyn Filter + Send + Sync>,
+    enabled: bool,
+}
+
 /// The rust implementation of InputFilter
 pub struct InputFilter {
-    callbacks: Strong<dyn IInputFilterCallbacks>,
+    // In order to have multiple immutable references to the callbacks that is thread safe need to
+    // wrap the callbacks in Arc<RwLock<...>>
+    callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>,
+    // Access to mutable references to mutable state (includes access to filters, enabled, etc.) is
+    // guarded by Mutex for thread safety
+    state: Mutex<InputFilterState>,
 }
 
 impl Interface for InputFilter {}
@@ -34,35 +56,87 @@
 impl InputFilter {
     /// Create a new InputFilter instance.
     pub fn new(callbacks: Strong<dyn IInputFilterCallbacks>) -> InputFilter {
-        Self { callbacks }
+        let ref_callbacks = Arc::new(RwLock::new(callbacks));
+        let base_filter = Box::new(BaseFilter::new(ref_callbacks.clone()));
+        Self::create_input_filter(base_filter, ref_callbacks)
+    }
+
+    /// Create test instance of InputFilter
+    fn create_input_filter(
+        first_filter: Box<dyn Filter + Send + Sync>,
+        callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>,
+    ) -> InputFilter {
+        Self { callbacks, state: Mutex::new(InputFilterState { first_filter, enabled: false }) }
     }
 }
 
 impl IInputFilter for InputFilter {
     fn isEnabled(&self) -> binder::Result<bool> {
-        // TODO(b/294546335): Return true if any filters are to be applied, false otherwise
-        Result::Ok(false)
+        Result::Ok(self.state.lock().unwrap().enabled)
     }
+
     fn notifyKey(&self, event: &KeyEvent) -> binder::Result<()> {
-        // TODO(b/294546335): Handle key event and modify key events here
-        // Just send back the event without processing for now.
-        let _ = self.callbacks.sendKeyEvent(event);
+        let first_filter = &mut self.state.lock().unwrap().first_filter;
+        first_filter.notify_key(event);
         Result::Ok(())
     }
-    fn notifyInputDevicesChanged(&self, _device_ids: &[i32]) -> binder::Result<()> {
-        // TODO(b/294546335): Update data based on device changes here
+
+    fn notifyInputDevicesChanged(&self, device_infos: &[DeviceInfo]) -> binder::Result<()> {
+        let first_filter = &mut self.state.lock().unwrap().first_filter;
+        first_filter.notify_devices_changed(device_infos);
         Result::Ok(())
     }
+
+    fn notifyConfigurationChanged(&self, config: &InputFilterConfiguration) -> binder::Result<()> {
+        let mut state = self.state.lock().unwrap();
+        let mut first_filter: Box<dyn Filter + Send + Sync> =
+            Box::new(BaseFilter::new(self.callbacks.clone()));
+        if config.bounceKeysThresholdNs > 0 {
+            first_filter =
+                Box::new(BounceKeysFilter::new(first_filter, config.bounceKeysThresholdNs));
+            state.enabled = true;
+            info!("Bounce keys filter is installed");
+        }
+        state.first_filter = first_filter;
+        Result::Ok(())
+    }
+}
+
+struct BaseFilter {
+    callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>,
+}
+
+impl BaseFilter {
+    fn new(callbacks: Arc<RwLock<Strong<dyn IInputFilterCallbacks>>>) -> BaseFilter {
+        Self { callbacks }
+    }
+}
+
+impl Filter for BaseFilter {
+    fn notify_key(&mut self, event: &KeyEvent) {
+        match self.callbacks.read().unwrap().sendKeyEvent(event) {
+            Ok(_) => (),
+            _ => error!("Failed to send key event back to native C++"),
+        }
+    }
+
+    fn notify_devices_changed(&mut self, _device_infos: &[DeviceInfo]) {
+        // do nothing
+    }
 }
 
 #[cfg(test)]
 mod tests {
-    use crate::input_filter::InputFilter;
+    use crate::input_filter::{test_filter::TestFilter, Filter, InputFilter};
+    use android_hardware_input_common::aidl::android::hardware::input::common::Source::Source;
     use binder::{Interface, Strong};
     use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
-        IInputFilter::IInputFilter, IInputFilter::IInputFilterCallbacks::IInputFilterCallbacks,
-        KeyEvent::KeyEvent,
+        DeviceInfo::DeviceInfo, IInputFilter::IInputFilter,
+        IInputFilter::IInputFilterCallbacks::IInputFilterCallbacks,
+        InputFilterConfiguration::InputFilterConfiguration, KeyEvent::KeyEvent,
+        KeyEventAction::KeyEventAction,
     };
+    use std::sync::{Arc, RwLock};
 
     struct FakeCallbacks {}
 
@@ -75,31 +149,60 @@
     }
 
     #[test]
-    fn test_is_enabled() {
+    fn test_not_enabled_with_default_filter() {
         let fake_callbacks: Strong<dyn IInputFilterCallbacks> =
             Strong::new(Box::new(FakeCallbacks {}));
-        let filter: Box<dyn IInputFilter> = Box::new(InputFilter::new(fake_callbacks));
-        let result = filter.isEnabled();
+        let input_filter = InputFilter::new(fake_callbacks);
+        let result = input_filter.isEnabled();
         assert!(result.is_ok());
         assert!(!result.unwrap());
     }
 
     #[test]
-    fn test_notify_key() {
+    fn test_notify_key_with_no_filters() {
         let fake_callbacks: Strong<dyn IInputFilterCallbacks> =
             Strong::new(Box::new(FakeCallbacks {}));
-        let filter: Box<dyn IInputFilter> = Box::new(InputFilter::new(fake_callbacks));
+        let input_filter = InputFilter::new(fake_callbacks);
         let event = create_key_event();
-        assert!(filter.notifyKey(&event).is_ok());
+        assert!(input_filter.notifyKey(&event).is_ok());
+    }
+
+    #[test]
+    fn test_notify_key_with_filter() {
+        let test_filter = TestFilter::new();
+        let input_filter = create_input_filter(Box::new(test_filter.clone()));
+        let event = create_key_event();
+        assert!(input_filter.notifyKey(&event).is_ok());
+        assert_eq!(test_filter.last_event().unwrap(), event);
     }
 
     #[test]
     fn test_notify_devices_changed() {
+        let test_filter = TestFilter::new();
+        let input_filter = create_input_filter(Box::new(test_filter.clone()));
+        assert!(input_filter
+            .notifyInputDevicesChanged(&[DeviceInfo { deviceId: 0, external: true }])
+            .is_ok());
+        assert!(test_filter.is_device_changed_called());
+    }
+
+    #[test]
+    fn test_notify_configuration_changed_enabled_bounce_keys() {
         let fake_callbacks: Strong<dyn IInputFilterCallbacks> =
             Strong::new(Box::new(FakeCallbacks {}));
-        let filter: Box<dyn IInputFilter> = Box::new(InputFilter::new(fake_callbacks));
-        let result = filter.notifyInputDevicesChanged(&[0]);
+        let input_filter = InputFilter::new(fake_callbacks);
+        let result = input_filter
+            .notifyConfigurationChanged(&InputFilterConfiguration { bounceKeysThresholdNs: 100 });
         assert!(result.is_ok());
+        let result = input_filter.isEnabled();
+        assert!(result.is_ok());
+        assert!(result.unwrap());
+    }
+
+    fn create_input_filter(filter: Box<dyn Filter + Send + Sync>) -> InputFilter {
+        let fake_callbacks: Strong<dyn IInputFilterCallbacks> =
+            Strong::new(Box::new(FakeCallbacks {}));
+        InputFilter::create_input_filter(filter, Arc::new(RwLock::new(fake_callbacks)))
     }
 
     fn create_key_event() -> KeyEvent {
@@ -109,10 +212,10 @@
             downTime: 0,
             readTime: 0,
             eventTime: 0,
-            source: 0,
+            source: Source::KEYBOARD,
             displayId: 0,
             policyFlags: 0,
-            action: 0,
+            action: KeyEventAction::DOWN,
             flags: 0,
             keyCode: 0,
             scanCode: 0,
@@ -120,3 +223,52 @@
         }
     }
 }
+
+#[cfg(test)]
+pub mod test_filter {
+    use crate::input_filter::Filter;
+    use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{
+        DeviceInfo::DeviceInfo, KeyEvent::KeyEvent,
+    };
+    use std::sync::{Arc, RwLock, RwLockWriteGuard};
+
+    #[derive(Default)]
+    struct TestFilterInner {
+        is_device_changed_called: bool,
+        last_event: Option<KeyEvent>,
+    }
+
+    #[derive(Default, Clone)]
+    pub struct TestFilter(Arc<RwLock<TestFilterInner>>);
+
+    impl TestFilter {
+        pub fn new() -> Self {
+            Default::default()
+        }
+
+        fn inner(&mut self) -> RwLockWriteGuard<'_, TestFilterInner> {
+            self.0.write().unwrap()
+        }
+
+        pub fn last_event(&self) -> Option<KeyEvent> {
+            self.0.read().unwrap().last_event
+        }
+
+        pub fn clear(&mut self) {
+            self.inner().last_event = None
+        }
+
+        pub fn is_device_changed_called(&self) -> bool {
+            self.0.read().unwrap().is_device_changed_called
+        }
+    }
+
+    impl Filter for TestFilter {
+        fn notify_key(&mut self, event: &KeyEvent) {
+            self.inner().last_event = Some(*event);
+        }
+        fn notify_devices_changed(&mut self, _device_infos: &[DeviceInfo]) {
+            self.inner().is_device_changed_called = true;
+        }
+    }
+}
diff --git a/services/inputflinger/rust/lib.rs b/services/inputflinger/rust/lib.rs
index a4049d5..68cd480 100644
--- a/services/inputflinger/rust/lib.rs
+++ b/services/inputflinger/rust/lib.rs
@@ -19,6 +19,7 @@
 //! We use cxxbridge to create IInputFlingerRust - the Rust component of inputflinger - and
 //! pass it back to C++ as a local AIDL interface.
 
+mod bounce_keys_filter;
 mod input_filter;
 
 use crate::input_filter::InputFilter;