diff options
-rw-r--r-- | include/input/InputVerifier.h | 2 | ||||
-rw-r--r-- | libs/input/InputVerifier.cpp | 9 | ||||
-rw-r--r-- | libs/input/rust/input_verifier.rs | 131 | ||||
-rw-r--r-- | libs/input/rust/lib.rs | 9 | ||||
-rw-r--r-- | services/inputflinger/dispatcher/InputDispatcher.cpp | 4 |
5 files changed, 150 insertions, 5 deletions
diff --git a/include/input/InputVerifier.h b/include/input/InputVerifier.h index 3715408388..b8574829f3 100644 --- a/include/input/InputVerifier.h +++ b/include/input/InputVerifier.h @@ -51,6 +51,8 @@ public: const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags); + void resetDevice(int32_t deviceId); + private: rust::Box<android::input::verifier::InputVerifier> mVerifier; }; diff --git a/libs/input/InputVerifier.cpp b/libs/input/InputVerifier.cpp index b0546a5243..851babfb54 100644 --- a/libs/input/InputVerifier.cpp +++ b/libs/input/InputVerifier.cpp @@ -24,6 +24,8 @@ using android::base::Error; using android::base::Result; using android::input::RustPointerProperties; +using DeviceId = int32_t; + namespace android { // --- InputVerifier --- @@ -31,7 +33,8 @@ namespace android { InputVerifier::InputVerifier(const std::string& name) : mVerifier(android::input::verifier::create(name)){}; -Result<void> InputVerifier::processMovement(int32_t deviceId, int32_t action, uint32_t pointerCount, +Result<void> InputVerifier::processMovement(DeviceId deviceId, int32_t action, + uint32_t pointerCount, const PointerProperties* pointerProperties, const PointerCoords* pointerCoords, int32_t flags) { std::vector<RustPointerProperties> rpp; @@ -49,4 +52,8 @@ Result<void> InputVerifier::processMovement(int32_t deviceId, int32_t action, ui } } +void InputVerifier::resetDevice(DeviceId deviceId) { + android::input::verifier::reset_device(*mVerifier, deviceId); +} + } // namespace android diff --git a/libs/input/rust/input_verifier.rs b/libs/input/rust/input_verifier.rs index 1cc11297b6..fdb623033b 100644 --- a/libs/input/rust/input_verifier.rs +++ b/libs/input/rust/input_verifier.rs @@ -27,6 +27,7 @@ pub struct InputVerifier { name: String, should_log: bool, touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>, + hovering_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>, } impl InputVerifier { @@ -37,7 +38,12 @@ impl InputVerifier { .with_tag_on_device("InputVerifier") .with_min_level(log::Level::Trace), ); - Self { name: name.to_owned(), should_log, touching_pointer_ids_by_device: HashMap::new() } + Self { + name: name.to_owned(), + should_log, + touching_pointer_ids_by_device: HashMap::new(), + hovering_pointer_ids_by_device: HashMap::new(), + } } /// Process a pointer movement event from an InputDevice. @@ -135,7 +141,7 @@ impl InputVerifier { self.name, pointer_id, it, device_id )); } - it.clear(); + self.touching_pointer_ids_by_device.remove(&device_id); } MotionAction::Cancel => { if flags.contains(MotionFlags::CANCELED) { @@ -153,11 +159,68 @@ impl InputVerifier { } self.touching_pointer_ids_by_device.remove(&device_id); } + /* + * The hovering protocol currently supports a single pointer only, because we do not + * have ACTION_HOVER_POINTER_ENTER or ACTION_HOVER_POINTER_EXIT. + * Still, we are keeping the infrastructure here pretty general in case that is + * eventually supported. + */ + MotionAction::HoverEnter => { + if self.hovering_pointer_ids_by_device.contains_key(&device_id) { + return Err(format!( + "{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\ + {:?}", + self.name, device_id, self.hovering_pointer_ids_by_device + )); + } + let it = self + .hovering_pointer_ids_by_device + .entry(device_id) + .or_insert_with(HashSet::new); + it.insert(pointer_properties[0].id); + } + MotionAction::HoverMove => { + // For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER. + // If there was no prior HOVER_ENTER, just start a new hovering pointer. + let it = self + .hovering_pointer_ids_by_device + .entry(device_id) + .or_insert_with(HashSet::new); + it.insert(pointer_properties[0].id); + } + MotionAction::HoverExit => { + if !self.hovering_pointer_ids_by_device.contains_key(&device_id) { + return Err(format!( + "{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}", + self.name, device_id + )); + } + let pointer_id = pointer_properties[0].id; + let it = self.hovering_pointer_ids_by_device.get_mut(&device_id).unwrap(); + it.remove(&pointer_id); + + if !it.is_empty() { + return Err(format!( + "{}: Removed hovering pointer {}, but pointers are still\ + hovering for device {:?}: {:?}", + self.name, pointer_id, device_id, it + )); + } + self.hovering_pointer_ids_by_device.remove(&device_id); + } _ => return Ok(()), } Ok(()) } + /// Notify the verifier that the device has been reset, which will cause the verifier to erase + /// the current internal state for this device. Subsequent events from this device are expected + //// to start a new gesture. + pub fn reset_device(&mut self, device_id: DeviceId) { + self.touching_pointer_ids_by_device.remove(&device_id); + self.hovering_pointer_ids_by_device.remove(&device_id); + } + fn ensure_touching_pointers_match( &self, device_id: DeviceId, @@ -272,4 +335,68 @@ mod tests { ) .is_err()); } + + #[test] + fn correct_hover_sequence() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + } + + #[test] + fn double_hover_enter() { + let mut verifier = InputVerifier::new("Test", /*should_log*/ false); + let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]); + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_ok()); + + assert!(verifier + .process_movement( + DeviceId(1), + input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER, + &pointer_properties, + MotionFlags::empty(), + ) + .is_err()); + } } diff --git a/libs/input/rust/lib.rs b/libs/input/rust/lib.rs index 25b2ecbcda..892f558da6 100644 --- a/libs/input/rust/lib.rs +++ b/libs/input/rust/lib.rs @@ -54,6 +54,7 @@ mod ffi { pointer_properties: &[RustPointerProperties], flags: i32, ) -> String; + fn reset_device(verifier: &mut InputVerifier, device_id: i32); } #[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] @@ -64,6 +65,10 @@ mod ffi { use crate::ffi::RustPointerProperties; +fn create(name: String) -> Box<InputVerifier> { + Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +} + fn process_movement( verifier: &mut InputVerifier, device_id: i32, @@ -83,6 +88,6 @@ fn process_movement( } } -fn create(name: String) -> Box<InputVerifier> { - Box::new(InputVerifier::new(&name, ffi::shouldLog("InputVerifierLogEvents"))) +fn reset_device(verifier: &mut InputVerifier, device_id: i32) { + verifier.reset_device(DeviceId(device_id)); } diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp index 29c4e469ea..482e23f043 100644 --- a/services/inputflinger/dispatcher/InputDispatcher.cpp +++ b/services/inputflinger/dispatcher/InputDispatcher.cpp @@ -4516,6 +4516,10 @@ void InputDispatcher::notifyDeviceReset(const NotifyDeviceResetArgs& args) { std::unique_ptr<DeviceResetEntry> newEntry = std::make_unique<DeviceResetEntry>(args.id, args.eventTime, args.deviceId); needWake = enqueueInboundEventLocked(std::move(newEntry)); + + for (auto& [_, verifier] : mVerifiersByDisplay) { + verifier.resetDevice(args.deviceId); + } } // release lock if (needWake) { |