diff options
| author | 2024-09-25 13:19:56 +0000 | |
|---|---|---|
| committer | 2024-09-30 15:51:32 +0000 | |
| commit | ab2c2fcaff293100f8a2bbbe6b1d716fc02ed1fc (patch) | |
| tree | 188d4becb0bcd907aa5316850f61fb68e4bc6a3f | |
| parent | 26e74e586afad4a62a37cfa9962339386a355617 (diff) | |
Save and restore sticky keys state on configuration changed
Allow individual input filters to save and restore state when
getting recreated on a configuration changed
Test: atest --host libinputflinger_rs_test
Bug: 294546335
Flag: EXEMPT bugfix
Change-Id: I6e62b2c44c0e555957f72cdf911cb28d571e6074
| -rw-r--r-- | services/inputflinger/rust/bounce_keys_filter.rs | 12 | ||||
| -rw-r--r-- | services/inputflinger/rust/input_filter.rs | 33 | ||||
| -rw-r--r-- | services/inputflinger/rust/slow_keys_filter.rs | 16 | ||||
| -rw-r--r-- | services/inputflinger/rust/sticky_keys_filter.rs | 114 |
4 files changed, 150 insertions, 25 deletions
diff --git a/services/inputflinger/rust/bounce_keys_filter.rs b/services/inputflinger/rust/bounce_keys_filter.rs index e05e8e512f..a8959d9041 100644 --- a/services/inputflinger/rust/bounce_keys_filter.rs +++ b/services/inputflinger/rust/bounce_keys_filter.rs @@ -25,6 +25,7 @@ use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ }; use input::KeyboardType; use log::debug; +use std::any::Any; use std::collections::{HashMap, HashSet}; #[derive(Debug)] @@ -134,6 +135,17 @@ impl Filter for BounceKeysFilter { self.next.destroy(); } + fn save( + &mut self, + state: HashMap<&'static str, Box<dyn Any + Send + Sync>>, + ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> { + self.next.save(state) + } + + fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) { + self.next.restore(state); + } + fn dump(&mut self, dump_str: String) -> String { let mut result = "Bounce Keys filter: \n".to_string(); result += &format!("\tthreshold = {:?}ns\n", self.bounce_key_threshold_ns); diff --git a/services/inputflinger/rust/input_filter.rs b/services/inputflinger/rust/input_filter.rs index e2212449aa..39c3465aea 100644 --- a/services/inputflinger/rust/input_filter.rs +++ b/services/inputflinger/rust/input_filter.rs @@ -33,6 +33,8 @@ use crate::slow_keys_filter::SlowKeysFilter; use crate::sticky_keys_filter::StickyKeysFilter; use input::ModifierState; use log::{error, info}; +use std::any::Any; +use std::collections::HashMap; use std::sync::{Arc, Mutex, RwLock}; /// Virtual keyboard device ID @@ -43,6 +45,11 @@ pub trait Filter { fn notify_key(&mut self, event: &KeyEvent); fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]); fn destroy(&mut self); + fn save( + &mut self, + state: HashMap<&'static str, Box<dyn Any + Send + Sync>>, + ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>>; + fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>); fn dump(&mut self, dump_str: String) -> String; } @@ -105,6 +112,7 @@ impl IInputFilter for InputFilter { fn notifyConfigurationChanged(&self, config: &InputFilterConfiguration) -> binder::Result<()> { { let mut state = self.state.lock().unwrap(); + let saved_state = state.first_filter.save(HashMap::new()); state.first_filter.destroy(); let mut first_filter: Box<dyn Filter + Send + Sync> = Box::new(BaseFilter::new(self.callbacks.clone())); @@ -138,6 +146,7 @@ impl IInputFilter for InputFilter { ); } state.first_filter = first_filter; + state.first_filter.restore(&saved_state); } Result::Ok(()) } @@ -175,6 +184,18 @@ impl Filter for BaseFilter { // do nothing } + fn save( + &mut self, + state: HashMap<&'static str, Box<dyn Any + Send + Sync>>, + ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> { + // do nothing + state + } + + fn restore(&mut self, _state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) { + // do nothing + } + fn dump(&mut self, dump_str: String) -> String { // do nothing dump_str @@ -367,6 +388,8 @@ pub mod test_filter { use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, }; + use std::any::Any; + use std::collections::HashMap; use std::sync::{Arc, RwLock, RwLockWriteGuard}; #[derive(Default)] @@ -415,6 +438,16 @@ pub mod test_filter { fn destroy(&mut self) { self.inner().is_destroy_called = true; } + fn save( + &mut self, + state: HashMap<&'static str, Box<dyn Any + Send + Sync>>, + ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> { + // do nothing + state + } + fn restore(&mut self, _state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) { + // do nothing + } fn dump(&mut self, dump_str: String) -> String { // do nothing dump_str diff --git a/services/inputflinger/rust/slow_keys_filter.rs b/services/inputflinger/rust/slow_keys_filter.rs index 8830aac529..085e80e207 100644 --- a/services/inputflinger/rust/slow_keys_filter.rs +++ b/services/inputflinger/rust/slow_keys_filter.rs @@ -26,7 +26,8 @@ use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ }; use input::KeyboardType; use log::debug; -use std::collections::HashSet; +use std::any::Any; +use std::collections::{HashMap, HashSet}; use std::sync::{Arc, RwLock, RwLockReadGuard, RwLockWriteGuard}; // Policy flags from Input.h @@ -187,6 +188,19 @@ impl Filter for SlowKeysFilter { slow_filter.next.destroy(); } + fn save( + &mut self, + state: HashMap<&'static str, Box<dyn Any + Send + Sync>>, + ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> { + let mut slow_filter = self.write_inner(); + slow_filter.next.save(state) + } + + fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) { + let mut slow_filter = self.write_inner(); + slow_filter.next.restore(state); + } + fn dump(&mut self, dump_str: String) -> String { let mut slow_filter = self.write_inner(); let mut result = "Slow Keys filter: \n".to_string(); diff --git a/services/inputflinger/rust/sticky_keys_filter.rs b/services/inputflinger/rust/sticky_keys_filter.rs index 161a5fca60..7a1d0ec934 100644 --- a/services/inputflinger/rust/sticky_keys_filter.rs +++ b/services/inputflinger/rust/sticky_keys_filter.rs @@ -24,7 +24,8 @@ use com_android_server_inputflinger::aidl::com::android::server::inputflinger::{ DeviceInfo::DeviceInfo, KeyEvent::KeyEvent, KeyEventAction::KeyEventAction, }; use input::ModifierState; -use std::collections::HashSet; +use std::any::Any; +use std::collections::{HashMap, HashSet}; // Modifier keycodes: values are from /frameworks/native/include/android/keycodes.h const KEYCODE_ALT_LEFT: i32 = 57; @@ -40,10 +41,17 @@ const KEYCODE_META_LEFT: i32 = 117; const KEYCODE_META_RIGHT: i32 = 118; const KEYCODE_FUNCTION: i32 = 119; const KEYCODE_NUM_LOCK: i32 = 143; +static STICKY_KEYS_DATA: &str = "sticky_keys_data"; pub struct StickyKeysFilter { next: Box<dyn Filter + Send + Sync>, listener: ModifierStateListener, + data: Data, +} + +#[derive(Default)] +/// Data that will be saved and restored across configuration changes +struct Data { /// Tracking devices that contributed to the modifier state. contributing_devices: HashSet<i32>, /// State describing the current enabled modifiers. This contain both locked and non-locked @@ -61,21 +69,15 @@ impl StickyKeysFilter { next: Box<dyn Filter + Send + Sync>, listener: ModifierStateListener, ) -> StickyKeysFilter { - Self { - next, - listener, - contributing_devices: HashSet::new(), - modifier_state: ModifierState::None, - locked_modifier_state: ModifierState::None, - } + Self { next, listener, data: Default::default() } } } impl Filter for StickyKeysFilter { fn notify_key(&mut self, event: &KeyEvent) { let up = event.action == KeyEventAction::UP; - let mut modifier_state = self.modifier_state; - let mut locked_modifier_state = self.locked_modifier_state; + let mut modifier_state = self.data.modifier_state; + let mut locked_modifier_state = self.data.locked_modifier_state; if !is_ephemeral_modifier_key(event.keyCode) { // If non-ephemeral modifier key (i.e. non-modifier keys + toggle modifier keys like // CAPS_LOCK, NUM_LOCK etc.), don't block key and pass in the sticky modifier state with @@ -93,7 +95,7 @@ impl Filter for StickyKeysFilter { } } else if up { // Update contributing devices to track keyboards - self.contributing_devices.insert(event.deviceId); + self.data.contributing_devices.insert(event.deviceId); // If ephemeral modifier key, capture the key and update the sticky modifier states let modifier_key_mask = get_ephemeral_modifier_key_mask(event.keyCode); let symmetrical_modifier_key_mask = get_symmetrical_modifier_key_mask(event.keyCode); @@ -108,38 +110,62 @@ impl Filter for StickyKeysFilter { modifier_state |= modifier_key_mask; } } - if self.modifier_state != modifier_state - || self.locked_modifier_state != locked_modifier_state + if self.data.modifier_state != modifier_state + || self.data.locked_modifier_state != locked_modifier_state { - self.modifier_state = modifier_state; - self.locked_modifier_state = locked_modifier_state; + self.data.modifier_state = modifier_state; + self.data.locked_modifier_state = locked_modifier_state; self.listener.modifier_state_changed(modifier_state, locked_modifier_state); } } fn notify_devices_changed(&mut self, device_infos: &[DeviceInfo]) { // Clear state if all contributing devices removed - self.contributing_devices.retain(|id| device_infos.iter().any(|x| *id == x.deviceId)); - if self.contributing_devices.is_empty() - && (self.modifier_state != ModifierState::None - || self.locked_modifier_state != ModifierState::None) + self.data.contributing_devices.retain(|id| device_infos.iter().any(|x| *id == x.deviceId)); + if self.data.contributing_devices.is_empty() + && (self.data.modifier_state != ModifierState::None + || self.data.locked_modifier_state != ModifierState::None) { - self.modifier_state = ModifierState::None; - self.locked_modifier_state = ModifierState::None; + self.data.modifier_state = ModifierState::None; + self.data.locked_modifier_state = ModifierState::None; self.listener.modifier_state_changed(ModifierState::None, ModifierState::None); } self.next.notify_devices_changed(device_infos); } + fn save( + &mut self, + mut state: HashMap<&'static str, Box<dyn Any + Send + Sync>>, + ) -> HashMap<&'static str, Box<dyn Any + Send + Sync>> { + let data = Data { + contributing_devices: self.data.contributing_devices.clone(), + modifier_state: self.data.modifier_state, + locked_modifier_state: self.data.locked_modifier_state, + }; + state.insert(STICKY_KEYS_DATA, Box::new(data)); + self.next.save(state) + } + + fn restore(&mut self, state: &HashMap<&'static str, Box<dyn Any + Send + Sync>>) { + if let Some(value) = state.get(STICKY_KEYS_DATA) { + if let Some(data) = value.downcast_ref::<Data>() { + self.data.contributing_devices = data.contributing_devices.clone(); + self.data.modifier_state = data.modifier_state; + self.data.locked_modifier_state = data.locked_modifier_state; + } + } + self.next.restore(state) + } + fn destroy(&mut self) { self.next.destroy(); } fn dump(&mut self, dump_str: String) -> String { let mut result = "Sticky Keys filter: \n".to_string(); - result += &format!("\tmodifier_state = {:?}\n", self.modifier_state); - result += &format!("\tlocked_modifier_state = {:?}\n", self.locked_modifier_state); - result += &format!("\tcontributing_devices = {:?}\n", self.contributing_devices); + result += &format!("\tmodifier_state = {:?}\n", self.data.modifier_state); + result += &format!("\tlocked_modifier_state = {:?}\n", self.data.locked_modifier_state); + result += &format!("\tcontributing_devices = {:?}\n", self.data.contributing_devices); self.next.dump(dump_str + &result) } } @@ -245,6 +271,7 @@ mod tests { }; use input::KeyboardType; use input::ModifierState; + use std::collections::HashMap; use std::sync::{Arc, RwLock}; static DEVICE_ID: i32 = 1; @@ -452,6 +479,45 @@ mod tests { } #[test] + fn test_modifier_state_restored_on_recreation() { + let test_filter = TestFilter::new(); + let test_callbacks = TestCallbacks::new(); + let mut sticky_keys_filter = setup_filter( + Box::new(test_filter.clone()), + Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks.clone())))), + ); + sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_DOWN }); + sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_UP }); + + let saved_state = sticky_keys_filter.save(HashMap::new()); + sticky_keys_filter.destroy(); + + // Create a new Sticky keys filter + let test_filter = TestFilter::new(); + let mut sticky_keys_filter = setup_filter( + Box::new(test_filter.clone()), + Arc::new(RwLock::new(Strong::new(Box::new(test_callbacks.clone())))), + ); + sticky_keys_filter.restore(&saved_state); + assert_eq!( + test_callbacks.get_last_modifier_state(), + ModifierState::CtrlLeftOn | ModifierState::CtrlOn + ); + assert_eq!(test_callbacks.get_last_locked_modifier_state(), ModifierState::None); + + sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_DOWN }); + sticky_keys_filter.notify_key(&KeyEvent { keyCode: KEYCODE_CTRL_LEFT, ..BASE_KEY_UP }); + assert_eq!( + test_callbacks.get_last_modifier_state(), + ModifierState::CtrlLeftOn | ModifierState::CtrlOn + ); + assert_eq!( + test_callbacks.get_last_locked_modifier_state(), + ModifierState::CtrlLeftOn | ModifierState::CtrlOn + ); + } + + #[test] fn test_key_events_have_sticky_modifier_state() { let test_filter = TestFilter::new(); let test_callbacks = TestCallbacks::new(); |