input_pipeline/gestures/
secondary_tap.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use super::gesture_arena::{
6    self, DetailedReasonFloat, DetailedReasonInt, DetailedReasonUint, ExamineEventResult,
7    ProcessBufferedEventsResult, Reason, RecognizedGesture, TouchpadEvent, VerifyEventResult,
8    SECONDARY_BUTTON,
9};
10use crate::mouse_binding::{MouseEvent, MouseLocation, MousePhase, RelativeLocation};
11use crate::utils::{euclidean_distance, Position};
12
13use maplit::hashset;
14
15/// The initial state of this recognizer, before a secondary tap has been
16/// detected.
17#[derive(Debug)]
18pub(super) struct InitialContender {
19    /// The maximum displacement that a detected finger can withstand to still
20    /// be considered a secondary tap. Measured in millimeters.
21    pub(super) max_finger_displacement_in_mm: f32,
22
23    /// The maximum time that can elapse between two fingers down and fingers up
24    /// to be considered a secondary tap gesture.
25    pub(super) max_time_elapsed: zx::MonotonicDuration,
26}
27
28impl InitialContender {
29    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
30    fn into_one_finger_contact_contender(
31        self: Box<Self>,
32        one_finger_contact_event: TouchpadEvent,
33    ) -> Box<dyn gesture_arena::Contender> {
34        Box::new(OneFingerContactContender {
35            one_finger_contact_event,
36            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
37            max_time_elapsed: self.max_time_elapsed,
38        })
39    }
40
41    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
42    fn into_two_finger_contacts_contender(
43        self: Box<Self>,
44        two_finger_contacts_event: TouchpadEvent,
45    ) -> Box<dyn gesture_arena::Contender> {
46        Box::new(TwoFingerContactsContender {
47            two_finger_contacts_event,
48            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
49            max_time_elapsed: self.max_time_elapsed,
50        })
51    }
52}
53
54impl gesture_arena::Contender for InitialContender {
55    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
56        let num_pressed_buttons = event.pressed_buttons.len();
57        if num_pressed_buttons != 0 {
58            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
59                criterion: "num_pressed_buttons",
60                min: Some(0),
61                max: Some(0),
62                actual: num_pressed_buttons,
63            }));
64        }
65
66        let num_contacts = event.contacts.len();
67        match num_contacts {
68            1 => {
69                ExamineEventResult::Contender(self.into_one_finger_contact_contender(event.clone()))
70            }
71            2 => ExamineEventResult::Contender(
72                self.into_two_finger_contacts_contender(event.clone()),
73            ),
74            0 | _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
75                criterion: "num_contacts",
76                min: Some(1),
77                max: Some(2),
78                actual: num_contacts,
79            })),
80        }
81    }
82
83    fn start_from_idle(&self) -> bool {
84        true
85    }
86}
87
88/// The state when this recognizer has detected a single finger down.
89#[derive(Debug)]
90struct OneFingerContactContender {
91    /// The TouchpadEvent when a finger down was first detected.
92    one_finger_contact_event: TouchpadEvent,
93
94    /// The maximum displacement that a detected finger can withstand to still
95    /// be considered a tap. Measured in millimeters.
96    max_finger_displacement_in_mm: f32,
97
98    /// The maximum time that can elapse between two fingers down and fingers up
99    /// to be considered a secondary tap gesture.
100    max_time_elapsed: zx::MonotonicDuration,
101}
102
103impl OneFingerContactContender {
104    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
105    fn into_two_finger_contacts_contender(
106        self: Box<Self>,
107        two_finger_contacts_event: TouchpadEvent,
108    ) -> Box<dyn gesture_arena::Contender> {
109        Box::new(TwoFingerContactsContender {
110            two_finger_contacts_event,
111            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
112            max_time_elapsed: self.max_time_elapsed,
113        })
114    }
115}
116
117impl gesture_arena::Contender for OneFingerContactContender {
118    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
119        let elapsed_time = event.timestamp - self.one_finger_contact_event.timestamp;
120        if elapsed_time >= self.max_time_elapsed {
121            return ExamineEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
122                criterion: "elapsed_time_micros",
123                min: None,
124                max: Some(self.max_time_elapsed.into_micros()),
125                actual: elapsed_time.into_micros(),
126            }));
127        }
128
129        let num_pressed_buttons = event.pressed_buttons.len();
130        if num_pressed_buttons != 0 {
131            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
132                criterion: "num_pressed_buttons",
133                min: Some(0),
134                max: Some(0),
135                actual: num_pressed_buttons,
136            }));
137        }
138
139        let num_contacts = event.contacts.len();
140        match num_contacts {
141            1 => {
142                let displacement_mm = euclidean_distance(
143                    position_from_event(event, 0),
144                    position_from_event(&self.one_finger_contact_event, 0),
145                );
146                if displacement_mm >= self.max_finger_displacement_in_mm {
147                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
148                        DetailedReasonFloat {
149                            criterion: "displacement_mm",
150                            min: None,
151                            max: Some(self.max_finger_displacement_in_mm),
152                            actual: displacement_mm,
153                        },
154                    ));
155                }
156                ExamineEventResult::Contender(self)
157            }
158            2 => {
159                let displacement_mm = euclidean_distance(
160                    position_from_event(event, 0),
161                    position_from_event(&self.one_finger_contact_event, 0),
162                );
163                if displacement_mm >= self.max_finger_displacement_in_mm {
164                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
165                        DetailedReasonFloat {
166                            criterion: "displacement_mm",
167                            min: None,
168                            max: Some(self.max_finger_displacement_in_mm),
169                            actual: displacement_mm,
170                        },
171                    ));
172                }
173                ExamineEventResult::Contender(
174                    self.into_two_finger_contacts_contender(event.clone()),
175                )
176            }
177            0 | _ => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
178                criterion: "num_contacts",
179                min: Some(1),
180                max: Some(2),
181                actual: num_contacts,
182            })),
183        }
184    }
185}
186
187/// The state when this recognizer has detected two fingers down.
188#[derive(Debug)]
189struct TwoFingerContactsContender {
190    /// The TouchpadEvent when two fingers were first detected.
191    two_finger_contacts_event: TouchpadEvent,
192
193    /// The maximum displacement that a detected finger can withstand to still
194    /// be considered a tap. Measured in millimeters.
195    max_finger_displacement_in_mm: f32,
196
197    /// The maximum time that can elapse between two fingers down and fingers up
198    /// to be considered a secondary tap gesture.
199    max_time_elapsed: zx::MonotonicDuration,
200}
201
202impl TwoFingerContactsContender {
203    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
204    fn into_one_finger_raised_contender(self: Box<Self>) -> Box<dyn gesture_arena::Contender> {
205        Box::new(OneFingerRaisedContender {
206            two_finger_contacts_event: self.two_finger_contacts_event,
207            max_finger_displacement_in_mm: self.max_finger_displacement_in_mm,
208            max_time_elapsed: self.max_time_elapsed,
209        })
210    }
211
212    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
213    fn into_matched_contender(
214        self: Box<Self>,
215        no_contacts_event: TouchpadEvent,
216    ) -> Box<dyn gesture_arena::MatchedContender> {
217        Box::new(MatchedContender {
218            two_finger_contacts_event: self.two_finger_contacts_event,
219            no_contacts_event,
220            max_time_elapsed: self.max_time_elapsed,
221        })
222    }
223}
224
225impl gesture_arena::Contender for TwoFingerContactsContender {
226    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
227        let elapsed_time = event.timestamp - self.two_finger_contacts_event.timestamp;
228        if elapsed_time >= self.max_time_elapsed {
229            return ExamineEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
230                criterion: "elapsed_time_micros",
231                min: None,
232                max: Some(self.max_time_elapsed.into_micros()),
233                actual: elapsed_time.into_micros(),
234            }));
235        }
236
237        let num_pressed_buttons = event.pressed_buttons.len();
238        if num_pressed_buttons != 0 {
239            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
240                criterion: "num_pressed_buttons",
241                min: Some(0),
242                max: Some(0),
243                actual: num_pressed_buttons,
244            }));
245        }
246
247        let num_contacts = u8::try_from(event.contacts.len()).unwrap_or(u8::MAX);
248        match num_contacts {
249            0 => ExamineEventResult::MatchedContender(self.into_matched_contender(event.clone())),
250            1 => {
251                match &self
252                    .two_finger_contacts_event
253                    .clone()
254                    .contacts
255                    .into_iter()
256                    .find(|contact| contact.id == event.contacts[0].id)
257                {
258                    Some(contact) => {
259                        let displacement_mm =
260                            euclidean_distance(position_from_event(event, 0), contact.position);
261                        if displacement_mm >= self.max_finger_displacement_in_mm {
262                            return ExamineEventResult::Mismatch(Reason::DetailedFloat(
263                                DetailedReasonFloat {
264                                    criterion: "displacement_mm",
265                                    min: None,
266                                    max: Some(self.max_finger_displacement_in_mm),
267                                    actual: displacement_mm,
268                                },
269                            ));
270                        }
271                    }
272                    None => {
273                        return ExamineEventResult::Mismatch(Reason::Basic(
274                            "remaining contact id differs from initial two finger contacts",
275                        ));
276                    }
277                }
278
279                ExamineEventResult::Contender(self.into_one_finger_raised_contender())
280            }
281            2 => {
282                // Acceptable displacement on the first touch contact.
283                let displacement_mm = euclidean_distance(
284                    position_from_event(event, 0),
285                    position_from_event(&self.two_finger_contacts_event, 0),
286                );
287                if displacement_mm >= self.max_finger_displacement_in_mm {
288                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
289                        DetailedReasonFloat {
290                            criterion: "displacement_mm",
291                            min: None,
292                            max: Some(self.max_finger_displacement_in_mm),
293                            actual: displacement_mm,
294                        },
295                    ));
296                }
297
298                // Acceptable displacement on the second touch contact.
299                let displacement_mm = euclidean_distance(
300                    position_from_event(event, 1),
301                    position_from_event(&self.two_finger_contacts_event, 1),
302                );
303                if displacement_mm >= self.max_finger_displacement_in_mm {
304                    return ExamineEventResult::Mismatch(Reason::DetailedFloat(
305                        DetailedReasonFloat {
306                            criterion: "displacement_mm",
307                            min: None,
308                            max: Some(self.max_finger_displacement_in_mm),
309                            actual: displacement_mm,
310                        },
311                    ));
312                }
313
314                ExamineEventResult::Contender(self)
315            }
316            3.. => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
317                criterion: "num_contacts",
318                min: Some(0),
319                max: Some(2),
320                actual: usize::from(num_contacts),
321            })),
322        }
323    }
324}
325
326/// The state when this recognizer has already detected two fingers down,
327/// and one of those fingers has been raised.
328#[derive(Debug)]
329struct OneFingerRaisedContender {
330    /// The TouchpadEvent when two fingers were first detected.
331    two_finger_contacts_event: TouchpadEvent,
332
333    /// The maximum displacement that a detected finger can withstand to still
334    /// be considered a tap. Measured in millimeters.
335    max_finger_displacement_in_mm: f32,
336
337    /// The maximum time that can elapse between two fingers down and fingers up
338    /// to be considered a secondary tap gesture.
339    max_time_elapsed: zx::MonotonicDuration,
340}
341
342impl OneFingerRaisedContender {
343    #[allow(clippy::boxed_local, reason = "mass allow for https://fxbug.dev/381896734")]
344    fn into_matched_contender(
345        self: Box<Self>,
346        no_contacts_event: TouchpadEvent,
347    ) -> Box<dyn gesture_arena::MatchedContender> {
348        Box::new(MatchedContender {
349            two_finger_contacts_event: self.two_finger_contacts_event,
350            no_contacts_event,
351            max_time_elapsed: self.max_time_elapsed,
352        })
353    }
354}
355
356impl gesture_arena::Contender for OneFingerRaisedContender {
357    fn examine_event(self: Box<Self>, event: &TouchpadEvent) -> ExamineEventResult {
358        let elapsed_time = event.timestamp - self.two_finger_contacts_event.timestamp;
359        if elapsed_time >= self.max_time_elapsed {
360            return ExamineEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
361                criterion: "elapsed_time_micros",
362                min: None,
363                max: Some(self.max_time_elapsed.into_micros()),
364                actual: elapsed_time.into_micros(),
365            }));
366        }
367
368        let num_pressed_buttons = event.pressed_buttons.len();
369        if num_pressed_buttons != 0 {
370            return ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
371                criterion: "num_pressed_buttons",
372                min: Some(0),
373                max: Some(0),
374                actual: num_pressed_buttons,
375            }));
376        }
377
378        let num_contacts = u8::try_from(event.contacts.len()).unwrap_or(u8::MAX);
379        match num_contacts {
380            0 => ExamineEventResult::MatchedContender(self.into_matched_contender(event.clone())),
381            1 => {
382                match &self
383                    .two_finger_contacts_event
384                    .clone()
385                    .contacts
386                    .into_iter()
387                    .find(|contact| contact.id == event.contacts[0].id)
388                {
389                    Some(contact) => {
390                        let displacement_mm =
391                            euclidean_distance(position_from_event(event, 0), contact.position);
392                        if displacement_mm >= self.max_finger_displacement_in_mm {
393                            return ExamineEventResult::Mismatch(Reason::DetailedFloat(
394                                DetailedReasonFloat {
395                                    criterion: "displacement_mm",
396                                    min: None,
397                                    max: Some(self.max_finger_displacement_in_mm),
398                                    actual: displacement_mm,
399                                },
400                            ));
401                        }
402                    }
403                    None => {
404                        return ExamineEventResult::Mismatch(Reason::Basic(
405                            "remaining contact id differs from initial two finger contacts",
406                        ));
407                    }
408                }
409
410                ExamineEventResult::Contender(self)
411            }
412            2.. => ExamineEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
413                criterion: "num_contacts",
414                min: Some(0),
415                max: Some(1),
416                actual: usize::from(num_contacts),
417            })),
418        }
419    }
420}
421
422/// The state when this recognizer has detected a secondary tap, but the
423/// gesture arena has not declared this recognizer the winner.
424#[derive(Debug)]
425struct MatchedContender {
426    /// The TouchpadEvent when two fingers were first detected.
427    two_finger_contacts_event: TouchpadEvent,
428
429    /// The TouchpadEvent when two fingers, previously detected, were released.
430    no_contacts_event: TouchpadEvent,
431
432    /// The maximum time that can elapse between two fingers down and fingers up
433    /// to be considered a secondary tap gesture.
434    max_time_elapsed: zx::MonotonicDuration,
435}
436
437impl gesture_arena::MatchedContender for MatchedContender {
438    fn verify_event(self: Box<Self>, event: &TouchpadEvent) -> VerifyEventResult {
439        let elapsed_time = event.timestamp - self.two_finger_contacts_event.timestamp;
440        if elapsed_time >= self.max_time_elapsed {
441            return VerifyEventResult::Mismatch(Reason::DetailedInt(DetailedReasonInt {
442                criterion: "elapsed_time_micros",
443                min: None,
444                max: Some(self.max_time_elapsed.into_micros()),
445                actual: elapsed_time.into_micros(),
446            }));
447        }
448
449        let num_contacts = event.contacts.len();
450        if num_contacts != 0 {
451            return VerifyEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
452                criterion: "num_contacts",
453                min: Some(0),
454                max: Some(0),
455                actual: num_contacts,
456            }));
457        }
458
459        let num_pressed_buttons = event.pressed_buttons.len();
460        if num_pressed_buttons != 0 {
461            return VerifyEventResult::Mismatch(Reason::DetailedUint(DetailedReasonUint {
462                criterion: "num_pressed_buttons",
463                min: Some(0),
464                max: Some(0),
465                actual: num_pressed_buttons,
466            }));
467        }
468
469        VerifyEventResult::MatchedContender(self)
470    }
471
472    fn process_buffered_events(
473        self: Box<Self>,
474        _events: Vec<TouchpadEvent>,
475    ) -> ProcessBufferedEventsResult {
476        ProcessBufferedEventsResult {
477            generated_events: vec![
478                gesture_arena::MouseEvent {
479                    timestamp: self.two_finger_contacts_event.timestamp,
480                    mouse_data: MouseEvent {
481                        location: MouseLocation::Relative(RelativeLocation {
482                            millimeters: Position::zero(),
483                        }),
484                        wheel_delta_v: None,
485                        wheel_delta_h: None,
486                        phase: MousePhase::Down,
487                        affected_buttons: hashset! {SECONDARY_BUTTON},
488                        pressed_buttons: hashset! {SECONDARY_BUTTON},
489                        is_precision_scroll: None,
490                    },
491                },
492                gesture_arena::MouseEvent {
493                    timestamp: self.no_contacts_event.timestamp,
494                    mouse_data: MouseEvent {
495                        location: MouseLocation::Relative(RelativeLocation {
496                            millimeters: Position::zero(),
497                        }),
498                        wheel_delta_v: None,
499                        wheel_delta_h: None,
500                        phase: MousePhase::Up,
501                        affected_buttons: hashset! {SECONDARY_BUTTON},
502                        pressed_buttons: hashset! {},
503                        is_precision_scroll: None,
504                    },
505                },
506            ],
507            winner: None,
508            recognized_gesture: RecognizedGesture::SecondaryTap,
509        }
510    }
511}
512
513/// This function returns the position associated with the touch contact at the
514/// given index from a TouchpadEvent.
515fn position_from_event(event: &TouchpadEvent, index: usize) -> Position {
516    event.contacts[index].position
517}
518
519#[cfg(test)]
520mod tests {
521    use super::*;
522    use crate::gestures::gesture_arena::{Contender, MatchedContender as _};
523    use crate::testing_utilities::create_touch_contact;
524    use assert_matches::assert_matches;
525    use std::any::TypeId;
526
527    const MAX_TIME_ELAPSED: zx::MonotonicDuration = zx::MonotonicDuration::from_nanos(10000);
528    const MAX_FINGER_DISPLACEMENT_IN_MM: f32 = 10.0;
529    const HALF_MOTION: f32 = MAX_FINGER_DISPLACEMENT_IN_MM / 2.0;
530
531    fn get_initial_contender() -> Box<InitialContender> {
532        Box::new(InitialContender {
533            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
534            max_time_elapsed: MAX_TIME_ELAPSED,
535        })
536    }
537
538    fn get_one_finger_contact_contender() -> Box<OneFingerContactContender> {
539        Box::new(OneFingerContactContender {
540            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
541            max_time_elapsed: MAX_TIME_ELAPSED,
542            one_finger_contact_event: TouchpadEvent {
543                contacts: vec![create_touch_contact(0, Position::zero())],
544                timestamp: zx::MonotonicInstant::from_nanos(0),
545                pressed_buttons: vec![],
546                filtered_palm_contacts: vec![],
547            },
548        })
549    }
550
551    fn get_two_finger_contacts_contender() -> Box<TwoFingerContactsContender> {
552        Box::new(TwoFingerContactsContender {
553            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
554            max_time_elapsed: MAX_TIME_ELAPSED,
555            two_finger_contacts_event: TouchpadEvent {
556                contacts: vec![
557                    create_touch_contact(0, Position::zero()),
558                    create_touch_contact(1, Position::zero()),
559                ],
560                timestamp: zx::MonotonicInstant::from_nanos(0),
561                pressed_buttons: vec![],
562                filtered_palm_contacts: vec![],
563            },
564        })
565    }
566
567    fn get_one_finger_raised_contender() -> Box<OneFingerRaisedContender> {
568        Box::new(OneFingerRaisedContender {
569            max_finger_displacement_in_mm: MAX_FINGER_DISPLACEMENT_IN_MM,
570            max_time_elapsed: MAX_TIME_ELAPSED,
571            two_finger_contacts_event: TouchpadEvent {
572                contacts: vec![
573                    create_touch_contact(0, Position::zero()),
574                    create_touch_contact(1, Position::zero()),
575                ],
576                timestamp: zx::MonotonicInstant::from_nanos(0),
577                pressed_buttons: vec![],
578                filtered_palm_contacts: vec![],
579            },
580        })
581    }
582
583    fn get_matched_contender() -> Box<MatchedContender> {
584        Box::new(MatchedContender {
585            two_finger_contacts_event: TouchpadEvent {
586                contacts: vec![
587                    create_touch_contact(0, Position::zero()),
588                    create_touch_contact(1, Position::zero()),
589                ],
590                timestamp: zx::MonotonicInstant::from_nanos(0),
591                pressed_buttons: vec![],
592                filtered_palm_contacts: vec![],
593            },
594            no_contacts_event: TouchpadEvent {
595                contacts: vec![],
596                timestamp: zx::MonotonicInstant::from_nanos(123),
597                pressed_buttons: vec![],
598                filtered_palm_contacts: vec![],
599            },
600            max_time_elapsed: MAX_TIME_ELAPSED,
601        })
602    }
603
604    fn assert_contender(result: ExamineEventResult, type_id: TypeId) {
605        match result {
606            ExamineEventResult::Contender(boxed) => {
607                assert_eq!((&*boxed).as_any().type_id(), type_id);
608            }
609            other => panic!("Expected a Contender but found {:?}", other),
610        }
611    }
612
613    fn assert_examined_matched_contender(result: ExamineEventResult) {
614        match result {
615            ExamineEventResult::MatchedContender(boxed) => {
616                assert_eq!((&*boxed).as_any().type_id(), TypeId::of::<MatchedContender>());
617            }
618            other => panic!("Expected a MatchedContender but found {:?}", other),
619        }
620    }
621
622    fn assert_verified_matched_contender(result: VerifyEventResult) {
623        match result {
624            VerifyEventResult::MatchedContender(boxed) => {
625                assert_eq!((&*boxed).as_any().type_id(), TypeId::of::<MatchedContender>());
626            }
627            other => panic!("Expected a MatchedContender but found {:?}", other),
628        }
629    }
630
631    /// Tests that an InitialContender with a single touch contact and one
632    /// pressed button yields a Mismatch.
633    #[fuchsia::test]
634    fn contender_single_button() {
635        assert_matches!(
636            get_initial_contender().examine_event(&TouchpadEvent {
637                contacts: vec![create_touch_contact(0, Position::zero())],
638                timestamp: zx::MonotonicInstant::from_nanos(0),
639                pressed_buttons: vec![0],
640                filtered_palm_contacts: vec![],
641            },),
642            ExamineEventResult::Mismatch(_)
643        );
644    }
645
646    /// Tests that an InitialContender with a single touch contact and multiple
647    /// pressed button yields a Mismatch.
648    #[fuchsia::test]
649    fn contender_many_buttons() {
650        assert_matches!(
651            get_initial_contender().examine_event(&TouchpadEvent {
652                contacts: vec![create_touch_contact(0, Position::zero())],
653                timestamp: zx::MonotonicInstant::from_nanos(0),
654                pressed_buttons: vec![0, 1],
655                filtered_palm_contacts: vec![],
656            },),
657            ExamineEventResult::Mismatch(_)
658        );
659    }
660
661    /// Tests that an InitialContender with zero touch contacts yields a
662    /// Mismatch.
663    #[fuchsia::test]
664    fn contender_no_contacts() {
665        assert_matches!(
666            get_initial_contender().examine_event(&TouchpadEvent {
667                contacts: vec![],
668                timestamp: zx::MonotonicInstant::from_nanos(0),
669                pressed_buttons: vec![],
670                filtered_palm_contacts: vec![],
671            }),
672            ExamineEventResult::Mismatch(_)
673        );
674    }
675
676    /// Tests that an InitialContender with a single touch contact and no
677    /// pressed buttons yields a OneFingerContactContender.
678    #[fuchsia::test]
679    fn contender_one_contact() {
680        assert_contender(
681            get_initial_contender().examine_event(&TouchpadEvent {
682                contacts: vec![create_touch_contact(0, Position::zero())],
683                timestamp: zx::MonotonicInstant::from_nanos(0),
684                pressed_buttons: vec![],
685                filtered_palm_contacts: vec![],
686            }),
687            TypeId::of::<OneFingerContactContender>(),
688        );
689    }
690
691    /// Tests that an InitialContender with two touch contacts and no pressed
692    /// buttons yields a TwoFingerContactsContender.
693    #[fuchsia::test]
694    fn contender_two_contacts() {
695        assert_contender(
696            get_initial_contender().examine_event(&TouchpadEvent {
697                contacts: vec![
698                    create_touch_contact(0, Position::zero()),
699                    create_touch_contact(1, Position::zero()),
700                ],
701                timestamp: zx::MonotonicInstant::from_nanos(0),
702                pressed_buttons: vec![],
703                filtered_palm_contacts: vec![],
704            }),
705            TypeId::of::<TwoFingerContactsContender>(),
706        );
707    }
708
709    /// Tests that an InitialContender with more than two touch contacts yields
710    /// a Mismatch.
711    #[fuchsia::test]
712    fn contender_many_contacts() {
713        assert_matches!(
714            get_initial_contender().examine_event(&TouchpadEvent {
715                contacts: vec![
716                    create_touch_contact(0, Position::zero()),
717                    create_touch_contact(1, Position::zero()),
718                    create_touch_contact(2, Position::zero())
719                ],
720                timestamp: zx::MonotonicInstant::from_nanos(0),
721                pressed_buttons: vec![],
722                filtered_palm_contacts: vec![],
723            }),
724            ExamineEventResult::Mismatch(_)
725        );
726    }
727
728    /// Tests that a OneFingerContactContender with an event whose timestamp
729    /// exceeds the elapsed threshold yields a Mismatch.
730    #[fuchsia::test]
731    fn one_finger_contact_contender_too_long() {
732        assert_matches!(
733            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
734                contacts: vec![create_touch_contact(0, Position::zero()),],
735                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
736                pressed_buttons: vec![],
737                filtered_palm_contacts: vec![],
738            }),
739            ExamineEventResult::Mismatch(_)
740        );
741    }
742
743    /// Tests that a OneFingerContactContender with one pressed button yields a
744    /// Mismatch.
745    #[fuchsia::test]
746    fn one_finger_contact_contender_single_button() {
747        assert_matches!(
748            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
749                contacts: vec![create_touch_contact(0, Position::zero())],
750                timestamp: zx::MonotonicInstant::from_nanos(0),
751                pressed_buttons: vec![0],
752                filtered_palm_contacts: vec![],
753            }),
754            ExamineEventResult::Mismatch(_)
755        );
756    }
757
758    /// Tests that a OneFingerContactContender with multiple pressed buttons
759    /// yields a Mismatch.
760    #[fuchsia::test]
761    fn one_finger_contact_contender_many_buttons() {
762        assert_matches!(
763            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
764                contacts: vec![create_touch_contact(0, Position::zero())],
765                timestamp: zx::MonotonicInstant::from_nanos(0),
766                pressed_buttons: vec![0, 1],
767                filtered_palm_contacts: vec![],
768            }),
769            ExamineEventResult::Mismatch(_)
770        );
771    }
772
773    /// Tests that a OneFingerContactContender with zero touch contacts yields a
774    /// Mismatch.
775    #[fuchsia::test]
776    fn one_finger_contact_contender_no_contacts() {
777        assert_matches!(
778            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
779                contacts: vec![],
780                timestamp: zx::MonotonicInstant::from_nanos(0),
781                pressed_buttons: vec![],
782                filtered_palm_contacts: vec![],
783            }),
784            ExamineEventResult::Mismatch(_)
785        );
786    }
787
788    /// Tests that a OneFingerContactContender with more than two touch contacts
789    /// yields a Mismatch.
790    #[fuchsia::test]
791    fn one_finger_contact_contender_many_touch_contacts() {
792        assert_matches!(
793            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
794                contacts: vec![
795                    create_touch_contact(0, Position::zero()),
796                    create_touch_contact(1, Position::zero()),
797                    create_touch_contact(2, Position::zero())
798                ],
799                timestamp: zx::MonotonicInstant::from_nanos(0),
800                pressed_buttons: vec![],
801                filtered_palm_contacts: vec![],
802            }),
803            ExamineEventResult::Mismatch(_)
804        );
805    }
806
807    /// Tests that a OneFingerContactContender with one touch contact yields
808    /// a OneFingerContactContender.
809    #[fuchsia::test]
810    fn one_finger_contact_contender_one_contact() {
811        assert_contender(
812            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
813                contacts: vec![create_touch_contact(0, Position::zero())],
814                timestamp: zx::MonotonicInstant::from_nanos(0),
815                pressed_buttons: vec![],
816                filtered_palm_contacts: vec![],
817            }),
818            TypeId::of::<OneFingerContactContender>(),
819        );
820    }
821
822    /// Tests that a OneFingerContactContender with two touch contacts yields
823    /// a TwoFingerContactsContender.
824    #[fuchsia::test]
825    fn one_finger_contact_contender_two_touch_contacts() {
826        assert_contender(
827            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
828                contacts: vec![
829                    create_touch_contact(0, Position::zero()),
830                    create_touch_contact(1, Position::zero()),
831                ],
832                timestamp: zx::MonotonicInstant::from_nanos(0),
833                pressed_buttons: vec![],
834                filtered_palm_contacts: vec![],
835            }),
836            TypeId::of::<TwoFingerContactsContender>(),
837        );
838    }
839
840    /// Tests that a OneFingerContactContender with a single touch contact and
841    /// too much displacement yields a Mismatch.
842    #[fuchsia::test]
843    fn one_finger_contact_contender_one_contact_large_displacement() {
844        assert_matches!(
845            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
846                contacts: vec![create_touch_contact(
847                    0,
848                    Position { x: MAX_FINGER_DISPLACEMENT_IN_MM, y: MAX_FINGER_DISPLACEMENT_IN_MM }
849                )],
850                timestamp: zx::MonotonicInstant::from_nanos(0),
851                pressed_buttons: vec![],
852                filtered_palm_contacts: vec![],
853            }),
854            ExamineEventResult::Mismatch(_)
855        );
856    }
857
858    /// Tests that a OneFingerContactContender with two touch contacts and
859    /// one with too much displacement yields a Mismatch.
860    #[fuchsia::test]
861    fn one_finger_contact_contender_two_contacts_large_displacement() {
862        assert_matches!(
863            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
864                contacts: vec![
865                    create_touch_contact(
866                        0,
867                        Position {
868                            x: MAX_FINGER_DISPLACEMENT_IN_MM,
869                            y: MAX_FINGER_DISPLACEMENT_IN_MM
870                        }
871                    ),
872                    create_touch_contact(1, Position::zero())
873                ],
874                timestamp: zx::MonotonicInstant::from_nanos(0),
875                pressed_buttons: vec![],
876                filtered_palm_contacts: vec![],
877            }),
878            ExamineEventResult::Mismatch(_)
879        );
880    }
881
882    /// Tests that a OneFingerContactContender with a single touch contact
883    /// and acceptable displacement yields a OneFingerContactContender.
884    #[fuchsia::test]
885    fn one_finger_contact_contender_one_contact_some_displacement() {
886        assert_contender(
887            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
888                contacts: vec![create_touch_contact(
889                    0,
890                    Position { x: HALF_MOTION, y: HALF_MOTION },
891                )],
892                timestamp: zx::MonotonicInstant::from_nanos(0),
893                pressed_buttons: vec![],
894                filtered_palm_contacts: vec![],
895            }),
896            TypeId::of::<OneFingerContactContender>(),
897        );
898    }
899
900    /// Tests that a OneFingerContactContender with a two touch contacts
901    /// and one with acceptable displacement yields a OneFingerContactContender.
902    #[fuchsia::test]
903    fn one_finger_contact_contender_two_contacts_some_displacement() {
904        assert_contender(
905            get_one_finger_contact_contender().examine_event(&TouchpadEvent {
906                contacts: vec![
907                    create_touch_contact(0, Position { x: HALF_MOTION, y: HALF_MOTION }),
908                    create_touch_contact(1, Position::zero()),
909                ],
910                timestamp: zx::MonotonicInstant::from_nanos(0),
911                pressed_buttons: vec![],
912                filtered_palm_contacts: vec![],
913            }),
914            TypeId::of::<TwoFingerContactsContender>(),
915        );
916    }
917
918    /// Tests that a TwoFingerContactsContender with an event whose timestamp
919    /// exceeds the elapsed threshold yields a Mismatch.
920    #[fuchsia::test]
921    fn two_finger_contacts_contender_too_long() {
922        assert_matches!(
923            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
924                contacts: vec![],
925                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
926                pressed_buttons: vec![],
927                filtered_palm_contacts: vec![],
928            }),
929            ExamineEventResult::Mismatch(_)
930        );
931    }
932
933    /// Tests that a TwoFingerContactsContender with one pressed button yields a
934    /// Mismatch.
935    #[fuchsia::test]
936    fn two_finger_contacts_contender_single_button() {
937        assert_matches!(
938            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
939                contacts: vec![],
940                timestamp: zx::MonotonicInstant::from_nanos(0),
941                pressed_buttons: vec![0],
942                filtered_palm_contacts: vec![],
943            }),
944            ExamineEventResult::Mismatch(_)
945        );
946    }
947
948    /// Tests that a TwoFingerContactsContender with multiple pressed buttons
949    /// yields a Mismatch.
950    #[fuchsia::test]
951    fn two_finger_contacts_contender_many_buttons() {
952        assert_matches!(
953            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
954                contacts: vec![],
955                timestamp: zx::MonotonicInstant::from_nanos(0),
956                pressed_buttons: vec![0, 1],
957                filtered_palm_contacts: vec![],
958            }),
959            ExamineEventResult::Mismatch(_)
960        );
961    }
962
963    /// Tests that a TwoFingerContactsContender with zero touch contacts yields a
964    /// MatchedContender.
965    #[fuchsia::test]
966    fn two_finger_contacts_contender_no_touch_contacts() {
967        assert_examined_matched_contender(get_two_finger_contacts_contender().examine_event(
968            &TouchpadEvent {
969                contacts: vec![],
970                timestamp: zx::MonotonicInstant::from_nanos(0),
971                pressed_buttons: vec![],
972                filtered_palm_contacts: vec![],
973            },
974        ));
975    }
976
977    /// Tests that a TwoFingerContactsContender with one touch contact with
978    /// acceptable displacement yields a OneFingerRaisedContender.
979    #[fuchsia::test]
980    fn two_finger_contacts_contender_one_contact() {
981        assert_contender(
982            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
983                contacts: vec![create_touch_contact(0, Position::zero())],
984                timestamp: zx::MonotonicInstant::from_nanos(0),
985                pressed_buttons: vec![],
986                filtered_palm_contacts: vec![],
987            }),
988            TypeId::of::<OneFingerRaisedContender>(),
989        );
990    }
991
992    /// Tests that a TwoFingerContactsContender with one touch contact with
993    /// too much displacement yields a Mismatch.
994    #[fuchsia::test]
995    fn two_finger_contacts_contender_one_contact_large_displacement() {
996        assert_matches!(
997            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
998                contacts: vec![create_touch_contact(
999                    0,
1000                    Position { x: MAX_FINGER_DISPLACEMENT_IN_MM, y: MAX_FINGER_DISPLACEMENT_IN_MM },
1001                )],
1002                timestamp: zx::MonotonicInstant::from_nanos(0),
1003                pressed_buttons: vec![],
1004                filtered_palm_contacts: vec![],
1005            }),
1006            ExamineEventResult::Mismatch(_)
1007        );
1008    }
1009
1010    /// Tests that a TwoFingerContactsContender with more than two touch contacts
1011    /// yields a Mismatch.
1012    #[fuchsia::test]
1013    fn two_finger_contacts_contender_many_touch_contacts() {
1014        assert_matches!(
1015            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1016                contacts: vec![
1017                    create_touch_contact(0, Position::zero()),
1018                    create_touch_contact(1, Position::zero()),
1019                    create_touch_contact(2, Position::zero())
1020                ],
1021                timestamp: zx::MonotonicInstant::from_nanos(0),
1022                pressed_buttons: vec![],
1023                filtered_palm_contacts: vec![],
1024            }),
1025            ExamineEventResult::Mismatch(_)
1026        );
1027    }
1028
1029    /// Tests that a TwoFingerContactsContender with two touch contacts yields
1030    /// a TwoFingerContactsContender.
1031    #[fuchsia::test]
1032    fn two_finger_contacts_contender_two_touch_contacts() {
1033        assert_contender(
1034            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1035                contacts: vec![
1036                    create_touch_contact(0, Position::zero()),
1037                    create_touch_contact(1, Position::zero()),
1038                ],
1039                timestamp: zx::MonotonicInstant::from_nanos(0),
1040                pressed_buttons: vec![],
1041                filtered_palm_contacts: vec![],
1042            }),
1043            TypeId::of::<TwoFingerContactsContender>(),
1044        );
1045    }
1046
1047    /// Tests that a TwoFingerContactsContender with two touch contacts and
1048    /// one with too much displacement yields a Mismatch.
1049    #[fuchsia::test]
1050    fn two_finger_contacts_contender_two_contacts_large_displacement() {
1051        assert_matches!(
1052            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1053                contacts: vec![
1054                    create_touch_contact(
1055                        0,
1056                        Position {
1057                            x: MAX_FINGER_DISPLACEMENT_IN_MM,
1058                            y: MAX_FINGER_DISPLACEMENT_IN_MM
1059                        }
1060                    ),
1061                    create_touch_contact(1, Position::zero())
1062                ],
1063                timestamp: zx::MonotonicInstant::from_nanos(0),
1064                pressed_buttons: vec![],
1065                filtered_palm_contacts: vec![],
1066            }),
1067            ExamineEventResult::Mismatch(_)
1068        );
1069
1070        assert_matches!(
1071            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1072                contacts: vec![
1073                    create_touch_contact(0, Position::zero()),
1074                    create_touch_contact(
1075                        1,
1076                        Position {
1077                            x: MAX_FINGER_DISPLACEMENT_IN_MM,
1078                            y: MAX_FINGER_DISPLACEMENT_IN_MM
1079                        }
1080                    ),
1081                ],
1082                timestamp: zx::MonotonicInstant::from_nanos(0),
1083                pressed_buttons: vec![],
1084                filtered_palm_contacts: vec![],
1085            }),
1086            ExamineEventResult::Mismatch(_)
1087        );
1088    }
1089
1090    /// Tests that a TwoFingerContactsContender with two touch contact
1091    /// and acceptable displacement yields a TwoFingerContactsContender.
1092    #[fuchsia::test]
1093    fn two_finger_contacts_contender_two_contacts_some_displacement() {
1094        assert_contender(
1095            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1096                contacts: vec![
1097                    create_touch_contact(0, Position::zero()),
1098                    create_touch_contact(1, Position { x: HALF_MOTION, y: HALF_MOTION }),
1099                ],
1100                timestamp: zx::MonotonicInstant::from_nanos(0),
1101                pressed_buttons: vec![],
1102                filtered_palm_contacts: vec![],
1103            }),
1104            TypeId::of::<TwoFingerContactsContender>(),
1105        );
1106
1107        assert_contender(
1108            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1109                contacts: vec![
1110                    create_touch_contact(0, Position { x: HALF_MOTION, y: HALF_MOTION }),
1111                    create_touch_contact(1, Position::zero()),
1112                ],
1113                timestamp: zx::MonotonicInstant::from_nanos(0),
1114                pressed_buttons: vec![],
1115                filtered_palm_contacts: vec![],
1116            }),
1117            TypeId::of::<TwoFingerContactsContender>(),
1118        );
1119
1120        assert_contender(
1121            get_two_finger_contacts_contender().examine_event(&TouchpadEvent {
1122                contacts: vec![
1123                    create_touch_contact(0, Position { x: HALF_MOTION, y: HALF_MOTION }),
1124                    create_touch_contact(1, Position { x: HALF_MOTION, y: HALF_MOTION }),
1125                ],
1126                timestamp: zx::MonotonicInstant::from_nanos(0),
1127                pressed_buttons: vec![],
1128                filtered_palm_contacts: vec![],
1129            }),
1130            TypeId::of::<TwoFingerContactsContender>(),
1131        );
1132    }
1133
1134    /// Tests that a OneFingerRaisedContender with an event whose timestamp
1135    /// exceeds the elapsed threshold yields a Mismatch.
1136    #[fuchsia::test]
1137    fn one_finger_raised_contender_too_long() {
1138        assert_matches!(
1139            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1140                contacts: vec![],
1141                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
1142                pressed_buttons: vec![],
1143                filtered_palm_contacts: vec![],
1144            }),
1145            ExamineEventResult::Mismatch(_)
1146        );
1147    }
1148
1149    /// Tests that a OneFingerRaisedContender with one pressed button yields a
1150    /// Mismatch.
1151    #[fuchsia::test]
1152    fn one_finger_raised_contender_single_button() {
1153        assert_matches!(
1154            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1155                contacts: vec![],
1156                timestamp: zx::MonotonicInstant::from_nanos(0),
1157                pressed_buttons: vec![0],
1158                filtered_palm_contacts: vec![],
1159            }),
1160            ExamineEventResult::Mismatch(_)
1161        );
1162    }
1163
1164    /// Tests that a OneFingerRaisedContender with multiple pressed buttons
1165    /// yields a Mismatch.
1166    #[fuchsia::test]
1167    fn one_finger_raised_contender_many_buttons() {
1168        assert_matches!(
1169            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1170                contacts: vec![],
1171                timestamp: zx::MonotonicInstant::from_nanos(0),
1172                pressed_buttons: vec![0, 1],
1173                filtered_palm_contacts: vec![],
1174            }),
1175            ExamineEventResult::Mismatch(_)
1176        );
1177    }
1178
1179    /// Tests that a OneFingerRaisedContender with zero touch contacts yields a
1180    /// MatchedContender.
1181    #[fuchsia::test]
1182    fn one_finger_raised_contender_no_touch_contacts() {
1183        assert_examined_matched_contender(get_one_finger_raised_contender().examine_event(
1184            &TouchpadEvent {
1185                contacts: vec![],
1186                timestamp: zx::MonotonicInstant::from_nanos(0),
1187                pressed_buttons: vec![],
1188                filtered_palm_contacts: vec![],
1189            },
1190        ));
1191    }
1192
1193    /// Tests that a OneFingerRaisedContender with one touch contact with
1194    /// acceptable displacement against first recorded contact yields a
1195    /// OneFingerRaisedContender.
1196    #[fuchsia::test]
1197    fn one_finger_raised_contender_one_contact_first_id() {
1198        assert_contender(
1199            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1200                contacts: vec![create_touch_contact(0, Position::zero())],
1201                timestamp: zx::MonotonicInstant::from_nanos(0),
1202                pressed_buttons: vec![],
1203                filtered_palm_contacts: vec![],
1204            }),
1205            TypeId::of::<OneFingerRaisedContender>(),
1206        );
1207
1208        assert_contender(
1209            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1210                contacts: vec![create_touch_contact(
1211                    0,
1212                    Position { x: HALF_MOTION, y: HALF_MOTION },
1213                )],
1214                timestamp: zx::MonotonicInstant::from_nanos(0),
1215                pressed_buttons: vec![],
1216                filtered_palm_contacts: vec![],
1217            }),
1218            TypeId::of::<OneFingerRaisedContender>(),
1219        );
1220    }
1221
1222    /// Tests that a OneFingerRaisedContender with one touch contact with
1223    /// acceptable displacement against second recorded contact yields a
1224    /// OneFingerRaisedContender.
1225    #[fuchsia::test]
1226    fn one_finger_raised_contender_one_contact_second_id() {
1227        assert_contender(
1228            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1229                contacts: vec![create_touch_contact(1, Position::zero())],
1230                timestamp: zx::MonotonicInstant::from_nanos(0),
1231                pressed_buttons: vec![],
1232                filtered_palm_contacts: vec![],
1233            }),
1234            TypeId::of::<OneFingerRaisedContender>(),
1235        );
1236
1237        assert_contender(
1238            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1239                contacts: vec![create_touch_contact(
1240                    1,
1241                    Position { x: HALF_MOTION, y: HALF_MOTION },
1242                )],
1243                timestamp: zx::MonotonicInstant::from_nanos(0),
1244                pressed_buttons: vec![],
1245                filtered_palm_contacts: vec![],
1246            }),
1247            TypeId::of::<OneFingerRaisedContender>(),
1248        );
1249    }
1250
1251    /// Tests that a OneFingerRaisedContender with one touch contact with
1252    /// acceptable displacement against an unrecorded contact id yields a
1253    /// Mismatch.
1254    #[fuchsia::test]
1255    fn one_finger_raised_contender_one_contact_invalid_id() {
1256        assert_matches!(
1257            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1258                contacts: vec![create_touch_contact(2, Position::zero(),)],
1259                timestamp: zx::MonotonicInstant::from_nanos(0),
1260                pressed_buttons: vec![],
1261                filtered_palm_contacts: vec![],
1262            }),
1263            ExamineEventResult::Mismatch(_)
1264        );
1265    }
1266
1267    /// Tests that a OneFingerRaisedContender with one touch contact with
1268    /// too much displacement yields a Mismatch.
1269    #[fuchsia::test]
1270    fn one_finger_raised_contender_one_contact_large_displacement() {
1271        assert_matches!(
1272            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1273                contacts: vec![create_touch_contact(
1274                    0,
1275                    Position { x: MAX_FINGER_DISPLACEMENT_IN_MM, y: MAX_FINGER_DISPLACEMENT_IN_MM },
1276                )],
1277                timestamp: zx::MonotonicInstant::from_nanos(0),
1278                pressed_buttons: vec![],
1279                filtered_palm_contacts: vec![],
1280            }),
1281            ExamineEventResult::Mismatch(_)
1282        );
1283    }
1284
1285    /// Tests that a OneFingerRaisedContender with more than one touch contacts
1286    /// yields a Mismatch.
1287    #[fuchsia::test]
1288    fn one_finger_raised_contender_many_touch_contacts() {
1289        assert_matches!(
1290            get_one_finger_raised_contender().examine_event(&TouchpadEvent {
1291                contacts: vec![
1292                    create_touch_contact(0, Position::zero()),
1293                    create_touch_contact(1, Position::zero()),
1294                ],
1295                timestamp: zx::MonotonicInstant::from_nanos(0),
1296                pressed_buttons: vec![],
1297                filtered_palm_contacts: vec![],
1298            }),
1299            ExamineEventResult::Mismatch(_)
1300        );
1301    }
1302
1303    /// Tests that a MatchedContender with an event whose timestamp exceeds
1304    /// the elapsed threshold yields a Mismatch.
1305    #[fuchsia::test]
1306    fn matched_contender_too_long() {
1307        assert_matches!(
1308            get_matched_contender().verify_event(&TouchpadEvent {
1309                contacts: vec![],
1310                timestamp: MAX_TIME_ELAPSED + zx::MonotonicInstant::from_nanos(1),
1311                pressed_buttons: vec![],
1312                filtered_palm_contacts: vec![],
1313            }),
1314            VerifyEventResult::Mismatch(_)
1315        );
1316    }
1317
1318    /// Tests that a MatchedContender with one touch contact yields a Mismatch.
1319    #[fuchsia::test]
1320    fn matched_contender_one_contact() {
1321        assert_matches!(
1322            get_matched_contender().verify_event(&TouchpadEvent {
1323                contacts: vec![create_touch_contact(0, Position::zero())],
1324                timestamp: zx::MonotonicInstant::from_nanos(0),
1325                pressed_buttons: vec![],
1326                filtered_palm_contacts: vec![],
1327            }),
1328            VerifyEventResult::Mismatch(_)
1329        );
1330    }
1331
1332    /// Tests that a MatchedContender with multiple touch contacts yields a
1333    /// Mismatch.
1334    #[fuchsia::test]
1335    fn matched_contender_many_contacts() {
1336        assert_matches!(
1337            get_matched_contender().verify_event(&TouchpadEvent {
1338                contacts: vec![
1339                    create_touch_contact(0, Position::zero()),
1340                    create_touch_contact(1, Position::zero())
1341                ],
1342                timestamp: zx::MonotonicInstant::from_nanos(0),
1343                pressed_buttons: vec![],
1344                filtered_palm_contacts: vec![],
1345            }),
1346            VerifyEventResult::Mismatch(_)
1347        );
1348    }
1349
1350    /// Tests that a MatchedContender with one button pressed yields a Mismatch.
1351    #[fuchsia::test]
1352    fn matched_contender_one_button() {
1353        assert_matches!(
1354            get_matched_contender().verify_event(&TouchpadEvent {
1355                contacts: vec![],
1356                timestamp: zx::MonotonicInstant::from_nanos(0),
1357                pressed_buttons: vec![0],
1358                filtered_palm_contacts: vec![],
1359            }),
1360            VerifyEventResult::Mismatch(_)
1361        );
1362    }
1363
1364    /// Tests that a MatchedContender with multiple buttons pressed yields a
1365    /// Mismatch.
1366    #[fuchsia::test]
1367    fn matched_contender_many_buttons() {
1368        assert_matches!(
1369            get_matched_contender().verify_event(&TouchpadEvent {
1370                contacts: vec![],
1371                timestamp: zx::MonotonicInstant::from_nanos(0),
1372                pressed_buttons: vec![0, 1],
1373                filtered_palm_contacts: vec![],
1374            }),
1375            VerifyEventResult::Mismatch(_)
1376        );
1377    }
1378
1379    /// Tests that a MatchedContender with no touch contacts yields a
1380    /// MatchedContender.
1381    #[fuchsia::test]
1382    fn matched_contender_no_contacts() {
1383        assert_verified_matched_contender(get_matched_contender().verify_event(&TouchpadEvent {
1384            contacts: vec![],
1385            timestamp: zx::MonotonicInstant::from_nanos(0),
1386            pressed_buttons: vec![],
1387            filtered_palm_contacts: vec![],
1388        }));
1389    }
1390
1391    /// Tests that a MatchedContender processes buffered events by
1392    /// returning mouse down and mouse up events.
1393    #[fuchsia::test]
1394    fn matched_contender_process_buffered_events() {
1395        let ProcessBufferedEventsResult { generated_events, winner, recognized_gesture } =
1396            get_matched_contender().process_buffered_events(vec![]);
1397
1398        assert_eq!(
1399            generated_events,
1400            [
1401                gesture_arena::MouseEvent {
1402                    timestamp: zx::MonotonicInstant::from_nanos(0),
1403                    mouse_data: MouseEvent {
1404                        location: MouseLocation::Relative(RelativeLocation {
1405                            millimeters: Position { x: 0.0, y: 0.0 }
1406                        }),
1407                        wheel_delta_v: None,
1408                        wheel_delta_h: None,
1409                        phase: MousePhase::Down,
1410                        affected_buttons: hashset! {SECONDARY_BUTTON},
1411                        pressed_buttons: hashset! {SECONDARY_BUTTON},
1412                        is_precision_scroll: None,
1413                    },
1414                },
1415                gesture_arena::MouseEvent {
1416                    timestamp: zx::MonotonicInstant::from_nanos(123),
1417                    mouse_data: MouseEvent {
1418                        location: MouseLocation::Relative(RelativeLocation {
1419                            millimeters: Position { x: 0.0, y: 0.0 }
1420                        }),
1421                        wheel_delta_v: None,
1422                        wheel_delta_h: None,
1423                        phase: MousePhase::Up,
1424                        affected_buttons: hashset! {SECONDARY_BUTTON},
1425                        pressed_buttons: hashset! {},
1426                        is_precision_scroll: None,
1427                    },
1428                }
1429            ]
1430        );
1431        assert_matches!(winner, None);
1432        assert_eq!(recognized_gesture, RecognizedGesture::SecondaryTap);
1433    }
1434}