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