1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::utils::{Position, Size};
7use crate::{metrics, mouse_binding};
8use anyhow::{format_err, Context, Error};
9use async_trait::async_trait;
10use fidl_fuchsia_input_report::{InputDeviceProxy, InputReport};
11use fuchsia_inspect::health::Reporter;
12use fuchsia_inspect::ArrayProperty;
13use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
14use maplit::hashmap;
15use metrics_registry::*;
16use std::collections::{HashMap, HashSet};
17use {
18 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
19 fidl_fuchsia_ui_pointerinjector as pointerinjector,
20};
21
22#[derive(Clone, Debug, PartialEq)]
38pub struct TouchScreenEvent {
39 pub contacts: HashMap<fidl_ui_input::PointerEventPhase, Vec<TouchContact>>,
45
46 pub injector_contacts: HashMap<pointerinjector::EventPhase, Vec<TouchContact>>,
51
52 pub pressed_buttons: Vec<fidl_input_report::TouchButton>,
54}
55
56impl TouchScreenEvent {
57 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
58 let contacts_clone = self.injector_contacts.clone();
59 node.record_child("injector_contacts", move |contacts_node| {
60 for (phase, contacts) in contacts_clone.iter() {
61 let phase_str = match phase {
62 pointerinjector::EventPhase::Add => "add",
63 pointerinjector::EventPhase::Change => "change",
64 pointerinjector::EventPhase::Remove => "remove",
65 pointerinjector::EventPhase::Cancel => "cancel",
66 };
67 contacts_node.record_child(phase_str, move |phase_node| {
68 for contact in contacts.iter() {
69 phase_node.record_child(contact.id.to_string(), move |contact_node| {
70 contact_node
71 .record_double("position_x_mm", f64::from(contact.position.x));
72 contact_node
73 .record_double("position_y_mm", f64::from(contact.position.y));
74 if let Some(pressure) = contact.pressure {
75 contact_node.record_int("pressure", pressure);
76 }
77 if let Some(contact_size) = contact.contact_size {
78 contact_node.record_double(
79 "contact_width_mm",
80 f64::from(contact_size.width),
81 );
82 contact_node.record_double(
83 "contact_height_mm",
84 f64::from(contact_size.height),
85 );
86 }
87 });
88 }
89 });
90 }
91 });
92
93 let pressed_buttons_node =
94 node.create_string_array("pressed_buttons", self.pressed_buttons.len());
95 self.pressed_buttons.iter().enumerate().for_each(|(i, &ref button)| {
96 let button_name: String = match button {
97 fidl_input_report::TouchButton::Palm => "palm".into(),
98 unknown_value => {
99 format!("unknown({:?})", unknown_value)
100 }
101 };
102 pressed_buttons_node.set(i, &button_name);
103 });
104 node.record(pressed_buttons_node);
105 }
106}
107
108#[derive(Clone, Debug, PartialEq)]
113pub struct TouchpadEvent {
114 pub injector_contacts: Vec<TouchContact>,
117
118 pub pressed_buttons: HashSet<mouse_binding::MouseButton>,
120}
121
122impl TouchpadEvent {
123 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
124 let pressed_buttons_node =
125 node.create_uint_array("pressed_buttons", self.pressed_buttons.len());
126 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
127 pressed_buttons_node.set(i, *button);
128 });
129 node.record(pressed_buttons_node);
130
131 let contacts_clone = self.injector_contacts.clone();
133 node.record_child("injector_contacts", move |contacts_node| {
134 for contact in contacts_clone.iter() {
135 contacts_node.record_child(contact.id.to_string(), move |contact_node| {
136 contact_node.record_double("position_x_mm", f64::from(contact.position.x));
137 contact_node.record_double("position_y_mm", f64::from(contact.position.y));
138 if let Some(pressure) = contact.pressure {
139 contact_node.record_int("pressure", pressure);
140 }
141 if let Some(contact_size) = contact.contact_size {
142 contact_node
143 .record_double("contact_width_mm", f64::from(contact_size.width));
144 contact_node
145 .record_double("contact_height_mm", f64::from(contact_size.height));
146 }
147 })
148 }
149 });
150 }
151}
152
153#[derive(Clone, Copy, Debug, Eq, PartialEq)]
156pub enum TouchDeviceType {
157 TouchScreen,
158 WindowsPrecisionTouchpad,
159}
160
161#[derive(Clone, Copy, Debug, PartialEq)]
164pub struct TouchContact {
165 pub id: u32,
167
168 pub position: Position,
171
172 pub pressure: Option<i64>,
175
176 pub contact_size: Option<Size>,
179}
180
181impl Eq for TouchContact {}
182
183impl From<&fidl_fuchsia_input_report::ContactInputReport> for TouchContact {
184 fn from(fidl_contact: &fidl_fuchsia_input_report::ContactInputReport) -> TouchContact {
185 let contact_size =
186 if fidl_contact.contact_width.is_some() && fidl_contact.contact_height.is_some() {
187 Some(Size {
188 width: fidl_contact.contact_width.unwrap() as f32,
189 height: fidl_contact.contact_height.unwrap() as f32,
190 })
191 } else {
192 None
193 };
194
195 TouchContact {
196 id: fidl_contact.contact_id.unwrap_or_default(),
197 position: Position {
198 x: fidl_contact.position_x.unwrap_or_default() as f32,
199 y: fidl_contact.position_y.unwrap_or_default() as f32,
200 },
201 pressure: fidl_contact.pressure,
202 contact_size,
203 }
204 }
205}
206
207#[derive(Clone, Debug, Eq, PartialEq)]
208pub struct TouchScreenDeviceDescriptor {
209 pub device_id: u32,
211
212 pub contacts: Vec<ContactDeviceDescriptor>,
214}
215
216#[derive(Clone, Debug, Eq, PartialEq)]
217pub struct TouchpadDeviceDescriptor {
218 pub device_id: u32,
220
221 pub contacts: Vec<ContactDeviceDescriptor>,
223}
224
225#[derive(Clone, Debug, Eq, PartialEq)]
226enum TouchDeviceDescriptor {
227 TouchScreen(TouchScreenDeviceDescriptor),
228 Touchpad(TouchpadDeviceDescriptor),
229}
230
231#[derive(Clone, Debug, Eq, PartialEq)]
245pub struct ContactDeviceDescriptor {
246 pub x_range: fidl_input_report::Range,
248
249 pub y_range: fidl_input_report::Range,
251
252 pub x_unit: fidl_input_report::Unit,
254
255 pub y_unit: fidl_input_report::Unit,
257
258 pub pressure_range: Option<fidl_input_report::Range>,
260
261 pub width_range: Option<fidl_input_report::Range>,
263
264 pub height_range: Option<fidl_input_report::Range>,
266}
267
268pub struct TouchBinding {
275 event_sender: UnboundedSender<InputEvent>,
277
278 device_descriptor: TouchDeviceDescriptor,
280
281 touch_device_type: TouchDeviceType,
283
284 device_proxy: InputDeviceProxy,
286}
287
288#[async_trait]
289impl input_device::InputDeviceBinding for TouchBinding {
290 fn input_event_sender(&self) -> UnboundedSender<InputEvent> {
291 self.event_sender.clone()
292 }
293
294 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
295 match self.device_descriptor.clone() {
296 TouchDeviceDescriptor::TouchScreen(desc) => {
297 input_device::InputDeviceDescriptor::TouchScreen(desc)
298 }
299 TouchDeviceDescriptor::Touchpad(desc) => {
300 input_device::InputDeviceDescriptor::Touchpad(desc)
301 }
302 }
303 }
304}
305
306impl TouchBinding {
307 pub async fn new(
322 device_proxy: InputDeviceProxy,
323 device_id: u32,
324 input_event_sender: UnboundedSender<input_device::InputEvent>,
325 device_node: fuchsia_inspect::Node,
326 metrics_logger: metrics::MetricsLogger,
327 ) -> Result<Self, Error> {
328 let (device_binding, mut inspect_status) =
329 Self::bind_device(device_proxy.clone(), device_id, input_event_sender, device_node)
330 .await?;
331 device_binding
332 .set_touchpad_mode(true)
333 .await
334 .with_context(|| format!("enabling touchpad mode for device {}", device_id))?;
335 inspect_status.health_node.set_ok();
336 input_device::initialize_report_stream(
337 device_proxy,
338 device_binding.get_device_descriptor(),
339 device_binding.input_event_sender(),
340 inspect_status,
341 metrics_logger,
342 Self::process_reports,
343 );
344
345 Ok(device_binding)
346 }
347
348 async fn bind_device(
360 device_proxy: InputDeviceProxy,
361 device_id: u32,
362 input_event_sender: UnboundedSender<input_device::InputEvent>,
363 device_node: fuchsia_inspect::Node,
364 ) -> Result<(Self, InputDeviceStatus), Error> {
365 let mut input_device_status = InputDeviceStatus::new(device_node);
366 let device_descriptor: fidl_input_report::DeviceDescriptor = match device_proxy
367 .get_descriptor()
368 .await
369 {
370 Ok(descriptor) => descriptor,
371 Err(_) => {
372 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
373 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
374 }
375 };
376
377 let touch_device_type = get_device_type(&device_proxy).await;
378
379 match device_descriptor.touch {
380 Some(fidl_fuchsia_input_report::TouchDescriptor {
381 input:
382 Some(fidl_fuchsia_input_report::TouchInputDescriptor {
383 contacts: Some(contact_descriptors),
384 max_contacts: _,
385 touch_type: _,
386 buttons: _,
387 ..
388 }),
389 ..
390 }) => Ok((
391 TouchBinding {
392 event_sender: input_event_sender,
393 device_descriptor: match touch_device_type {
394 TouchDeviceType::TouchScreen => {
395 TouchDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
396 device_id,
397 contacts: contact_descriptors
398 .iter()
399 .map(TouchBinding::parse_contact_descriptor)
400 .filter_map(Result::ok)
401 .collect(),
402 })
403 }
404 TouchDeviceType::WindowsPrecisionTouchpad => {
405 TouchDeviceDescriptor::Touchpad(TouchpadDeviceDescriptor {
406 device_id,
407 contacts: contact_descriptors
408 .iter()
409 .map(TouchBinding::parse_contact_descriptor)
410 .filter_map(Result::ok)
411 .collect(),
412 })
413 }
414 },
415 touch_device_type,
416 device_proxy,
417 },
418 input_device_status,
419 )),
420 descriptor => {
421 input_device_status
422 .health_node
423 .set_unhealthy("Touch Device Descriptor failed to parse.");
424 Err(format_err!("Touch Descriptor failed to parse: \n {:?}", descriptor))
425 }
426 }
427 }
428
429 async fn set_touchpad_mode(&self, enable: bool) -> Result<(), Error> {
430 match self.touch_device_type {
431 TouchDeviceType::TouchScreen => Ok(()),
432 TouchDeviceType::WindowsPrecisionTouchpad => {
433 let mut report = match self.device_proxy.get_feature_report().await? {
436 Ok(report) => report,
437 Err(e) => return Err(format_err!("get_feature_report failed: {}", e)),
438 };
439 let mut touch =
440 report.touch.unwrap_or_else(fidl_input_report::TouchFeatureReport::default);
441 touch.input_mode = match enable {
442 true => Some(fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection),
443 false => Some(fidl_input_report::TouchConfigurationInputMode::MouseCollection),
444 };
445 report.touch = Some(touch);
446 match self.device_proxy.set_feature_report(&report).await? {
447 Ok(()) => {
448 log::info!("touchpad: set touchpad_enabled to {}", enable);
450 Ok(())
451 }
452 Err(e) => Err(format_err!("set_feature_report failed: {}", e)),
453 }
454 }
455 }
456 }
457
458 fn process_reports(
478 report: InputReport,
479 previous_report: Option<InputReport>,
480 device_descriptor: &input_device::InputDeviceDescriptor,
481 input_event_sender: &mut UnboundedSender<InputEvent>,
482 inspect_status: &InputDeviceStatus,
483 metrics_logger: &metrics::MetricsLogger,
484 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
485 inspect_status.count_received_report(&report);
486 match device_descriptor {
487 input_device::InputDeviceDescriptor::TouchScreen(_) => process_touch_screen_reports(
488 report,
489 previous_report,
490 device_descriptor,
491 input_event_sender,
492 inspect_status,
493 metrics_logger,
494 ),
495 input_device::InputDeviceDescriptor::Touchpad(_) => process_touchpad_reports(
496 report,
497 device_descriptor,
498 input_event_sender,
499 inspect_status,
500 metrics_logger,
501 ),
502 _ => (None, None),
503 }
504 }
505
506 fn parse_contact_descriptor(
514 contact_device_descriptor: &fidl_input_report::ContactInputDescriptor,
515 ) -> Result<ContactDeviceDescriptor, Error> {
516 match contact_device_descriptor {
517 fidl_input_report::ContactInputDescriptor {
518 position_x: Some(x_axis),
519 position_y: Some(y_axis),
520 pressure: pressure_axis,
521 contact_width: width_axis,
522 contact_height: height_axis,
523 ..
524 } => Ok(ContactDeviceDescriptor {
525 x_range: x_axis.range,
526 y_range: y_axis.range,
527 x_unit: x_axis.unit,
528 y_unit: y_axis.unit,
529 pressure_range: pressure_axis.map(|axis| axis.range),
530 width_range: width_axis.map(|axis| axis.range),
531 height_range: height_axis.map(|axis| axis.range),
532 }),
533 descriptor => {
534 Err(format_err!("Touch Contact Descriptor failed to parse: \n {:?}", descriptor))
535 }
536 }
537 }
538}
539
540fn process_touch_screen_reports(
541 report: InputReport,
542 previous_report: Option<InputReport>,
543 device_descriptor: &input_device::InputDeviceDescriptor,
544 input_event_sender: &mut UnboundedSender<InputEvent>,
545 inspect_status: &InputDeviceStatus,
546 metrics_logger: &metrics::MetricsLogger,
547) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
548 fuchsia_trace::duration!(c"input", c"touch-binding-process-report");
549 fuchsia_trace::flow_end!(c"input", c"input_report", report.trace_id.unwrap_or(0).into());
550
551 let touch_report: &fidl_fuchsia_input_report::TouchInputReport = match &report.touch {
553 Some(touch) => touch,
554 None => {
555 inspect_status.count_filtered_report();
556 return (previous_report, None);
557 }
558 };
559
560 let (previous_contacts, previous_buttons): (
561 HashMap<u32, TouchContact>,
562 Vec<fidl_fuchsia_input_report::TouchButton>,
563 ) = previous_report
564 .as_ref()
565 .and_then(|unwrapped_report| unwrapped_report.touch.as_ref())
566 .map(touch_contacts_and_buttons_from_touch_report)
567 .unwrap_or_default();
568 let (current_contacts, current_buttons): (
569 HashMap<u32, TouchContact>,
570 Vec<fidl_fuchsia_input_report::TouchButton>,
571 ) = touch_contacts_and_buttons_from_touch_report(touch_report);
572
573 if previous_contacts.is_empty()
575 && current_contacts.is_empty()
576 && previous_buttons.is_empty()
577 && current_buttons.is_empty()
578 {
579 inspect_status.count_filtered_report();
580 return (Some(report), None);
581 }
582
583 let added_contacts: Vec<TouchContact> = Vec::from_iter(
585 current_contacts
586 .values()
587 .cloned()
588 .filter(|contact| !previous_contacts.contains_key(&contact.id)),
589 );
590 let moved_contacts: Vec<TouchContact> = Vec::from_iter(
592 current_contacts
593 .values()
594 .cloned()
595 .filter(|contact| previous_contacts.contains_key(&contact.id)),
596 );
597 let removed_contacts: Vec<TouchContact> = Vec::from_iter(
599 previous_contacts
600 .values()
601 .cloned()
602 .filter(|contact| !current_contacts.contains_key(&contact.id)),
603 );
604
605 let trace_id = fuchsia_trace::Id::random();
606 fuchsia_trace::flow_begin!(c"input", c"event_in_input_pipeline", trace_id);
607 send_touch_screen_event(
608 hashmap! {
609 fidl_ui_input::PointerEventPhase::Add => added_contacts.clone(),
610 fidl_ui_input::PointerEventPhase::Down => added_contacts.clone(),
611 fidl_ui_input::PointerEventPhase::Move => moved_contacts.clone(),
612 fidl_ui_input::PointerEventPhase::Up => removed_contacts.clone(),
613 fidl_ui_input::PointerEventPhase::Remove => removed_contacts.clone(),
614 },
615 hashmap! {
616 pointerinjector::EventPhase::Add => added_contacts,
617 pointerinjector::EventPhase::Change => moved_contacts,
618 pointerinjector::EventPhase::Remove => removed_contacts,
619 },
620 current_buttons,
621 device_descriptor,
622 input_event_sender,
623 trace_id,
624 inspect_status,
625 metrics_logger,
626 );
627
628 (Some(report), None)
629}
630
631fn process_touchpad_reports(
632 report: InputReport,
633 device_descriptor: &input_device::InputDeviceDescriptor,
634 input_event_sender: &mut UnboundedSender<InputEvent>,
635 inspect_status: &InputDeviceStatus,
636 metrics_logger: &metrics::MetricsLogger,
637) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
638 fuchsia_trace::duration!(c"input", c"touch-binding-process-report");
639 if let Some(trace_id) = report.trace_id {
640 fuchsia_trace::flow_end!(c"input", c"input_report", trace_id.into());
641 }
642
643 let touch_report: &fidl_fuchsia_input_report::TouchInputReport = match &report.touch {
645 Some(touch) => touch,
646 None => {
647 inspect_status.count_filtered_report();
648 return (None, None);
649 }
650 };
651
652 let current_contacts: Vec<TouchContact> = touch_report
653 .contacts
654 .as_ref()
655 .and_then(|unwrapped_contacts| {
656 Some(unwrapped_contacts.iter().map(TouchContact::from).collect())
658 })
659 .unwrap_or_default();
660
661 let buttons: HashSet<mouse_binding::MouseButton> = match &touch_report.pressed_buttons {
662 Some(buttons) => HashSet::from_iter(buttons.iter().filter_map(|button| match button {
663 fidl_fuchsia_input_report::TouchButton::Palm => Some(1),
664 fidl_fuchsia_input_report::TouchButton::__SourceBreaking { unknown_ordinal } => {
665 log::warn!("unknown TouchButton ordinal {unknown_ordinal:?}");
666 None
667 }
668 })),
669 None => HashSet::new(),
670 };
671
672 let trace_id = fuchsia_trace::Id::random();
673 fuchsia_trace::flow_begin!(c"input", c"event_in_input_pipeline", trace_id);
674 send_touchpad_event(
675 current_contacts,
676 buttons,
677 device_descriptor,
678 input_event_sender,
679 trace_id,
680 inspect_status,
681 metrics_logger,
682 );
683
684 (Some(report), None)
685}
686
687fn touch_contacts_and_buttons_from_touch_report(
688 touch_report: &fidl_fuchsia_input_report::TouchInputReport,
689) -> (HashMap<u32, TouchContact>, Vec<fidl_fuchsia_input_report::TouchButton>) {
690 let contacts: Vec<TouchContact> = touch_report
692 .contacts
693 .as_ref()
694 .and_then(|unwrapped_contacts| {
695 Some(unwrapped_contacts.iter().map(TouchContact::from).collect())
697 })
698 .unwrap_or_default();
699
700 (
701 contacts.into_iter().map(|contact| (contact.id, contact)).collect(),
702 touch_report.pressed_buttons.clone().unwrap_or_default(),
703 )
704}
705
706fn send_touch_screen_event(
715 contacts: HashMap<fidl_ui_input::PointerEventPhase, Vec<TouchContact>>,
716 injector_contacts: HashMap<pointerinjector::EventPhase, Vec<TouchContact>>,
717 pressed_buttons: Vec<fidl_input_report::TouchButton>,
718 device_descriptor: &input_device::InputDeviceDescriptor,
719 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
720 trace_id: fuchsia_trace::Id,
721 inspect_status: &InputDeviceStatus,
722 metrics_logger: &metrics::MetricsLogger,
723) {
724 let event = input_device::InputEvent {
725 device_event: input_device::InputDeviceEvent::TouchScreen(TouchScreenEvent {
726 contacts,
727 injector_contacts,
728 pressed_buttons,
729 }),
730 device_descriptor: device_descriptor.clone(),
731 event_time: zx::MonotonicInstant::get(),
732 handled: Handled::No,
733 trace_id: Some(trace_id),
734 };
735
736 match input_event_sender.unbounded_send(event.clone()) {
737 Err(e) => {
738 metrics_logger.log_error(
739 InputPipelineErrorMetricDimensionEvent::TouchFailedToSendTouchScreenEvent,
740 std::format!("Failed to send TouchScreenEvent with error: {:?}", e),
741 );
742 }
743 _ => inspect_status.count_generated_event(event),
744 }
745}
746
747fn send_touchpad_event(
755 injector_contacts: Vec<TouchContact>,
756 pressed_buttons: HashSet<mouse_binding::MouseButton>,
757 device_descriptor: &input_device::InputDeviceDescriptor,
758 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
759 trace_id: fuchsia_trace::Id,
760 inspect_status: &InputDeviceStatus,
761 metrics_logger: &metrics::MetricsLogger,
762) {
763 let event = input_device::InputEvent {
764 device_event: input_device::InputDeviceEvent::Touchpad(TouchpadEvent {
765 injector_contacts,
766 pressed_buttons,
767 }),
768 device_descriptor: device_descriptor.clone(),
769 event_time: zx::MonotonicInstant::get(),
770 handled: Handled::No,
771 trace_id: Some(trace_id),
772 };
773
774 match input_event_sender.unbounded_send(event.clone()) {
775 Err(e) => {
776 metrics_logger.log_error(
777 InputPipelineErrorMetricDimensionEvent::TouchFailedToSendTouchpadEvent,
778 std::format!("Failed to send TouchpadEvent with error: {:?}", e),
779 );
780 }
781 _ => inspect_status.count_generated_event(event),
782 }
783}
784
785async fn get_device_type(input_device: &fidl_input_report::InputDeviceProxy) -> TouchDeviceType {
791 match input_device.get_feature_report().await {
792 Ok(Ok(fidl_input_report::FeatureReport {
793 touch:
794 Some(fidl_input_report::TouchFeatureReport {
795 input_mode:
796 Some(
797 fidl_input_report::TouchConfigurationInputMode::MouseCollection
798 | fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection,
799 ),
800 ..
801 }),
802 ..
803 })) => TouchDeviceType::WindowsPrecisionTouchpad,
804 _ => TouchDeviceType::TouchScreen,
805 }
806}
807
808#[cfg(test)]
809mod tests {
810 use super::*;
811 use crate::testing_utilities::{
812 self, create_touch_contact, create_touch_input_report, create_touch_screen_event,
813 create_touch_screen_event_with_buttons, create_touchpad_event,
814 };
815 use crate::utils::Position;
816 use assert_matches::assert_matches;
817 use diagnostics_assertions::AnyProperty;
818 use fidl_test_util::spawn_stream_handler;
819 use fuchsia_async as fasync;
820 use futures::StreamExt;
821 use pretty_assertions::assert_eq;
822 use test_case::test_case;
823
824 #[fasync::run_singlethreaded(test)]
825 async fn process_empty_reports() {
826 let previous_report_time = zx::MonotonicInstant::get().into_nanos();
827 let previous_report = create_touch_input_report(
828 vec![],
829 None,
830 previous_report_time,
831 );
832 let report_time = zx::MonotonicInstant::get().into_nanos();
833 let report =
834 create_touch_input_report(vec![], None, report_time);
835
836 let descriptor =
837 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
838 device_id: 1,
839 contacts: vec![],
840 });
841 let (mut event_sender, mut event_receiver) = futures::channel::mpsc::unbounded();
842
843 let inspector = fuchsia_inspect::Inspector::default();
844 let test_node = inspector.root().create_child("TestDevice_Touch");
845 let mut inspect_status = InputDeviceStatus::new(test_node);
846 inspect_status.health_node.set_ok();
847
848 let (returned_report, _) = TouchBinding::process_reports(
849 report,
850 Some(previous_report),
851 &descriptor,
852 &mut event_sender,
853 &inspect_status,
854 &metrics::MetricsLogger::default(),
855 );
856 assert!(returned_report.is_some());
857 assert_eq!(returned_report.unwrap().event_time, Some(report_time));
858
859 let event = event_receiver.try_next();
861 assert!(event.is_err());
862
863 diagnostics_assertions::assert_data_tree!(inspector, root: {
864 "TestDevice_Touch": contains {
865 reports_received_count: 1u64,
866 reports_filtered_count: 1u64,
867 events_generated: 0u64,
868 last_received_timestamp_ns: report_time as u64,
869 last_generated_timestamp_ns: 0u64,
870 "fuchsia.inspect.Health": {
871 status: "OK",
872 start_timestamp_nanos: AnyProperty
875 },
876 }
877 });
878 }
879
880 #[fasync::run_singlethreaded(test)]
882 async fn add_and_down() {
883 const TOUCH_ID: u32 = 2;
884
885 let descriptor =
886 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
887 device_id: 1,
888 contacts: vec![],
889 });
890 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
891
892 let contact = fidl_fuchsia_input_report::ContactInputReport {
893 contact_id: Some(TOUCH_ID),
894 position_x: Some(0),
895 position_y: Some(0),
896 pressure: None,
897 contact_width: None,
898 contact_height: None,
899 ..Default::default()
900 };
901 let reports = vec![create_touch_input_report(
902 vec![contact],
903 None,
904 event_time_i64,
905 )];
906
907 let expected_events = vec![create_touch_screen_event(
908 hashmap! {
909 fidl_ui_input::PointerEventPhase::Add
910 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
911 fidl_ui_input::PointerEventPhase::Down
912 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
913 },
914 event_time_u64,
915 &descriptor,
916 )];
917
918 assert_input_report_sequence_generates_events!(
919 input_reports: reports,
920 expected_events: expected_events,
921 device_descriptor: descriptor,
922 device_type: TouchBinding,
923 );
924 }
925
926 #[fasync::run_singlethreaded(test)]
928 async fn up_and_remove() {
929 const TOUCH_ID: u32 = 2;
930
931 let descriptor =
932 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
933 device_id: 1,
934 contacts: vec![],
935 });
936 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
937
938 let contact = fidl_fuchsia_input_report::ContactInputReport {
939 contact_id: Some(TOUCH_ID),
940 position_x: Some(0),
941 position_y: Some(0),
942 pressure: None,
943 contact_width: None,
944 contact_height: None,
945 ..Default::default()
946 };
947 let reports = vec![
948 create_touch_input_report(
949 vec![contact],
950 None,
951 event_time_i64,
952 ),
953 create_touch_input_report(vec![], None, event_time_i64),
954 ];
955
956 let expected_events = vec![
957 create_touch_screen_event(
958 hashmap! {
959 fidl_ui_input::PointerEventPhase::Add
960 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
961 fidl_ui_input::PointerEventPhase::Down
962 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
963 },
964 event_time_u64,
965 &descriptor,
966 ),
967 create_touch_screen_event(
968 hashmap! {
969 fidl_ui_input::PointerEventPhase::Up
970 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
971 fidl_ui_input::PointerEventPhase::Remove
972 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
973 },
974 event_time_u64,
975 &descriptor,
976 ),
977 ];
978
979 assert_input_report_sequence_generates_events!(
980 input_reports: reports,
981 expected_events: expected_events,
982 device_descriptor: descriptor,
983 device_type: TouchBinding,
984 );
985 }
986
987 #[fasync::run_singlethreaded(test)]
989 async fn add_down_move() {
990 const TOUCH_ID: u32 = 2;
991 let first = Position { x: 10.0, y: 30.0 };
992 let second = Position { x: first.x * 2.0, y: first.y * 2.0 };
993
994 let descriptor =
995 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
996 device_id: 1,
997 contacts: vec![],
998 });
999 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1000
1001 let first_contact = fidl_fuchsia_input_report::ContactInputReport {
1002 contact_id: Some(TOUCH_ID),
1003 position_x: Some(first.x as i64),
1004 position_y: Some(first.y as i64),
1005 pressure: None,
1006 contact_width: None,
1007 contact_height: None,
1008 ..Default::default()
1009 };
1010 let second_contact = fidl_fuchsia_input_report::ContactInputReport {
1011 contact_id: Some(TOUCH_ID),
1012 position_x: Some(first.x as i64 * 2),
1013 position_y: Some(first.y as i64 * 2),
1014 pressure: None,
1015 contact_width: None,
1016 contact_height: None,
1017 ..Default::default()
1018 };
1019
1020 let reports = vec![
1021 create_touch_input_report(
1022 vec![first_contact],
1023 None,
1024 event_time_i64,
1025 ),
1026 create_touch_input_report(
1027 vec![second_contact],
1028 None,
1029 event_time_i64,
1030 ),
1031 ];
1032
1033 let expected_events = vec![
1034 create_touch_screen_event(
1035 hashmap! {
1036 fidl_ui_input::PointerEventPhase::Add
1037 => vec![create_touch_contact(TOUCH_ID, first)],
1038 fidl_ui_input::PointerEventPhase::Down
1039 => vec![create_touch_contact(TOUCH_ID, first)],
1040 },
1041 event_time_u64,
1042 &descriptor,
1043 ),
1044 create_touch_screen_event(
1045 hashmap! {
1046 fidl_ui_input::PointerEventPhase::Move
1047 => vec![create_touch_contact(TOUCH_ID, second)],
1048 },
1049 event_time_u64,
1050 &descriptor,
1051 ),
1052 ];
1053
1054 assert_input_report_sequence_generates_events!(
1055 input_reports: reports,
1056 expected_events: expected_events,
1057 device_descriptor: descriptor,
1058 device_type: TouchBinding,
1059 );
1060 }
1061
1062 #[fasync::run_singlethreaded(test)]
1063 async fn sent_event_has_trace_id() {
1064 let previous_report_time = zx::MonotonicInstant::get().into_nanos();
1065 let previous_report = create_touch_input_report(
1066 vec![],
1067 None,
1068 previous_report_time,
1069 );
1070
1071 let report_time = zx::MonotonicInstant::get().into_nanos();
1072 let contact = fidl_fuchsia_input_report::ContactInputReport {
1073 contact_id: Some(222),
1074 position_x: Some(333),
1075 position_y: Some(444),
1076 ..Default::default()
1077 };
1078 let report =
1079 create_touch_input_report(vec![contact], None, report_time);
1080
1081 let descriptor =
1082 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
1083 device_id: 1,
1084 contacts: vec![],
1085 });
1086 let (mut event_sender, mut event_receiver) = futures::channel::mpsc::unbounded();
1087
1088 let inspector = fuchsia_inspect::Inspector::default();
1089 let test_node = inspector.root().create_child("TestDevice_Touch");
1090 let mut inspect_status = InputDeviceStatus::new(test_node);
1091 inspect_status.health_node.set_ok();
1092
1093 let _ = TouchBinding::process_reports(
1094 report,
1095 Some(previous_report),
1096 &descriptor,
1097 &mut event_sender,
1098 &inspect_status,
1099 &metrics::MetricsLogger::default(),
1100 );
1101 assert_matches!(event_receiver.try_next(), Ok(Some(InputEvent { trace_id: Some(_), .. })));
1102 }
1103
1104 #[fuchsia::test(allow_stalls = false)]
1105 async fn enables_touchpad_mode_automatically() {
1106 let (set_feature_report_sender, set_feature_report_receiver) =
1107 futures::channel::mpsc::unbounded();
1108 let input_device_proxy = spawn_stream_handler(move |input_device_request| {
1109 let set_feature_report_sender = set_feature_report_sender.clone();
1110 async move {
1111 match input_device_request {
1112 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1113 let _ = responder.send(&get_touchpad_device_descriptor(
1114 true, ));
1116 }
1117 fidl_input_report::InputDeviceRequest::GetFeatureReport { responder } => {
1118 let _ = responder.send(Ok(&fidl_input_report::FeatureReport {
1119 touch: Some(fidl_input_report::TouchFeatureReport {
1120 input_mode: Some(
1121 fidl_input_report::TouchConfigurationInputMode::MouseCollection,
1122 ),
1123 ..Default::default()
1124 }),
1125 ..Default::default()
1126 }));
1127 }
1128 fidl_input_report::InputDeviceRequest::SetFeatureReport {
1129 responder,
1130 report,
1131 } => {
1132 match set_feature_report_sender.unbounded_send(report) {
1133 Ok(_) => {
1134 let _ = responder.send(Ok(()));
1135 }
1136 Err(e) => {
1137 panic!("try_send set_feature_report_request failed: {}", e);
1138 }
1139 };
1140 }
1141 fidl_input_report::InputDeviceRequest::GetInputReportsReader { .. } => {
1142 }
1144 r => panic!("unsupported request {:?}", r),
1145 }
1146 }
1147 });
1148
1149 let (device_event_sender, _) = futures::channel::mpsc::unbounded();
1150
1151 let inspector = fuchsia_inspect::Inspector::default();
1153 let test_node = inspector.root().create_child("test_node");
1154
1155 TouchBinding::new(
1159 input_device_proxy,
1160 0,
1161 device_event_sender,
1162 test_node,
1163 metrics::MetricsLogger::default(),
1164 )
1165 .await
1166 .unwrap();
1167 assert_matches!(
1168 set_feature_report_receiver.collect::<Vec<_>>().await.as_slice(),
1169 [fidl_input_report::FeatureReport {
1170 touch: Some(fidl_input_report::TouchFeatureReport {
1171 input_mode: Some(
1172 fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection
1173 ),
1174 ..
1175 }),
1176 ..
1177 }]
1178 );
1179 }
1180
1181 #[test_case(true, None, TouchDeviceType::TouchScreen; "touch screen")]
1182 #[test_case(false, None, TouchDeviceType::TouchScreen; "no mouse descriptor, no touch_input_mode")]
1183 #[test_case(true, Some(fidl_input_report::TouchConfigurationInputMode::MouseCollection), TouchDeviceType::WindowsPrecisionTouchpad; "touchpad in mouse mode")]
1184 #[test_case(true, Some(fidl_input_report::TouchConfigurationInputMode::WindowsPrecisionTouchpadCollection), TouchDeviceType::WindowsPrecisionTouchpad; "touchpad in touchpad mode")]
1185 #[fuchsia::test(allow_stalls = false)]
1186 async fn identifies_correct_touch_device_type(
1187 has_mouse_descriptor: bool,
1188 touch_input_mode: Option<fidl_input_report::TouchConfigurationInputMode>,
1189 expect_touch_device_type: TouchDeviceType,
1190 ) {
1191 let input_device_proxy = spawn_stream_handler(move |input_device_request| async move {
1192 match input_device_request {
1193 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1194 let _ = responder.send(&get_touchpad_device_descriptor(has_mouse_descriptor));
1195 }
1196 fidl_input_report::InputDeviceRequest::GetFeatureReport { responder } => {
1197 let _ = responder.send(Ok(&fidl_input_report::FeatureReport {
1198 touch: Some(fidl_input_report::TouchFeatureReport {
1199 input_mode: touch_input_mode,
1200 ..Default::default()
1201 }),
1202 ..Default::default()
1203 }));
1204 }
1205 fidl_input_report::InputDeviceRequest::SetFeatureReport { responder, .. } => {
1206 let _ = responder.send(Ok(()));
1207 }
1208 r => panic!("unsupported request {:?}", r),
1209 }
1210 });
1211
1212 let (device_event_sender, _) = futures::channel::mpsc::unbounded();
1213
1214 let inspector = fuchsia_inspect::Inspector::default();
1216 let test_node = inspector.root().create_child("test_node");
1217
1218 let binding = TouchBinding::new(
1219 input_device_proxy,
1220 0,
1221 device_event_sender,
1222 test_node,
1223 metrics::MetricsLogger::default(),
1224 )
1225 .await
1226 .unwrap();
1227 pretty_assertions::assert_eq!(binding.touch_device_type, expect_touch_device_type);
1228 }
1229
1230 fn get_touchpad_device_descriptor(
1233 has_mouse_descriptor: bool,
1234 ) -> fidl_fuchsia_input_report::DeviceDescriptor {
1235 fidl_input_report::DeviceDescriptor {
1236 mouse: match has_mouse_descriptor {
1237 true => Some(fidl_input_report::MouseDescriptor::default()),
1238 false => None,
1239 },
1240 touch: Some(fidl_input_report::TouchDescriptor {
1241 input: Some(fidl_input_report::TouchInputDescriptor {
1242 contacts: Some(vec![fidl_input_report::ContactInputDescriptor {
1243 position_x: Some(fidl_input_report::Axis {
1244 range: fidl_input_report::Range { min: 1, max: 2 },
1245 unit: fidl_input_report::Unit {
1246 type_: fidl_input_report::UnitType::None,
1247 exponent: 0,
1248 },
1249 }),
1250 position_y: Some(fidl_input_report::Axis {
1251 range: fidl_input_report::Range { min: 2, max: 3 },
1252 unit: fidl_input_report::Unit {
1253 type_: fidl_input_report::UnitType::Other,
1254 exponent: 100000,
1255 },
1256 }),
1257 pressure: Some(fidl_input_report::Axis {
1258 range: fidl_input_report::Range { min: 3, max: 4 },
1259 unit: fidl_input_report::Unit {
1260 type_: fidl_input_report::UnitType::Grams,
1261 exponent: -991,
1262 },
1263 }),
1264 contact_width: Some(fidl_input_report::Axis {
1265 range: fidl_input_report::Range { min: 5, max: 6 },
1266 unit: fidl_input_report::Unit {
1267 type_: fidl_input_report::UnitType::EnglishAngularVelocity,
1268 exponent: 123,
1269 },
1270 }),
1271 contact_height: Some(fidl_input_report::Axis {
1272 range: fidl_input_report::Range { min: 7, max: 8 },
1273 unit: fidl_input_report::Unit {
1274 type_: fidl_input_report::UnitType::Pascals,
1275 exponent: 100,
1276 },
1277 }),
1278 ..Default::default()
1279 }]),
1280 ..Default::default()
1281 }),
1282 ..Default::default()
1283 }),
1284 ..Default::default()
1285 }
1286 }
1287
1288 #[fasync::run_singlethreaded(test)]
1289 async fn send_touchpad_event_button() {
1290 const TOUCH_ID: u32 = 1;
1291 const PRIMARY_BUTTON: u8 = 1;
1292
1293 let descriptor = input_device::InputDeviceDescriptor::Touchpad(TouchpadDeviceDescriptor {
1294 device_id: 1,
1295 contacts: vec![],
1296 });
1297 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1298
1299 let contact = fidl_fuchsia_input_report::ContactInputReport {
1300 contact_id: Some(TOUCH_ID),
1301 position_x: Some(0),
1302 position_y: Some(0),
1303 pressure: None,
1304 contact_width: None,
1305 contact_height: None,
1306 ..Default::default()
1307 };
1308 let reports = vec![create_touch_input_report(
1309 vec![contact],
1310 Some(vec![fidl_fuchsia_input_report::TouchButton::__SourceBreaking {
1311 unknown_ordinal: PRIMARY_BUTTON,
1312 }]),
1313 event_time_i64,
1314 )];
1315
1316 let expected_events = vec![create_touchpad_event(
1317 vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
1318 vec![fidl_fuchsia_input_report::TouchButton::__SourceBreaking {
1319 unknown_ordinal: PRIMARY_BUTTON,
1320 }]
1321 .into_iter()
1322 .collect(),
1323 event_time_u64,
1324 &descriptor,
1325 )];
1326
1327 assert_input_report_sequence_generates_events!(
1328 input_reports: reports,
1329 expected_events: expected_events,
1330 device_descriptor: descriptor,
1331 device_type: TouchBinding,
1332 );
1333 }
1334
1335 #[fasync::run_singlethreaded(test)]
1336 async fn send_touchpad_event_2_fingers_down_up() {
1337 const TOUCH_ID_1: u32 = 1;
1338 const TOUCH_ID_2: u32 = 2;
1339
1340 let descriptor = input_device::InputDeviceDescriptor::Touchpad(TouchpadDeviceDescriptor {
1341 device_id: 1,
1342 contacts: vec![],
1343 });
1344 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1345
1346 let contact1 = fidl_fuchsia_input_report::ContactInputReport {
1347 contact_id: Some(TOUCH_ID_1),
1348 position_x: Some(0),
1349 position_y: Some(0),
1350 pressure: None,
1351 contact_width: None,
1352 contact_height: None,
1353 ..Default::default()
1354 };
1355 let contact2 = fidl_fuchsia_input_report::ContactInputReport {
1356 contact_id: Some(TOUCH_ID_2),
1357 position_x: Some(10),
1358 position_y: Some(10),
1359 pressure: None,
1360 contact_width: None,
1361 contact_height: None,
1362 ..Default::default()
1363 };
1364 let reports = vec![
1365 create_touch_input_report(
1366 vec![contact1, contact2],
1367 None,
1368 event_time_i64,
1369 ),
1370 create_touch_input_report(vec![], None, event_time_i64),
1371 ];
1372
1373 let expected_events = vec![
1374 create_touchpad_event(
1375 vec![
1376 create_touch_contact(TOUCH_ID_1, Position { x: 0.0, y: 0.0 }),
1377 create_touch_contact(TOUCH_ID_2, Position { x: 10.0, y: 10.0 }),
1378 ],
1379 HashSet::new(),
1380 event_time_u64,
1381 &descriptor,
1382 ),
1383 create_touchpad_event(vec![], HashSet::new(), event_time_u64, &descriptor),
1384 ];
1385
1386 assert_input_report_sequence_generates_events!(
1387 input_reports: reports,
1388 expected_events: expected_events,
1389 device_descriptor: descriptor,
1390 device_type: TouchBinding,
1391 );
1392 }
1393
1394 #[test_case(Position{x: 0.0, y: 0.0}, Position{x: 5.0, y: 5.0}; "down move")]
1395 #[test_case(Position{x: 0.0, y: 0.0}, Position{x: 0.0, y: 0.0}; "down hold")]
1396 #[fasync::run_singlethreaded(test)]
1397 async fn send_touchpad_event_1_finger(p0: Position, p1: Position) {
1398 const TOUCH_ID: u32 = 1;
1399
1400 let descriptor = input_device::InputDeviceDescriptor::Touchpad(TouchpadDeviceDescriptor {
1401 device_id: 1,
1402 contacts: vec![],
1403 });
1404 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1405
1406 let contact1 = fidl_fuchsia_input_report::ContactInputReport {
1407 contact_id: Some(TOUCH_ID),
1408 position_x: Some(p0.x as i64),
1409 position_y: Some(p0.y as i64),
1410 pressure: None,
1411 contact_width: None,
1412 contact_height: None,
1413 ..Default::default()
1414 };
1415 let contact2 = fidl_fuchsia_input_report::ContactInputReport {
1416 contact_id: Some(TOUCH_ID),
1417 position_x: Some(p1.x as i64),
1418 position_y: Some(p1.y as i64),
1419 pressure: None,
1420 contact_width: None,
1421 contact_height: None,
1422 ..Default::default()
1423 };
1424 let reports = vec![
1425 create_touch_input_report(
1426 vec![contact1],
1427 None,
1428 event_time_i64,
1429 ),
1430 create_touch_input_report(
1431 vec![contact2],
1432 None,
1433 event_time_i64,
1434 ),
1435 ];
1436
1437 let expected_events = vec![
1438 create_touchpad_event(
1439 vec![create_touch_contact(TOUCH_ID, p0)],
1440 HashSet::new(),
1441 event_time_u64,
1442 &descriptor,
1443 ),
1444 create_touchpad_event(
1445 vec![create_touch_contact(TOUCH_ID, p1)],
1446 HashSet::new(),
1447 event_time_u64,
1448 &descriptor,
1449 ),
1450 ];
1451
1452 assert_input_report_sequence_generates_events!(
1453 input_reports: reports,
1454 expected_events: expected_events,
1455 device_descriptor: descriptor,
1456 device_type: TouchBinding,
1457 );
1458 }
1459
1460 #[fasync::run_singlethreaded(test)]
1463 async fn send_pressed_button_no_contact() {
1464 let descriptor =
1465 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
1466 device_id: 1,
1467 contacts: vec![],
1468 });
1469 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1470
1471 let reports = vec![create_touch_input_report(
1472 vec![],
1473 Some(vec![fidl_fuchsia_input_report::TouchButton::Palm]),
1474 event_time_i64,
1475 )];
1476
1477 let expected_events = vec![create_touch_screen_event_with_buttons(
1478 hashmap! {},
1479 vec![fidl_fuchsia_input_report::TouchButton::Palm],
1480 event_time_u64,
1481 &descriptor,
1482 )];
1483
1484 assert_input_report_sequence_generates_events!(
1485 input_reports: reports,
1486 expected_events: expected_events,
1487 device_descriptor: descriptor,
1488 device_type: TouchBinding,
1489 );
1490 }
1491
1492 #[fasync::run_singlethreaded(test)]
1495 async fn send_pressed_button_with_contact() {
1496 const TOUCH_ID: u32 = 2;
1497
1498 let descriptor =
1499 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
1500 device_id: 1,
1501 contacts: vec![],
1502 });
1503 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1504
1505 let contact = fidl_fuchsia_input_report::ContactInputReport {
1506 contact_id: Some(TOUCH_ID),
1507 position_x: Some(0),
1508 position_y: Some(0),
1509 pressure: None,
1510 contact_width: None,
1511 contact_height: None,
1512 ..Default::default()
1513 };
1514 let reports = vec![create_touch_input_report(
1515 vec![contact],
1516 Some(vec![fidl_fuchsia_input_report::TouchButton::Palm]),
1517 event_time_i64,
1518 )];
1519
1520 let expected_events = vec![create_touch_screen_event_with_buttons(
1521 hashmap! {
1522 fidl_ui_input::PointerEventPhase::Add
1523 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
1524 fidl_ui_input::PointerEventPhase::Down
1525 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
1526 },
1527 vec![fidl_fuchsia_input_report::TouchButton::Palm],
1528 event_time_u64,
1529 &descriptor,
1530 )];
1531
1532 assert_input_report_sequence_generates_events!(
1533 input_reports: reports,
1534 expected_events: expected_events,
1535 device_descriptor: descriptor,
1536 device_type: TouchBinding,
1537 );
1538 }
1539
1540 #[fasync::run_singlethreaded(test)]
1543 async fn send_multiple_pressed_buttons_with_contact() {
1544 const TOUCH_ID: u32 = 2;
1545
1546 let descriptor =
1547 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
1548 device_id: 1,
1549 contacts: vec![],
1550 });
1551 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
1552
1553 let contact = fidl_fuchsia_input_report::ContactInputReport {
1554 contact_id: Some(TOUCH_ID),
1555 position_x: Some(0),
1556 position_y: Some(0),
1557 pressure: None,
1558 contact_width: None,
1559 contact_height: None,
1560 ..Default::default()
1561 };
1562 let reports = vec![create_touch_input_report(
1563 vec![contact],
1564 Some(vec![
1565 fidl_fuchsia_input_report::TouchButton::Palm,
1566 fidl_fuchsia_input_report::TouchButton::__SourceBreaking { unknown_ordinal: 2 },
1567 ]),
1568 event_time_i64,
1569 )];
1570
1571 let expected_events = vec![create_touch_screen_event_with_buttons(
1572 hashmap! {
1573 fidl_ui_input::PointerEventPhase::Add
1574 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
1575 fidl_ui_input::PointerEventPhase::Down
1576 => vec![create_touch_contact(TOUCH_ID, Position { x: 0.0, y: 0.0 })],
1577 },
1578 vec![
1579 fidl_fuchsia_input_report::TouchButton::Palm,
1580 fidl_fuchsia_input_report::TouchButton::__SourceBreaking { unknown_ordinal: 2 },
1581 ],
1582 event_time_u64,
1583 &descriptor,
1584 )];
1585
1586 assert_input_report_sequence_generates_events!(
1587 input_reports: reports,
1588 expected_events: expected_events,
1589 device_descriptor: descriptor,
1590 device_type: TouchBinding,
1591 );
1592 }
1593
1594 #[fasync::run_singlethreaded(test)]
1596 async fn send_no_buttons_no_contacts() {
1597 let descriptor =
1598 input_device::InputDeviceDescriptor::TouchScreen(TouchScreenDeviceDescriptor {
1599 device_id: 1,
1600 contacts: vec![],
1601 });
1602 let (event_time_i64, _) = testing_utilities::event_times();
1603
1604 let reports = vec![create_touch_input_report(vec![], Some(vec![]), event_time_i64)];
1605
1606 let expected_events: Vec<input_device::InputEvent> = vec![];
1607
1608 assert_input_report_sequence_generates_events!(
1609 input_reports: reports,
1610 expected_events: expected_events,
1611 device_descriptor: descriptor,
1612 device_type: TouchBinding,
1613 );
1614 }
1615}