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