summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/input/InputVerifier.h2
-rw-r--r--libs/input/InputVerifier.cpp9
-rw-r--r--libs/input/rust/input_verifier.rs131
-rw-r--r--libs/input/rust/lib.rs9
-rw-r--r--services/inputflinger/dispatcher/InputDispatcher.cpp4
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) {