1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //! Contains the InputVerifier, used to validate a stream of input events.
18
19 use crate::ffi::RustPointerProperties;
20 use crate::input::{DeviceId, MotionAction, MotionFlags, Source, SourceClass};
21 use log::info;
22 use std::collections::HashMap;
23 use std::collections::HashSet;
24
verify_event( action: MotionAction, pointer_properties: &[RustPointerProperties], flags: &MotionFlags, ) -> Result<(), String>25 fn verify_event(
26 action: MotionAction,
27 pointer_properties: &[RustPointerProperties],
28 flags: &MotionFlags,
29 ) -> Result<(), String> {
30 let pointer_count = pointer_properties.len();
31 if pointer_count < 1 {
32 return Err(format!("Invalid {} event: no pointers", action));
33 }
34 match action {
35 MotionAction::Down
36 | MotionAction::HoverEnter
37 | MotionAction::HoverExit
38 | MotionAction::HoverMove
39 | MotionAction::Up => {
40 if pointer_count != 1 {
41 return Err(format!(
42 "Invalid {} event: there are {} pointers in the event",
43 action, pointer_count
44 ));
45 }
46 }
47
48 MotionAction::Cancel => {
49 if !flags.contains(MotionFlags::CANCELED) {
50 return Err(format!(
51 "For ACTION_CANCEL, must set FLAG_CANCELED. Received flags: {:#?}",
52 flags
53 ));
54 }
55 }
56
57 MotionAction::PointerDown { action_index } | MotionAction::PointerUp { action_index } => {
58 if action_index >= pointer_count {
59 return Err(format!("Got {}, but event has {} pointer(s)", action, pointer_count));
60 }
61 }
62
63 _ => {}
64 }
65 Ok(())
66 }
67
68 /// The InputVerifier is used to validate a stream of input events.
69 pub struct InputVerifier {
70 name: String,
71 should_log: bool,
72 touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
73 hovering_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
74 }
75
76 impl InputVerifier {
77 /// Create a new InputVerifier.
new(name: &str, should_log: bool) -> Self78 pub fn new(name: &str, should_log: bool) -> Self {
79 logger::init(
80 logger::Config::default()
81 .with_tag_on_device("InputVerifier")
82 .with_max_level(log::LevelFilter::Trace),
83 );
84 Self {
85 name: name.to_owned(),
86 should_log,
87 touching_pointer_ids_by_device: HashMap::new(),
88 hovering_pointer_ids_by_device: HashMap::new(),
89 }
90 }
91
92 /// Process a pointer movement event from an InputDevice.
93 /// If the event is not valid, we return an error string that describes the issue.
process_movement( &mut self, device_id: DeviceId, source: Source, action: u32, pointer_properties: &[RustPointerProperties], flags: MotionFlags, ) -> Result<(), String>94 pub fn process_movement(
95 &mut self,
96 device_id: DeviceId,
97 source: Source,
98 action: u32,
99 pointer_properties: &[RustPointerProperties],
100 flags: MotionFlags,
101 ) -> Result<(), String> {
102 if !source.is_from_class(SourceClass::Pointer) {
103 // Skip non-pointer sources like MOUSE_RELATIVE for now
104 return Ok(());
105 }
106 if self.should_log {
107 info!(
108 "Processing {} for device {:?} ({} pointer{}) on {}",
109 MotionAction::from(action).to_string(),
110 device_id,
111 pointer_properties.len(),
112 if pointer_properties.len() == 1 { "" } else { "s" },
113 self.name
114 );
115 }
116
117 verify_event(action.into(), pointer_properties, &flags)?;
118
119 match action.into() {
120 MotionAction::Down => {
121 if self.touching_pointer_ids_by_device.contains_key(&device_id) {
122 return Err(format!(
123 "{}: Invalid DOWN event - pointers already down for device {:?}: {:?}",
124 self.name, device_id, self.touching_pointer_ids_by_device
125 ));
126 }
127 let it = self.touching_pointer_ids_by_device.entry(device_id).or_default();
128 it.insert(pointer_properties[0].id);
129 }
130 MotionAction::PointerDown { action_index } => {
131 if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
132 return Err(format!(
133 "{}: Received POINTER_DOWN but no pointers are currently down \
134 for device {:?}",
135 self.name, device_id
136 ));
137 }
138 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
139 if it.len() != pointer_properties.len() - 1 {
140 return Err(format!(
141 "{}: There are currently {} touching pointers, but the incoming \
142 POINTER_DOWN event has {}",
143 self.name,
144 it.len(),
145 pointer_properties.len()
146 ));
147 }
148 let pointer_id = pointer_properties[action_index].id;
149 if it.contains(&pointer_id) {
150 return Err(format!(
151 "{}: Pointer with id={} already present found in the properties",
152 self.name, pointer_id
153 ));
154 }
155 it.insert(pointer_id);
156 }
157 MotionAction::Move => {
158 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
159 return Err(format!(
160 "{}: ACTION_MOVE touching pointers don't match",
161 self.name
162 ));
163 }
164 }
165 MotionAction::PointerUp { action_index } => {
166 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
167 return Err(format!(
168 "{}: ACTION_POINTER_UP touching pointers don't match",
169 self.name
170 ));
171 }
172 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
173 let pointer_id = pointer_properties[action_index].id;
174 it.remove(&pointer_id);
175 }
176 MotionAction::Up => {
177 if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
178 return Err(format!(
179 "{} Received ACTION_UP but no pointers are currently down for device {:?}",
180 self.name, device_id
181 ));
182 }
183 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
184 if it.len() != 1 {
185 return Err(format!(
186 "{}: Got ACTION_UP, but we have pointers: {:?} for device {:?}",
187 self.name, it, device_id
188 ));
189 }
190 let pointer_id = pointer_properties[0].id;
191 if !it.contains(&pointer_id) {
192 return Err(format!(
193 "{}: Got ACTION_UP, but pointerId {} is not touching. Touching pointers:\
194 {:?} for device {:?}",
195 self.name, pointer_id, it, device_id
196 ));
197 }
198 self.touching_pointer_ids_by_device.remove(&device_id);
199 }
200 MotionAction::Cancel => {
201 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
202 return Err(format!(
203 "{}: Got ACTION_CANCEL, but the pointers don't match. \
204 Existing pointers: {:?}",
205 self.name, self.touching_pointer_ids_by_device
206 ));
207 }
208 self.touching_pointer_ids_by_device.remove(&device_id);
209 }
210 /*
211 * The hovering protocol currently supports a single pointer only, because we do not
212 * have ACTION_HOVER_POINTER_ENTER or ACTION_HOVER_POINTER_EXIT.
213 * Still, we are keeping the infrastructure here pretty general in case that is
214 * eventually supported.
215 */
216 MotionAction::HoverEnter => {
217 if self.hovering_pointer_ids_by_device.contains_key(&device_id) {
218 return Err(format!(
219 "{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\
220 {:?}",
221 self.name, device_id, self.hovering_pointer_ids_by_device
222 ));
223 }
224 let it = self.hovering_pointer_ids_by_device.entry(device_id).or_default();
225 it.insert(pointer_properties[0].id);
226 }
227 MotionAction::HoverMove => {
228 // For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER.
229 // If there was no prior HOVER_ENTER, just start a new hovering pointer.
230 let it = self.hovering_pointer_ids_by_device.entry(device_id).or_default();
231 it.insert(pointer_properties[0].id);
232 }
233 MotionAction::HoverExit => {
234 if !self.hovering_pointer_ids_by_device.contains_key(&device_id) {
235 return Err(format!(
236 "{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}",
237 self.name, device_id
238 ));
239 }
240 let pointer_id = pointer_properties[0].id;
241 let it = self.hovering_pointer_ids_by_device.get_mut(&device_id).unwrap();
242 it.remove(&pointer_id);
243
244 if !it.is_empty() {
245 return Err(format!(
246 "{}: Removed hovering pointer {}, but pointers are still\
247 hovering for device {:?}: {:?}",
248 self.name, pointer_id, device_id, it
249 ));
250 }
251 self.hovering_pointer_ids_by_device.remove(&device_id);
252 }
253 _ => return Ok(()),
254 }
255 Ok(())
256 }
257
258 /// Notify the verifier that the device has been reset, which will cause the verifier to erase
259 /// the current internal state for this device. Subsequent events from this device are expected
260 //// to start a new gesture.
reset_device(&mut self, device_id: DeviceId)261 pub fn reset_device(&mut self, device_id: DeviceId) {
262 self.touching_pointer_ids_by_device.remove(&device_id);
263 self.hovering_pointer_ids_by_device.remove(&device_id);
264 }
265
ensure_touching_pointers_match( &self, device_id: DeviceId, pointer_properties: &[RustPointerProperties], ) -> bool266 fn ensure_touching_pointers_match(
267 &self,
268 device_id: DeviceId,
269 pointer_properties: &[RustPointerProperties],
270 ) -> bool {
271 let Some(pointers) = self.touching_pointer_ids_by_device.get(&device_id) else {
272 return false;
273 };
274
275 if pointers.len() != pointer_properties.len() {
276 return false;
277 }
278
279 for pointer_property in pointer_properties.iter() {
280 let pointer_id = pointer_property.id;
281 if !pointers.contains(&pointer_id) {
282 return false;
283 }
284 }
285 true
286 }
287 }
288
289 #[cfg(test)]
290 mod tests {
291 use crate::input_verifier::InputVerifier;
292 use crate::DeviceId;
293 use crate::MotionFlags;
294 use crate::RustPointerProperties;
295 use crate::Source;
296
297 #[test]
298 /**
299 * Send a DOWN event with 2 pointers and ensure that it's marked as invalid.
300 */
bad_down_event()301 fn bad_down_event() {
302 let mut verifier = InputVerifier::new("Test", /*should_log*/ true);
303 let pointer_properties =
304 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
305 assert!(verifier
306 .process_movement(
307 DeviceId(1),
308 Source::Touchscreen,
309 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
310 &pointer_properties,
311 MotionFlags::empty(),
312 )
313 .is_err());
314 }
315
316 #[test]
single_pointer_stream()317 fn single_pointer_stream() {
318 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
319 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
320 assert!(verifier
321 .process_movement(
322 DeviceId(1),
323 Source::Touchscreen,
324 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
325 &pointer_properties,
326 MotionFlags::empty(),
327 )
328 .is_ok());
329 assert!(verifier
330 .process_movement(
331 DeviceId(1),
332 Source::Touchscreen,
333 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
334 &pointer_properties,
335 MotionFlags::empty(),
336 )
337 .is_ok());
338 assert!(verifier
339 .process_movement(
340 DeviceId(1),
341 Source::Touchscreen,
342 input_bindgen::AMOTION_EVENT_ACTION_UP,
343 &pointer_properties,
344 MotionFlags::empty(),
345 )
346 .is_ok());
347 }
348
349 #[test]
two_pointer_stream()350 fn two_pointer_stream() {
351 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
352 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
353 assert!(verifier
354 .process_movement(
355 DeviceId(1),
356 Source::Touchscreen,
357 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
358 &pointer_properties,
359 MotionFlags::empty(),
360 )
361 .is_ok());
362 // POINTER 1 DOWN
363 let two_pointer_properties =
364 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
365 assert!(verifier
366 .process_movement(
367 DeviceId(1),
368 Source::Touchscreen,
369 input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
370 | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
371 &two_pointer_properties,
372 MotionFlags::empty(),
373 )
374 .is_ok());
375 // POINTER 0 UP
376 assert!(verifier
377 .process_movement(
378 DeviceId(1),
379 Source::Touchscreen,
380 input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP
381 | (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
382 &two_pointer_properties,
383 MotionFlags::empty(),
384 )
385 .is_ok());
386 // ACTION_UP for pointer id=1
387 let pointer_1_properties = Vec::from([RustPointerProperties { id: 1 }]);
388 assert!(verifier
389 .process_movement(
390 DeviceId(1),
391 Source::Touchscreen,
392 input_bindgen::AMOTION_EVENT_ACTION_UP,
393 &pointer_1_properties,
394 MotionFlags::empty(),
395 )
396 .is_ok());
397 }
398
399 #[test]
multi_device_stream()400 fn multi_device_stream() {
401 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
402 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
403 assert!(verifier
404 .process_movement(
405 DeviceId(1),
406 Source::Touchscreen,
407 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
408 &pointer_properties,
409 MotionFlags::empty(),
410 )
411 .is_ok());
412 assert!(verifier
413 .process_movement(
414 DeviceId(1),
415 Source::Touchscreen,
416 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
417 &pointer_properties,
418 MotionFlags::empty(),
419 )
420 .is_ok());
421 assert!(verifier
422 .process_movement(
423 DeviceId(2),
424 Source::Touchscreen,
425 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
426 &pointer_properties,
427 MotionFlags::empty(),
428 )
429 .is_ok());
430 assert!(verifier
431 .process_movement(
432 DeviceId(2),
433 Source::Touchscreen,
434 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
435 &pointer_properties,
436 MotionFlags::empty(),
437 )
438 .is_ok());
439 assert!(verifier
440 .process_movement(
441 DeviceId(1),
442 Source::Touchscreen,
443 input_bindgen::AMOTION_EVENT_ACTION_UP,
444 &pointer_properties,
445 MotionFlags::empty(),
446 )
447 .is_ok());
448 }
449
450 #[test]
action_cancel()451 fn action_cancel() {
452 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
453 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
454 assert!(verifier
455 .process_movement(
456 DeviceId(1),
457 Source::Touchscreen,
458 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
459 &pointer_properties,
460 MotionFlags::empty(),
461 )
462 .is_ok());
463 assert!(verifier
464 .process_movement(
465 DeviceId(1),
466 Source::Touchscreen,
467 input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
468 &pointer_properties,
469 MotionFlags::CANCELED,
470 )
471 .is_ok());
472 }
473
474 #[test]
invalid_action_cancel()475 fn invalid_action_cancel() {
476 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
477 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
478 assert!(verifier
479 .process_movement(
480 DeviceId(1),
481 Source::Touchscreen,
482 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
483 &pointer_properties,
484 MotionFlags::empty(),
485 )
486 .is_ok());
487 assert!(verifier
488 .process_movement(
489 DeviceId(1),
490 Source::Touchscreen,
491 input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
492 &pointer_properties,
493 MotionFlags::empty(), // forgot to set FLAG_CANCELED
494 )
495 .is_err());
496 }
497
498 #[test]
invalid_up()499 fn invalid_up() {
500 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
501 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
502 assert!(verifier
503 .process_movement(
504 DeviceId(1),
505 Source::Touchscreen,
506 input_bindgen::AMOTION_EVENT_ACTION_UP,
507 &pointer_properties,
508 MotionFlags::empty(),
509 )
510 .is_err());
511 }
512
513 #[test]
correct_hover_sequence()514 fn correct_hover_sequence() {
515 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
516 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
517 assert!(verifier
518 .process_movement(
519 DeviceId(1),
520 Source::Touchscreen,
521 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
522 &pointer_properties,
523 MotionFlags::empty(),
524 )
525 .is_ok());
526
527 assert!(verifier
528 .process_movement(
529 DeviceId(1),
530 Source::Touchscreen,
531 input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
532 &pointer_properties,
533 MotionFlags::empty(),
534 )
535 .is_ok());
536
537 assert!(verifier
538 .process_movement(
539 DeviceId(1),
540 Source::Touchscreen,
541 input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT,
542 &pointer_properties,
543 MotionFlags::empty(),
544 )
545 .is_ok());
546
547 assert!(verifier
548 .process_movement(
549 DeviceId(1),
550 Source::Touchscreen,
551 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
552 &pointer_properties,
553 MotionFlags::empty(),
554 )
555 .is_ok());
556 }
557
558 #[test]
double_hover_enter()559 fn double_hover_enter() {
560 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
561 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
562 assert!(verifier
563 .process_movement(
564 DeviceId(1),
565 Source::Touchscreen,
566 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
567 &pointer_properties,
568 MotionFlags::empty(),
569 )
570 .is_ok());
571
572 assert!(verifier
573 .process_movement(
574 DeviceId(1),
575 Source::Touchscreen,
576 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
577 &pointer_properties,
578 MotionFlags::empty(),
579 )
580 .is_err());
581 }
582
583 // Send a MOVE without a preceding DOWN event. This is OK because it's from source
584 // MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event.
585 #[test]
relative_mouse_move()586 fn relative_mouse_move() {
587 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
588 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
589 assert!(verifier
590 .process_movement(
591 DeviceId(2),
592 Source::MouseRelative,
593 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
594 &pointer_properties,
595 MotionFlags::empty(),
596 )
597 .is_ok());
598 }
599
600 // Send a MOVE event with incorrect number of pointers (one of the pointers is missing).
601 #[test]
move_with_wrong_number_of_pointers()602 fn move_with_wrong_number_of_pointers() {
603 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
604 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
605 assert!(verifier
606 .process_movement(
607 DeviceId(1),
608 Source::Touchscreen,
609 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
610 &pointer_properties,
611 MotionFlags::empty(),
612 )
613 .is_ok());
614 // POINTER 1 DOWN
615 let two_pointer_properties =
616 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
617 assert!(verifier
618 .process_movement(
619 DeviceId(1),
620 Source::Touchscreen,
621 input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
622 | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
623 &two_pointer_properties,
624 MotionFlags::empty(),
625 )
626 .is_ok());
627 // MOVE event with 1 pointer missing (the pointer with id = 1). It should be rejected
628 assert!(verifier
629 .process_movement(
630 DeviceId(1),
631 Source::Touchscreen,
632 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
633 &pointer_properties,
634 MotionFlags::empty(),
635 )
636 .is_err());
637 }
638 }
639