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