Loading libs/input/rust/lib.rs +2 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,8 @@ mod keyboard_classifier; pub use data_store::{DataStore, DefaultFileReaderWriter}; pub use input::{ DeviceClass, DeviceId, InputDevice, ModifierState, MotionAction, MotionFlags, Source, DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionFlags, Source, }; pub use input_verifier::InputVerifier; pub use keyboard_classifier::KeyboardClassifier; Loading services/inputflinger/InputFilter.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ void InputFilter::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& AidlDeviceInfo& aidlInfo = mDeviceInfos.emplace_back(); aidlInfo.deviceId = info.getId(); aidlInfo.external = info.isExternal(); aidlInfo.keyboardType = info.getKeyboardType(); } if (isFilterEnabled()) { LOG_ALWAYS_FATAL_IF(!mInputFilterRust->notifyInputDevicesChanged(mDeviceInfos).isOk()); Loading services/inputflinger/aidl/com/android/server/inputflinger/DeviceInfo.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -23,4 +23,5 @@ package com.android.server.inputflinger; parcelable DeviceInfo { int deviceId; boolean external; int keyboardType; } No newline at end of file services/inputflinger/rust/bounce_keys_filter.rs +138 −13 Original line number Diff line number Diff line Loading @@ -17,12 +17,13 @@ //! 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 crate::input_filter::{Filter, VIRTUAL_KEYBOARD_DEVICE_ID}; 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 input::KeyboardType; use log::debug; use std::collections::{HashMap, HashSet}; Loading @@ -42,7 +43,7 @@ pub struct BounceKeysFilter { next: Box<dyn Filter + Send + Sync>, key_event_map: HashMap<i32, LastUpKeyEvent>, blocked_events: Vec<BlockedEvent>, external_devices: HashSet<i32>, supported_devices: HashSet<i32>, bounce_key_threshold_ns: i64, } Loading @@ -56,7 +57,7 @@ impl BounceKeysFilter { next, key_event_map: HashMap::new(), blocked_events: Vec::new(), external_devices: HashSet::new(), supported_devices: HashSet::new(), bounce_key_threshold_ns, } } Loading @@ -64,7 +65,7 @@ impl BounceKeysFilter { impl Filter for BounceKeysFilter { fn notify_key(&mut self, event: &KeyEvent) { if !(self.external_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) { if !(self.supported_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) { self.next.notify_key(event); return; } Loading Loading @@ -110,10 +111,17 @@ impl Filter for BounceKeysFilter { self.blocked_events.retain(|blocked_event| { device_infos.iter().any(|x| blocked_event.device_id == x.deviceId) }); self.external_devices.clear(); self.supported_devices.clear(); for device_info in device_infos { if device_info.external { self.external_devices.insert(device_info.deviceId); if device_info.deviceId == VIRTUAL_KEYBOARD_DEVICE_ID { continue; } if device_info.keyboardType == KeyboardType::None as i32 { continue; } // Support Alphabetic keyboards and Non-alphabetic external keyboards if device_info.external || device_info.keyboardType == KeyboardType::Alphabetic as i32 { self.supported_devices.insert(device_info.deviceId); } } self.next.notify_devices_changed(device_infos); Loading @@ -127,11 +135,12 @@ impl Filter for BounceKeysFilter { #[cfg(test)] mod tests { use crate::bounce_keys_filter::BounceKeysFilter; use crate::input_filter::{test_filter::TestFilter, Filter}; use crate::input_filter::{test_filter::TestFilter, Filter, VIRTUAL_KEYBOARD_DEVICE_ID}; 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 input::KeyboardType; static BASE_KEY_EVENT: KeyEvent = KeyEvent { id: 1, Loading @@ -156,6 +165,7 @@ mod tests { Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::Alphabetic, ); let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT }; Loading @@ -181,12 +191,68 @@ mod tests { } #[test] fn test_is_notify_key_doesnt_block_for_internal_keyboard() { fn test_is_notify_key_blocks_for_internal_keyboard() { let mut next = TestFilter::new(); let mut filter = setup_filter_with_internal_device( Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::Alphabetic, ); 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_non_alphabetic_keyboard() { let next = TestFilter::new(); let mut filter = setup_filter_with_internal_device( Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::NonAlphabetic, ); 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_virtual_keyboard() { let next = TestFilter::new(); let mut filter = setup_filter_with_internal_device( Box::new(next.clone()), VIRTUAL_KEYBOARD_DEVICE_ID, /* device_id */ 100, /* threshold */ KeyboardType::Alphabetic, ); let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT }; Loading @@ -209,6 +275,7 @@ mod tests { Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::NonAlphabetic, ); let event = Loading @@ -233,12 +300,60 @@ mod tests { let mut filter = setup_filter_with_devices( Box::new(next.clone()), &[ DeviceInfo { deviceId: 1, external: true }, DeviceInfo { deviceId: 2, external: true }, DeviceInfo { deviceId: 1, external: true, keyboardType: KeyboardType::Alphabetic as i32, }, DeviceInfo { deviceId: 2, external: true, keyboardType: KeyboardType::Alphabetic as i32, }, ], 100, /* threshold */ ); // Bounce key scenario on the external keyboard 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); } #[test] fn test_is_notify_key_for_external_and_internal_alphabetic_keyboards() { let mut next = TestFilter::new(); let mut filter = setup_filter_with_devices( Box::new(next.clone()), &[ DeviceInfo { deviceId: 1, external: false, keyboardType: KeyboardType::Alphabetic as i32, }, DeviceInfo { deviceId: 2, external: true, keyboardType: KeyboardType::Alphabetic as i32, }, ], 100, /* threshold */ ); // Bounce key scenario on the internal keyboard let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT }; filter.notify_key(&event); assert_eq!(next.last_event().unwrap(), event); Loading @@ -261,10 +376,15 @@ mod tests { next: Box<dyn Filter + Send + Sync>, device_id: i32, threshold: i64, keyboard_type: KeyboardType, ) -> BounceKeysFilter { setup_filter_with_devices( next, &[DeviceInfo { deviceId: device_id, external: true }], &[DeviceInfo { deviceId: device_id, external: true, keyboardType: keyboard_type as i32, }], threshold, ) } Loading @@ -273,10 +393,15 @@ mod tests { next: Box<dyn Filter + Send + Sync>, device_id: i32, threshold: i64, keyboard_type: KeyboardType, ) -> BounceKeysFilter { setup_filter_with_devices( next, &[DeviceInfo { deviceId: device_id, external: false }], &[DeviceInfo { deviceId: device_id, external: false, keyboardType: keyboard_type as i32, }], threshold, ) } Loading services/inputflinger/rust/input_filter.rs +9 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,9 @@ use input::ModifierState; use log::{error, info}; use std::sync::{Arc, Mutex, RwLock}; /// Virtual keyboard device ID pub const VIRTUAL_KEYBOARD_DEVICE_ID: i32 = -1; /// Interface for all the sub input filters pub trait Filter { fn notify_key(&mut self, event: &KeyEvent); Loading Loading @@ -214,6 +217,7 @@ mod tests { InputFilterConfiguration::InputFilterConfiguration, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction, }; use input::KeyboardType; use std::sync::{Arc, RwLock}; #[test] Loading Loading @@ -256,7 +260,11 @@ mod tests { Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks)))), ); assert!(input_filter .notifyInputDevicesChanged(&[DeviceInfo { deviceId: 0, external: true }]) .notifyInputDevicesChanged(&[DeviceInfo { deviceId: 0, external: true, keyboardType: KeyboardType::None as i32 }]) .is_ok()); assert!(test_filter.is_device_changed_called()); } Loading Loading
libs/input/rust/lib.rs +2 −1 Original line number Diff line number Diff line Loading @@ -24,7 +24,8 @@ mod keyboard_classifier; pub use data_store::{DataStore, DefaultFileReaderWriter}; pub use input::{ DeviceClass, DeviceId, InputDevice, ModifierState, MotionAction, MotionFlags, Source, DeviceClass, DeviceId, InputDevice, KeyboardType, ModifierState, MotionAction, MotionFlags, Source, }; pub use input_verifier::InputVerifier; pub use keyboard_classifier::KeyboardClassifier; Loading
services/inputflinger/InputFilter.cpp +1 −0 Original line number Diff line number Diff line Loading @@ -60,6 +60,7 @@ void InputFilter::notifyInputDevicesChanged(const NotifyInputDevicesChangedArgs& AidlDeviceInfo& aidlInfo = mDeviceInfos.emplace_back(); aidlInfo.deviceId = info.getId(); aidlInfo.external = info.isExternal(); aidlInfo.keyboardType = info.getKeyboardType(); } if (isFilterEnabled()) { LOG_ALWAYS_FATAL_IF(!mInputFilterRust->notifyInputDevicesChanged(mDeviceInfos).isOk()); Loading
services/inputflinger/aidl/com/android/server/inputflinger/DeviceInfo.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -23,4 +23,5 @@ package com.android.server.inputflinger; parcelable DeviceInfo { int deviceId; boolean external; int keyboardType; } No newline at end of file
services/inputflinger/rust/bounce_keys_filter.rs +138 −13 Original line number Diff line number Diff line Loading @@ -17,12 +17,13 @@ //! 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 crate::input_filter::{Filter, VIRTUAL_KEYBOARD_DEVICE_ID}; 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 input::KeyboardType; use log::debug; use std::collections::{HashMap, HashSet}; Loading @@ -42,7 +43,7 @@ pub struct BounceKeysFilter { next: Box<dyn Filter + Send + Sync>, key_event_map: HashMap<i32, LastUpKeyEvent>, blocked_events: Vec<BlockedEvent>, external_devices: HashSet<i32>, supported_devices: HashSet<i32>, bounce_key_threshold_ns: i64, } Loading @@ -56,7 +57,7 @@ impl BounceKeysFilter { next, key_event_map: HashMap::new(), blocked_events: Vec::new(), external_devices: HashSet::new(), supported_devices: HashSet::new(), bounce_key_threshold_ns, } } Loading @@ -64,7 +65,7 @@ impl BounceKeysFilter { impl Filter for BounceKeysFilter { fn notify_key(&mut self, event: &KeyEvent) { if !(self.external_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) { if !(self.supported_devices.contains(&event.deviceId) && event.source == Source::KEYBOARD) { self.next.notify_key(event); return; } Loading Loading @@ -110,10 +111,17 @@ impl Filter for BounceKeysFilter { self.blocked_events.retain(|blocked_event| { device_infos.iter().any(|x| blocked_event.device_id == x.deviceId) }); self.external_devices.clear(); self.supported_devices.clear(); for device_info in device_infos { if device_info.external { self.external_devices.insert(device_info.deviceId); if device_info.deviceId == VIRTUAL_KEYBOARD_DEVICE_ID { continue; } if device_info.keyboardType == KeyboardType::None as i32 { continue; } // Support Alphabetic keyboards and Non-alphabetic external keyboards if device_info.external || device_info.keyboardType == KeyboardType::Alphabetic as i32 { self.supported_devices.insert(device_info.deviceId); } } self.next.notify_devices_changed(device_infos); Loading @@ -127,11 +135,12 @@ impl Filter for BounceKeysFilter { #[cfg(test)] mod tests { use crate::bounce_keys_filter::BounceKeysFilter; use crate::input_filter::{test_filter::TestFilter, Filter}; use crate::input_filter::{test_filter::TestFilter, Filter, VIRTUAL_KEYBOARD_DEVICE_ID}; 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 input::KeyboardType; static BASE_KEY_EVENT: KeyEvent = KeyEvent { id: 1, Loading @@ -156,6 +165,7 @@ mod tests { Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::Alphabetic, ); let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT }; Loading @@ -181,12 +191,68 @@ mod tests { } #[test] fn test_is_notify_key_doesnt_block_for_internal_keyboard() { fn test_is_notify_key_blocks_for_internal_keyboard() { let mut next = TestFilter::new(); let mut filter = setup_filter_with_internal_device( Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::Alphabetic, ); 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_non_alphabetic_keyboard() { let next = TestFilter::new(); let mut filter = setup_filter_with_internal_device( Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::NonAlphabetic, ); 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_virtual_keyboard() { let next = TestFilter::new(); let mut filter = setup_filter_with_internal_device( Box::new(next.clone()), VIRTUAL_KEYBOARD_DEVICE_ID, /* device_id */ 100, /* threshold */ KeyboardType::Alphabetic, ); let event = KeyEvent { action: KeyEventAction::DOWN, ..BASE_KEY_EVENT }; Loading @@ -209,6 +275,7 @@ mod tests { Box::new(next.clone()), 1, /* device_id */ 100, /* threshold */ KeyboardType::NonAlphabetic, ); let event = Loading @@ -233,12 +300,60 @@ mod tests { let mut filter = setup_filter_with_devices( Box::new(next.clone()), &[ DeviceInfo { deviceId: 1, external: true }, DeviceInfo { deviceId: 2, external: true }, DeviceInfo { deviceId: 1, external: true, keyboardType: KeyboardType::Alphabetic as i32, }, DeviceInfo { deviceId: 2, external: true, keyboardType: KeyboardType::Alphabetic as i32, }, ], 100, /* threshold */ ); // Bounce key scenario on the external keyboard 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); } #[test] fn test_is_notify_key_for_external_and_internal_alphabetic_keyboards() { let mut next = TestFilter::new(); let mut filter = setup_filter_with_devices( Box::new(next.clone()), &[ DeviceInfo { deviceId: 1, external: false, keyboardType: KeyboardType::Alphabetic as i32, }, DeviceInfo { deviceId: 2, external: true, keyboardType: KeyboardType::Alphabetic as i32, }, ], 100, /* threshold */ ); // Bounce key scenario on the internal keyboard let event = KeyEvent { deviceId: 1, action: KeyEventAction::DOWN, ..BASE_KEY_EVENT }; filter.notify_key(&event); assert_eq!(next.last_event().unwrap(), event); Loading @@ -261,10 +376,15 @@ mod tests { next: Box<dyn Filter + Send + Sync>, device_id: i32, threshold: i64, keyboard_type: KeyboardType, ) -> BounceKeysFilter { setup_filter_with_devices( next, &[DeviceInfo { deviceId: device_id, external: true }], &[DeviceInfo { deviceId: device_id, external: true, keyboardType: keyboard_type as i32, }], threshold, ) } Loading @@ -273,10 +393,15 @@ mod tests { next: Box<dyn Filter + Send + Sync>, device_id: i32, threshold: i64, keyboard_type: KeyboardType, ) -> BounceKeysFilter { setup_filter_with_devices( next, &[DeviceInfo { deviceId: device_id, external: false }], &[DeviceInfo { deviceId: device_id, external: false, keyboardType: keyboard_type as i32, }], threshold, ) } Loading
services/inputflinger/rust/input_filter.rs +9 −1 Original line number Diff line number Diff line Loading @@ -35,6 +35,9 @@ use input::ModifierState; use log::{error, info}; use std::sync::{Arc, Mutex, RwLock}; /// Virtual keyboard device ID pub const VIRTUAL_KEYBOARD_DEVICE_ID: i32 = -1; /// Interface for all the sub input filters pub trait Filter { fn notify_key(&mut self, event: &KeyEvent); Loading Loading @@ -214,6 +217,7 @@ mod tests { InputFilterConfiguration::InputFilterConfiguration, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction, }; use input::KeyboardType; use std::sync::{Arc, RwLock}; #[test] Loading Loading @@ -256,7 +260,11 @@ mod tests { Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks)))), ); assert!(input_filter .notifyInputDevicesChanged(&[DeviceInfo { deviceId: 0, external: true }]) .notifyInputDevicesChanged(&[DeviceInfo { deviceId: 0, external: true, keyboardType: KeyboardType::None as i32 }]) .is_ok()); assert!(test_filter.is_device_changed_called()); } Loading