1#![warn(clippy::await_holding_refcell_ref)]
6use crate::dispatcher::TaskHandle;
7use crate::input_handler::{BatchInputHandler, Handler, InputHandlerStatus};
8use crate::utils::{Position, Size};
9use crate::{Dispatcher, Incoming, MonotonicInstant, input_device, metrics, touch_binding};
10use anyhow::{Context, Error, Result};
11use async_trait::async_trait;
12use async_utils::hanging_get::client::HangingGetStream;
13use fidl::AsHandleRef;
14use fidl::endpoints::{Proxy, create_proxy};
15use fuchsia_inspect::health::Reporter;
16use futures::channel::mpsc;
17use futures::stream::StreamExt;
18use metrics_registry::*;
19use std::cell::RefCell;
20use std::collections::HashMap;
21use std::rc::Rc;
22use {
23 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
24 fidl_fuchsia_ui_pointerinjector as pointerinjector,
25 fidl_fuchsia_ui_pointerinjector_configuration as pointerinjector_config,
26 fidl_fuchsia_ui_policy as fidl_ui_policy,
27};
28
29pub struct TouchInjectorHandler {
32 mutable_state: RefCell<MutableState>,
34
35 context_view_ref: fidl_fuchsia_ui_views::ViewRef,
38
39 target_view_ref: fidl_fuchsia_ui_views::ViewRef,
42
43 display_size: Size,
47
48 injector_registry_proxy: pointerinjector::RegistryProxy,
50
51 configuration_proxy: pointerinjector_config::SetupProxy,
53
54 pub inspect_status: InputHandlerStatus,
56
57 metrics_logger: metrics::MetricsLogger,
59}
60
61#[derive(Debug)]
62struct MutableState {
63 viewport: Option<pointerinjector::Viewport>,
66
67 injectors: HashMap<u32, pointerinjector::DeviceProxy>,
69
70 pub listeners: HashMap<u32, fidl_ui_policy::TouchButtonsListenerProxy>,
72
73 pub last_button_event: Option<fidl_ui_input::TouchButtonsEvent>,
76
77 pub send_event_task_tracker: LocalTaskTracker,
78}
79
80impl Handler for TouchInjectorHandler {
81 fn set_handler_healthy(self: std::rc::Rc<Self>) {
82 self.inspect_status.health_node.borrow_mut().set_ok();
83 }
84
85 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
86 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
87 }
88
89 fn get_name(&self) -> &'static str {
90 "TouchInjectorHandler"
91 }
92
93 fn interest(&self) -> Vec<input_device::InputEventType> {
94 vec![input_device::InputEventType::TouchScreen]
95 }
96}
97
98#[async_trait(?Send)]
99impl BatchInputHandler for TouchInjectorHandler {
100 async fn handle_input_events(
101 self: Rc<Self>,
102 events: Vec<input_device::InputEvent>,
103 ) -> Vec<input_device::InputEvent> {
104 if events.is_empty() {
105 return events;
106 }
107
108 fuchsia_trace::duration!("input", "touch_injector_handler");
109
110 let mut result: Vec<input_device::InputEvent> = Vec::new();
111 let mut pending_scenic_events: Vec<pointerinjector::Event> = Vec::new();
112
113 let device_id = events[0].device_descriptor.device_id();
114 let has_different_device_events =
115 events.iter().any(|e| e.device_descriptor.device_id() != device_id);
116 if has_different_device_events {
117 self.metrics_logger.log_error(
118 InputPipelineErrorMetricDimensionEvent::TouchInjectorReceivedInputFrameContainsEventsFromMultipleDevices,
119 std::format!("TouchInjectorHandler: Received events from different devices"),
120 );
121 return events;
122 }
123
124 for event in events {
125 let (out_events, scenic_events) = self.clone().handle_single_input_event(event).await;
126 result.extend(out_events);
127 pending_scenic_events.extend(scenic_events);
128 }
129
130 if !pending_scenic_events.is_empty() {
131 if let input_device::InputDeviceDescriptor::TouchScreen(ref touch_device_descriptor) =
132 result[0].device_descriptor
133 {
134 if let Err(e) =
135 self.inject_pointer_events(pending_scenic_events, touch_device_descriptor)
136 {
137 self.metrics_logger.log_error(
138 InputPipelineErrorMetricDimensionEvent::TouchInjectorSendEventToScenicFailed,
139 std::format!("inject_pointer_events failed: {}", e),
140 );
141 }
142 }
143 }
144
145 result
146 }
147}
148
149impl TouchInjectorHandler {
150 pub async fn new(
162 incoming: &Incoming,
163 display_size: Size,
164 input_handlers_node: &fuchsia_inspect::Node,
165 metrics_logger: metrics::MetricsLogger,
166 ) -> Result<Rc<Self>, Error> {
167 let configuration_proxy =
168 incoming.connect_protocol::<pointerinjector_config::SetupProxy>()?;
169 let injector_registry_proxy =
170 incoming.connect_protocol::<pointerinjector::RegistryProxy>()?;
171
172 Self::new_handler(
173 configuration_proxy,
174 injector_registry_proxy,
175 display_size,
176 input_handlers_node,
177 metrics_logger,
178 )
179 .await
180 }
181
182 pub async fn new_with_config_proxy(
197 incoming: &Incoming,
198 configuration_proxy: pointerinjector_config::SetupProxy,
199 display_size: Size,
200 input_handlers_node: &fuchsia_inspect::Node,
201 metrics_logger: metrics::MetricsLogger,
202 ) -> Result<Rc<Self>, Error> {
203 let injector_registry_proxy =
204 incoming.connect_protocol::<pointerinjector::RegistryProxy>()?;
205 Self::new_handler(
206 configuration_proxy,
207 injector_registry_proxy,
208 display_size,
209 input_handlers_node,
210 metrics_logger,
211 )
212 .await
213 }
214
215 async fn new_handler(
231 configuration_proxy: pointerinjector_config::SetupProxy,
232 injector_registry_proxy: pointerinjector::RegistryProxy,
233 display_size: Size,
234 input_handlers_node: &fuchsia_inspect::Node,
235 metrics_logger: metrics::MetricsLogger,
236 ) -> Result<Rc<Self>, Error> {
237 let (context_view_ref, target_view_ref) = configuration_proxy.get_view_refs().await?;
239
240 let inspect_status = InputHandlerStatus::new(
241 input_handlers_node,
242 "touch_injector_handler",
243 false,
244 );
245 let handler = Rc::new(Self {
246 mutable_state: RefCell::new(MutableState {
247 viewport: None,
248 injectors: HashMap::new(),
249 listeners: HashMap::new(),
250 last_button_event: None,
251 send_event_task_tracker: LocalTaskTracker::new(),
252 }),
253 context_view_ref,
254 target_view_ref,
255 display_size,
256 injector_registry_proxy,
257 configuration_proxy,
258 inspect_status,
259 metrics_logger,
260 });
261
262 Ok(handler)
263 }
264
265 fn clone_event(event: &fidl_ui_input::TouchButtonsEvent) -> fidl_ui_input::TouchButtonsEvent {
266 let trace_flow_id = fuchsia_trace::Id::random();
268 fuchsia_trace::flow_begin!("input", "dispatch_touch_button_to_listeners", trace_flow_id);
269
270 fidl_ui_input::TouchButtonsEvent {
271 event_time: event.event_time,
272 device_info: event.device_info.clone(),
273 pressed_buttons: event.pressed_buttons.clone(),
274 wake_lease: event.wake_lease.as_ref().map(|lease| {
275 lease.duplicate(zx::Rights::SAME_RIGHTS).expect("failed to duplicate event pair")
276 }),
277 trace_flow_id: Some(trace_flow_id.into()),
278 ..Default::default()
279 }
280 }
281
282 async fn handle_single_input_event(
283 self: Rc<Self>,
284 mut input_event: input_device::InputEvent,
285 ) -> (Vec<input_device::InputEvent>, Vec<pointerinjector::Event>) {
286 match input_event {
287 input_device::InputEvent {
288 device_event: input_device::InputDeviceEvent::TouchScreen(ref mut touch_event),
289 device_descriptor:
290 input_device::InputDeviceDescriptor::TouchScreen(ref touch_device_descriptor),
291 event_time,
292 handled: input_device::Handled::No,
293 trace_id,
294 } => {
295 self.inspect_status.count_received_event(&event_time);
296 fuchsia_trace::duration!("input", "touch_injector_handler[processing]");
297 if let Some(trace_id) = trace_id {
298 fuchsia_trace::flow_step!("input", "event_in_input_pipeline", trace_id.into());
299 }
300
301 let mut scenic_events = vec![];
302 if touch_event.injector_contacts.values().all(|vec| vec.is_empty()) {
303 let mut touch_buttons_event = Self::create_touch_buttons_event(
304 touch_event,
305 event_time,
306 &touch_device_descriptor,
307 );
308
309 self.send_event_to_listeners(&touch_buttons_event).await;
311
312 std::mem::drop(touch_buttons_event.wake_lease.take());
314 self.mutable_state.borrow_mut().last_button_event = Some(touch_buttons_event);
315 } else if touch_event.pressed_buttons.is_empty() {
316 if let Err(e) = self.ensure_injector_registered(&touch_device_descriptor).await
318 {
319 self.metrics_logger.log_error(
320 InputPipelineErrorMetricDimensionEvent::TouchInjectorEnsureInjectorRegisteredFailed,
321 std::format!("ensure_injector_registered failed: {}", e));
322 }
323
324 scenic_events = self.create_pointer_events(
326 touch_event,
327 &touch_device_descriptor,
328 event_time,
329 );
330 }
331
332 self.inspect_status.count_handled_event();
334 (vec![input_event.into_handled()], scenic_events)
335 }
336 input_device::InputEvent {
337 device_event: input_device::InputDeviceEvent::TouchScreen(_),
338 handled: input_device::Handled::Yes,
339 ..
340 } => {
341 (vec![input_event], vec![])
343 }
344 _ => {
345 log::warn!("Unhandled input event: {:?}", input_event.get_event_type());
346 (vec![input_event], vec![])
347 }
348 }
349 }
350
351 async fn ensure_injector_registered(
357 self: &Rc<Self>,
358 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
359 ) -> Result<(), anyhow::Error> {
360 if self.mutable_state.borrow().injectors.contains_key(&touch_descriptor.device_id) {
361 return Ok(());
362 }
363
364 let (device_proxy, device_server) = create_proxy::<pointerinjector::DeviceMarker>();
366 let context = fuchsia_scenic::duplicate_view_ref(&self.context_view_ref)
367 .context("Failed to duplicate context view ref.")?;
368 let target = fuchsia_scenic::duplicate_view_ref(&self.target_view_ref)
369 .context("Failed to duplicate target view ref.")?;
370 let viewport = self.mutable_state.borrow().viewport.clone();
371 if viewport.is_none() {
372 return Err(anyhow::format_err!(
375 "Received a touch event without a viewport to inject into."
376 ));
377 }
378 let config = pointerinjector::Config {
379 device_id: Some(touch_descriptor.device_id),
380 device_type: Some(pointerinjector::DeviceType::Touch),
381 context: Some(pointerinjector::Context::View(context)),
382 target: Some(pointerinjector::Target::View(target)),
383 viewport,
384 dispatch_policy: Some(pointerinjector::DispatchPolicy::TopHitAndAncestorsInTarget),
385 scroll_v_range: None,
386 scroll_h_range: None,
387 buttons: None,
388 ..Default::default()
389 };
390
391 self.mutable_state.borrow_mut().injectors.insert(touch_descriptor.device_id, device_proxy);
393
394 self.injector_registry_proxy
396 .register(config, device_server)
397 .await
398 .context("Failed to register injector.")?;
399 log::info!("Registered injector with device id {:?}", touch_descriptor.device_id);
400
401 Ok(())
402 }
403
404 fn create_pointer_events(
411 &self,
412 touch_event: &mut touch_binding::TouchScreenEvent,
413 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
414 event_time: zx::MonotonicInstant,
415 ) -> Vec<pointerinjector::Event> {
416 let ordered_phases = vec![
417 pointerinjector::EventPhase::Add,
418 pointerinjector::EventPhase::Change,
419 pointerinjector::EventPhase::Remove,
420 ];
421
422 let mut events: Vec<pointerinjector::Event> = vec![];
423 for phase in ordered_phases {
424 let contacts: Vec<touch_binding::TouchContact> = touch_event
425 .injector_contacts
426 .get(&phase)
427 .map_or(vec![], |contacts| contacts.to_owned());
428 let new_events = contacts.into_iter().map(|contact| {
429 Self::create_pointer_sample_event(
430 phase,
431 &contact,
432 touch_descriptor,
433 &self.display_size,
434 event_time,
435 touch_event.wake_lease.take(),
436 )
437 });
438 events.extend(new_events);
439 }
440
441 events
442 }
443
444 fn inject_pointer_events(
450 &self,
451 events: Vec<pointerinjector::Event>,
452 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
453 ) -> Result<(), anyhow::Error> {
454 fuchsia_trace::duration!("input", "touch-inject-into-scenic");
455
456 let injector =
457 self.mutable_state.borrow().injectors.get(&touch_descriptor.device_id).cloned();
458 if let Some(injector) = injector {
459 let _ = injector.inject_events(events);
460 Ok(())
461 } else {
462 Err(anyhow::format_err!(
463 "No injector found for touch device {}.",
464 touch_descriptor.device_id
465 ))
466 }
467 }
468
469 fn create_pointer_sample_event(
479 phase: pointerinjector::EventPhase,
480 contact: &touch_binding::TouchContact,
481 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
482 display_size: &Size,
483 event_time: zx::MonotonicInstant,
484 wake_lease: Option<zx::EventPair>,
485 ) -> pointerinjector::Event {
486 let position =
487 Self::display_coordinate_from_contact(&contact, &touch_descriptor, display_size);
488 let pointer_sample = pointerinjector::PointerSample {
489 pointer_id: Some(contact.id),
490 phase: Some(phase),
491 position_in_viewport: Some([position.x, position.y]),
492 scroll_v: None,
493 scroll_h: None,
494 pressed_buttons: None,
495 ..Default::default()
496 };
497 let data = pointerinjector::Data::PointerSample(pointer_sample);
498
499 let trace_flow_id = fuchsia_trace::Id::random();
500 let event = pointerinjector::Event {
501 timestamp: Some(event_time.into_nanos()),
502 data: Some(data),
503 trace_flow_id: Some(trace_flow_id.into()),
504 wake_lease,
505 ..Default::default()
506 };
507
508 fuchsia_trace::flow_begin!("input", "dispatch_event_to_scenic", trace_flow_id);
509
510 event
511 }
512
513 fn display_coordinate_from_contact(
527 contact: &touch_binding::TouchContact,
528 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
529 display_size: &Size,
530 ) -> Position {
531 if let Some(contact_descriptor) = touch_descriptor.contacts.first() {
532 let x_range: f32 =
534 contact_descriptor.x_range.max as f32 - contact_descriptor.x_range.min as f32;
535 let x_wrt_range: f32 = contact.position.x - contact_descriptor.x_range.min as f32;
536 let x: f32 = (display_size.width * x_wrt_range) / x_range;
537
538 let y_range: f32 =
540 contact_descriptor.y_range.max as f32 - contact_descriptor.y_range.min as f32;
541 let y_wrt_range: f32 = contact.position.y - contact_descriptor.y_range.min as f32;
542 let y: f32 = (display_size.height * y_wrt_range) / y_range;
543
544 Position { x, y }
545 } else {
546 return contact.position;
547 }
548 }
549
550 pub async fn watch_viewport(self: Rc<Self>) {
552 let configuration_proxy = self.configuration_proxy.clone();
553 let mut viewport_stream = HangingGetStream::new(
554 configuration_proxy,
555 pointerinjector_config::SetupProxy::watch_viewport,
556 );
557 loop {
558 match viewport_stream.next().await {
559 Some(Ok(new_viewport)) => {
560 self.mutable_state.borrow_mut().viewport = Some(new_viewport.clone());
562
563 let injectors: Vec<pointerinjector::DeviceProxy> =
565 self.mutable_state.borrow_mut().injectors.values().cloned().collect();
566 for injector in injectors {
567 let events = vec![pointerinjector::Event {
568 timestamp: Some(MonotonicInstant::now().into_nanos()),
569 data: Some(pointerinjector::Data::Viewport(new_viewport.clone())),
570 trace_flow_id: Some(fuchsia_trace::Id::random().into()),
571 ..Default::default()
572 }];
573 injector.inject_events(events).expect("Failed to inject updated viewport.");
574 }
575 }
576 Some(Err(e)) => {
577 self.metrics_logger.log_error(
578 InputPipelineErrorMetricDimensionEvent::TouchInjectorErrorWhileReadingViewportUpdate,
579 std::format!("Error while reading viewport update: {}", e));
580 return;
581 }
582 None => {
583 self.metrics_logger.log_error(
584 InputPipelineErrorMetricDimensionEvent::TouchInjectorViewportUpdateStreamTerminatedUnexpectedly,
585 "Viewport update stream terminated unexpectedly");
586 return;
587 }
588 }
589 }
590 }
591
592 fn create_touch_buttons_event(
599 event: &mut touch_binding::TouchScreenEvent,
600 event_time: zx::MonotonicInstant,
601 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
602 ) -> fidl_ui_input::TouchButtonsEvent {
603 let pressed_buttons = match event.pressed_buttons.len() {
604 0 => None,
605 _ => Some(
606 event
607 .pressed_buttons
608 .clone()
609 .into_iter()
610 .map(|button| match button {
611 fidl_input_report::TouchButton::Palm => fidl_ui_input::TouchButton::Palm,
612 fidl_input_report::TouchButton::SwipeUp => {
613 fidl_ui_input::TouchButton::SwipeUp
614 }
615 fidl_input_report::TouchButton::SwipeLeft => {
616 fidl_ui_input::TouchButton::SwipeLeft
617 }
618 fidl_input_report::TouchButton::SwipeRight => {
619 fidl_ui_input::TouchButton::SwipeRight
620 }
621 fidl_input_report::TouchButton::SwipeDown => {
622 fidl_ui_input::TouchButton::SwipeDown
623 }
624 fidl_input_report::TouchButton::__SourceBreaking { unknown_ordinal: n } => {
625 fidl_ui_input::TouchButton::__SourceBreaking {
626 unknown_ordinal: n as u32,
627 }
628 }
629 })
630 .collect::<Vec<_>>(),
631 ),
632 };
633 fidl_ui_input::TouchButtonsEvent {
634 event_time: Some(event_time),
635 device_info: Some(fidl_ui_input::TouchDeviceInfo {
636 id: Some(touch_descriptor.device_id),
637 ..Default::default()
638 }),
639 pressed_buttons,
640 wake_lease: event.wake_lease.take(),
641 ..Default::default()
642 }
643 }
644
645 async fn send_event_to_listeners(self: &Rc<Self>, event: &fidl_ui_input::TouchButtonsEvent) {
650 let tracker = &self.mutable_state.borrow().send_event_task_tracker;
651
652 for (handle, listener) in &self.mutable_state.borrow().listeners {
653 let weak_handler = Rc::downgrade(&self);
654 let listener_clone = listener.clone();
655 let handle_clone = handle.clone();
656 let event_to_send = Self::clone_event(event);
657 let fut = async move {
658 match listener_clone.on_event(event_to_send).await {
659 Ok(_) => {}
660 Err(e) => {
661 if let Some(handler) = weak_handler.upgrade() {
662 handler.mutable_state.borrow_mut().listeners.remove(&handle_clone);
663 log::info!(
664 "Unregistering listener; unable to send TouchButtonsEvent: {:?}",
665 e
666 )
667 }
668 }
669 }
670 };
671
672 let metrics_logger_clone = self.metrics_logger.clone();
673 tracker.track(metrics_logger_clone, Dispatcher::spawn_local(fut));
674 }
675 }
676
677 pub async fn register_listener_proxy(
682 self: &Rc<Self>,
683 proxy: fidl_ui_policy::TouchButtonsListenerProxy,
684 ) {
685 self.mutable_state
686 .borrow_mut()
687 .listeners
688 .insert(proxy.as_channel().as_handle_ref().raw_handle(), proxy.clone());
689
690 if let Some(event) = &self.mutable_state.borrow().last_button_event {
692 let event_to_send = Self::clone_event(event);
693 let fut = async move {
694 match proxy.on_event(event_to_send).await {
695 Ok(_) => {}
696 Err(e) => {
697 log::info!("Failed to send touch buttons event to listener {:?}", e)
698 }
699 }
700 };
701 let metrics_logger_clone = self.metrics_logger.clone();
702 self.mutable_state
703 .borrow()
704 .send_event_task_tracker
705 .track(metrics_logger_clone, Dispatcher::spawn_local(fut));
706 }
707 }
708}
709
710#[derive(Debug)]
713pub struct LocalTaskTracker {
714 sender: mpsc::UnboundedSender<TaskHandle<()>>,
715 _receiver_task: TaskHandle<()>,
716}
717
718impl LocalTaskTracker {
719 pub fn new() -> Self {
720 let (sender, receiver) = mpsc::unbounded();
721 let receiver_task = Dispatcher::spawn_local(async move {
722 receiver.for_each_concurrent(None, |task: TaskHandle<()>| task).await
724 });
725
726 Self { sender, _receiver_task: receiver_task }
727 }
728
729 pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: TaskHandle<()>) {
731 match self.sender.unbounded_send(task) {
732 Ok(_) => {}
733 Err(e) => {
737 metrics_logger.log_error(
738 InputPipelineErrorMetricDimensionEvent::TouchFailedToSendTouchScreenEvent,
739 std::format!("Unexpected {e:?} while pushing task"),
740 );
741 }
742 };
743 }
744}
745
746#[cfg(test)]
747mod tests {
748 use super::*;
749 use crate::input_handler::BatchInputHandler;
750 use crate::testing_utilities::{
751 create_fake_input_event, create_touch_contact, create_touch_pointer_sample_event,
752 create_touch_screen_event, create_touch_screen_event_with_handled, create_touchpad_event,
753 get_touch_screen_device_descriptor,
754 };
755 use assert_matches::assert_matches;
756 use futures::{FutureExt, TryStreamExt};
757 use maplit::hashmap;
758 use pretty_assertions::assert_eq;
759 use std::collections::HashSet;
760 use std::convert::TryFrom as _;
761 use std::ops::Add;
762 use {
763 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
764 fidl_fuchsia_ui_policy as fidl_ui_policy, fuchsia_async as fasync,
765 };
766
767 const TOUCH_ID: u32 = 1;
768 const DISPLAY_WIDTH: f32 = 100.0;
769 const DISPLAY_HEIGHT: f32 = 100.0;
770
771 struct TestFixtures {
772 touch_handler: Rc<TouchInjectorHandler>,
773 device_listener_proxy: fidl_ui_policy::DeviceListenerRegistryProxy,
774 injector_registry_request_stream: pointerinjector::RegistryRequestStream,
775 configuration_request_stream: pointerinjector_config::SetupRequestStream,
776 inspector: fuchsia_inspect::Inspector,
777 _test_node: fuchsia_inspect::Node,
778 }
779
780 fn spawn_device_listener_registry_server(
781 handler: Rc<TouchInjectorHandler>,
782 ) -> fidl_ui_policy::DeviceListenerRegistryProxy {
783 let (device_listener_proxy, mut device_listener_stream) =
784 fidl::endpoints::create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>(
785 );
786
787 fasync::Task::local(async move {
788 loop {
789 match device_listener_stream.try_next().await {
790 Ok(Some(
791 fidl_ui_policy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
792 listener,
793 responder,
794 },
795 )) => {
796 handler.register_listener_proxy(listener.into_proxy()).await;
797 let _ = responder.send();
798 }
799 Ok(Some(_)) => {
800 panic!("Unexpected registration");
801 }
802 Ok(None) => {
803 break;
804 }
805 Err(e) => {
806 panic!("Error handling device listener registry request stream: {}", e);
807 }
808 }
809 }
810 })
811 .detach();
812
813 device_listener_proxy
814 }
815
816 impl TestFixtures {
817 async fn new() -> Self {
818 let inspector = fuchsia_inspect::Inspector::default();
819 let test_node = inspector.root().create_child("test_node");
820 let (configuration_proxy, mut configuration_request_stream) =
821 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
822 let (injector_registry_proxy, injector_registry_request_stream) =
823 fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
824
825 let touch_handler_fut = TouchInjectorHandler::new_handler(
826 configuration_proxy,
827 injector_registry_proxy,
828 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
829 &test_node,
830 metrics::MetricsLogger::default(),
831 );
832
833 let handle_initial_request_fut = async {
834 match configuration_request_stream.next().await {
835 Some(Ok(pointerinjector_config::SetupRequest::GetViewRefs {
836 responder,
837 ..
838 })) => {
839 let context = fuchsia_scenic::ViewRefPair::new()
840 .expect("Failed to create viewrefpair.")
841 .view_ref;
842 let target = fuchsia_scenic::ViewRefPair::new()
843 .expect("Failed to create viewrefpair.")
844 .view_ref;
845 let _ = responder.send(context, target);
846 }
847 other => panic!("Expected GetViewRefs request, got {:?}", other),
848 }
849 };
850
851 let (touch_handler_res, _) =
852 futures::future::join(touch_handler_fut, handle_initial_request_fut).await;
853
854 let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
855 let device_listener_proxy =
856 spawn_device_listener_registry_server(touch_handler.clone());
857
858 TestFixtures {
859 touch_handler,
860 device_listener_proxy,
861 injector_registry_request_stream,
862 configuration_request_stream,
863 inspector,
864 _test_node: test_node,
865 }
866 }
867 }
868
869 fn get_touchpad_device_descriptor() -> input_device::InputDeviceDescriptor {
871 input_device::InputDeviceDescriptor::Touchpad(touch_binding::TouchpadDeviceDescriptor {
872 device_id: 1,
873 contacts: vec![touch_binding::ContactDeviceDescriptor {
874 x_range: fidl_input_report::Range { min: 0, max: 100 },
875 y_range: fidl_input_report::Range { min: 0, max: 100 },
876 x_unit: fidl_input_report::Unit {
877 type_: fidl_input_report::UnitType::Meters,
878 exponent: -6,
879 },
880 y_unit: fidl_input_report::Unit {
881 type_: fidl_input_report::UnitType::Meters,
882 exponent: -6,
883 },
884 pressure_range: None,
885 width_range: None,
886 height_range: None,
887 }],
888 })
889 }
890
891 async fn handle_device_request_stream(
894 mut injector_stream: pointerinjector::DeviceRequestStream,
895 expected_event: pointerinjector::Event,
896 ) {
897 match injector_stream.next().await {
898 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
899 panic!("DeviceRequest::Inject is deprecated.");
900 }
901 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
902 assert_eq!(events.len(), 1);
903 assert_eq!(events[0].timestamp, expected_event.timestamp);
904 assert_eq!(events[0].data, expected_event.data);
905 }
906 Some(Err(e)) => panic!("FIDL error {}", e),
907 None => panic!("Expected another event."),
908 }
909 }
910
911 fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
913 pointerinjector::Viewport {
914 extents: Some([[min, min], [max, max]]),
915 viewport_to_context_transform: None,
916 ..Default::default()
917 }
918 }
919
920 #[fuchsia::test]
921 async fn events_with_pressed_buttons_are_sent_to_listener() {
922 let fixtures = TestFixtures::new().await;
923 let (listener, mut listener_stream) =
924 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
925 fixtures
926 .device_listener_proxy
927 .register_touch_buttons_listener(listener)
928 .await
929 .expect("Failed to register listener.");
930
931 let descriptor = get_touch_screen_device_descriptor();
932 let event_time = zx::MonotonicInstant::get();
933 let input_event = create_touch_screen_event(hashmap! {}, event_time, &descriptor);
934
935 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
936
937 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
938 event_time: Some(event_time),
939 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
940 ..Default::default()
941 };
942
943 assert_matches!(
944 listener_stream.next().await,
945 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
946 event,
947 responder,
948 })) => {
949 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
950 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
951 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
952 assert!(event.trace_flow_id.is_some());
953 let _ = responder.send();
954 }
955 );
956 }
957
958 #[fuchsia::test]
959 async fn events_with_contacts_are_not_sent_to_listener() {
960 let fixtures = TestFixtures::new().await;
961 let (listener, mut listener_stream) =
962 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
963 fixtures
964 .device_listener_proxy
965 .register_touch_buttons_listener(listener)
966 .await
967 .expect("Failed to register listener.");
968
969 let descriptor = get_touch_screen_device_descriptor();
970 let event_time = zx::MonotonicInstant::get();
971 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
972 let input_event = create_touch_screen_event(
973 hashmap! {
974 fidl_ui_input::PointerEventPhase::Add
975 => vec![contact.clone()],
976 },
977 event_time,
978 &descriptor,
979 );
980
981 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
982
983 assert!(listener_stream.next().now_or_never().is_none());
984 }
985
986 #[fuchsia::test]
987 async fn multiple_listeners_receive_pressed_button_events() {
988 let fixtures = TestFixtures::new().await;
989 let (first_listener, mut first_listener_stream) =
990 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
991 let (second_listener, mut second_listener_stream) =
992 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
993 fixtures
994 .device_listener_proxy
995 .register_touch_buttons_listener(first_listener)
996 .await
997 .expect("Failed to register listener.");
998 fixtures
999 .device_listener_proxy
1000 .register_touch_buttons_listener(second_listener)
1001 .await
1002 .expect("Failed to register listener.");
1003
1004 let descriptor = get_touch_screen_device_descriptor();
1005 let event_time = zx::MonotonicInstant::get();
1006 let input_event = create_touch_screen_event(hashmap! {}, event_time, &descriptor);
1007
1008 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1009
1010 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
1011 event_time: Some(event_time),
1012 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1013 ..Default::default()
1014 };
1015
1016 assert_matches!(
1017 first_listener_stream.next().await,
1018 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1019 event,
1020 responder,
1021 })) => {
1022 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1023 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1024 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1025 assert!(event.trace_flow_id.is_some());
1026 let _ = responder.send();
1027 }
1028 );
1029 assert_matches!(
1030 second_listener_stream.next().await,
1031 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1032 event,
1033 responder,
1034 })) => {
1035 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1036 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1037 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1038 assert!(event.trace_flow_id.is_some());
1039 let _ = responder.send();
1040 }
1041 );
1042 }
1043
1044 #[fuchsia::test]
1047 async fn receives_viewport_updates() {
1048 let mut fixtures = TestFixtures::new().await;
1049
1050 let (injector_device_proxy, mut injector_device_request_stream) =
1052 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1053 fixtures
1054 .touch_handler
1055 .mutable_state
1056 .borrow_mut()
1057 .injectors
1058 .insert(1, injector_device_proxy);
1059
1060 {
1062 let _watch_viewport_task =
1064 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1065
1066 match fixtures.configuration_request_stream.next().await {
1068 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1069 responder, ..
1070 })) => {
1071 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1072 }
1073 other => panic!("Received unexpected value: {:?}", other),
1074 };
1075
1076 match injector_device_request_stream.next().await {
1078 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1079 panic!("DeviceRequest::Inject is deprecated.");
1080 }
1081 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1082 assert_eq!(events.len(), 1);
1083 assert!(events[0].data.is_some());
1084 assert_eq!(
1085 events[0].data,
1086 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1087 );
1088 }
1089 other => panic!("Received unexpected value: {:?}", other),
1090 }
1091
1092 match fixtures.configuration_request_stream.next().await {
1095 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1096 responder, ..
1097 })) => {
1098 responder
1099 .send(&create_viewport(100.0, 200.0))
1100 .expect("Failed to send viewport.");
1101 }
1102 other => panic!("Received unexpected value: {:?}", other),
1103 };
1104
1105 match injector_device_request_stream.next().await {
1107 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1108 panic!("DeviceRequest::Inject is deprecated.");
1109 }
1110 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1111 assert_eq!(events.len(), 1);
1112 assert!(events[0].data.is_some());
1113 assert_eq!(
1114 events[0].data,
1115 Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
1116 );
1117 }
1118 other => panic!("Received unexpected value: {:?}", other),
1119 }
1120 }
1121
1122 let expected_viewport = create_viewport(100.0, 200.0);
1124 assert_eq!(fixtures.touch_handler.mutable_state.borrow().viewport, Some(expected_viewport));
1125 }
1126
1127 #[fuchsia::test]
1129 async fn add_contact_drops_without_viewport() {
1130 let mut fixtures = TestFixtures::new().await;
1131
1132 let event_time = zx::MonotonicInstant::get();
1134 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1135 let descriptor = get_touch_screen_device_descriptor();
1136 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1137 hashmap! {
1138 fidl_ui_input::PointerEventPhase::Add
1139 => vec![contact.clone()],
1140 },
1141 event_time,
1142 &descriptor,
1143 ))
1144 .unwrap();
1145
1146 fixtures.touch_handler.mutable_state.borrow_mut().viewport = None;
1148
1149 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]).await;
1151
1152 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1154 }
1155
1156 #[fuchsia::test]
1158 async fn add_contact_succeeds_with_viewport() {
1159 let mut fixtures = TestFixtures::new().await;
1160
1161 let (injector_device_proxy, mut injector_device_request_stream) =
1163 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1164 fixtures
1165 .touch_handler
1166 .mutable_state
1167 .borrow_mut()
1168 .injectors
1169 .insert(1, injector_device_proxy);
1170
1171 let _watch_viewport_task =
1173 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1174
1175 match fixtures.configuration_request_stream.next().await {
1177 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1178 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1179 }
1180 other => panic!("Received unexpected value: {:?}", other),
1181 };
1182
1183 match injector_device_request_stream.next().await {
1185 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1186 panic!("DeviceRequest::Inject is deprecated.");
1187 }
1188 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1189 assert_eq!(events.len(), 1);
1190 assert!(events[0].data.is_some());
1191 assert_eq!(
1192 events[0].data,
1193 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1194 );
1195 }
1196 other => panic!("Received unexpected value: {:?}", other),
1197 }
1198
1199 let event_time = zx::MonotonicInstant::get();
1201 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1202 let descriptor = get_touch_screen_device_descriptor();
1203 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1204 hashmap! {
1205 fidl_ui_input::PointerEventPhase::Add
1206 => vec![contact.clone()],
1207 },
1208 event_time,
1209 &descriptor,
1210 ))
1211 .unwrap();
1212
1213 let handle_event_fut =
1215 fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1216
1217 let expected_event = create_touch_pointer_sample_event(
1219 pointerinjector::EventPhase::Add,
1220 &contact,
1221 Position { x: 20.0, y: 40.0 },
1222 event_time,
1223 );
1224
1225 let device_fut =
1228 handle_device_request_stream(injector_device_request_stream, expected_event);
1229 let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1230
1231 assert_matches!(
1233 handle_result.as_slice(),
1234 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1235 );
1236 }
1237
1238 #[fuchsia::test]
1240 async fn add_touchpad_contact_with_viewport() {
1241 let mut fixtures = TestFixtures::new().await;
1242
1243 let (injector_device_proxy, mut injector_device_request_stream) =
1245 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1246 fixtures
1247 .touch_handler
1248 .mutable_state
1249 .borrow_mut()
1250 .injectors
1251 .insert(1, injector_device_proxy);
1252
1253 let _watch_viewport_task =
1255 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1256
1257 match fixtures.configuration_request_stream.next().await {
1259 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1260 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1261 }
1262 other => panic!("Received unexpected value: {:?}", other),
1263 };
1264
1265 match injector_device_request_stream.next().await {
1267 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1268 panic!("DeviceRequest::Inject is deprecated.");
1269 }
1270 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1271 assert_eq!(events.len(), 1);
1272 assert!(events[0].data.is_some());
1273 assert_eq!(
1274 events[0].data,
1275 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1276 );
1277 }
1278 other => panic!("Received unexpected value: {:?}", other),
1279 }
1280
1281 let event_time = zx::MonotonicInstant::get();
1283 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1284 let descriptor = get_touchpad_device_descriptor();
1285 let input_event = input_device::UnhandledInputEvent::try_from(create_touchpad_event(
1286 vec![contact.clone()],
1287 HashSet::new(),
1288 event_time,
1289 &descriptor,
1290 ))
1291 .unwrap();
1292
1293 let handle_event_fut =
1295 fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1296
1297 let handle_result = handle_event_fut.await;
1298
1299 assert_matches!(
1301 handle_result.as_slice(),
1302 [input_device::InputEvent { handled: input_device::Handled::No, .. }]
1303 );
1304
1305 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1307 }
1308
1309 #[fuchsia::test(allow_stalls = false)]
1310 async fn touch_injector_handler_initialized_with_inspect_node() {
1311 let fixtures = TestFixtures::new().await;
1312 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1313 test_node: {
1314 touch_injector_handler: {
1315 events_received_count: 0u64,
1316 events_handled_count: 0u64,
1317 last_received_timestamp_ns: 0u64,
1318 "fuchsia.inspect.Health": {
1319 status: "STARTING_UP",
1320 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1323 },
1324 }
1325 }
1326 });
1327 }
1328
1329 #[fuchsia::test(allow_stalls = false)]
1330 async fn touch_injector_handler_inspect_counts_events() {
1331 let fixtures = TestFixtures::new().await;
1332
1333 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1334 let descriptor = get_touch_screen_device_descriptor();
1335 let event_time1 = zx::MonotonicInstant::get();
1336 let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1337 let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1338
1339 let input_events = vec![
1340 create_touch_screen_event(
1341 hashmap! {
1342 fidl_ui_input::PointerEventPhase::Add
1343 => vec![contact.clone()],
1344 },
1345 event_time1,
1346 &descriptor,
1347 ),
1348 create_touch_screen_event(
1349 hashmap! {
1350 fidl_ui_input::PointerEventPhase::Move
1351 => vec![contact.clone()],
1352 },
1353 event_time2,
1354 &descriptor,
1355 ),
1356 create_fake_input_event(event_time2),
1358 create_touch_screen_event_with_handled(
1360 hashmap! {
1361 fidl_ui_input::PointerEventPhase::Move
1362 => vec![contact.clone()],
1363 },
1364 event_time2,
1365 &descriptor,
1366 input_device::Handled::Yes,
1367 ),
1368 create_touch_screen_event(
1369 hashmap! {
1370 fidl_ui_input::PointerEventPhase::Remove
1371 => vec![contact.clone()],
1372 },
1373 event_time3,
1374 &descriptor,
1375 ),
1376 ];
1377
1378 for input_event in input_events {
1379 fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1380 }
1381
1382 let last_received_event_time: u64 = event_time3.into_nanos().try_into().unwrap();
1383
1384 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1385 test_node: {
1386 touch_injector_handler: {
1387 events_received_count: 3u64,
1388 events_handled_count: 3u64,
1389 last_received_timestamp_ns: last_received_event_time,
1390 "fuchsia.inspect.Health": {
1391 status: "STARTING_UP",
1392 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1395 },
1396 }
1397 }
1398 });
1399 }
1400
1401 #[fuchsia::test]
1402 async fn clone_event_with_lease_duplicates_lease() {
1403 let (event_pair, _) = fidl::EventPair::create();
1404 let event = fidl_ui_input::TouchButtonsEvent {
1405 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1406 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1407 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1408 wake_lease: Some(event_pair),
1409 ..Default::default()
1410 };
1411 let cloned_event = TouchInjectorHandler::clone_event(&event);
1412 assert_eq!(event.event_time, cloned_event.event_time);
1413 assert_eq!(event.device_info, cloned_event.device_info);
1414 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1415 assert!(event.wake_lease.is_some());
1416 assert!(cloned_event.wake_lease.is_some());
1417 assert_ne!(
1418 event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
1419 cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
1420 );
1421 }
1422
1423 #[fuchsia::test]
1424 async fn clone_event_without_lease_has_no_lease() {
1425 let event = fidl_ui_input::TouchButtonsEvent {
1426 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1427 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1428 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1429 wake_lease: None,
1430 ..Default::default()
1431 };
1432 let cloned_event = TouchInjectorHandler::clone_event(&event);
1433 assert_eq!(event.event_time, cloned_event.event_time);
1434 assert_eq!(event.device_info, cloned_event.device_info);
1435 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1436 assert!(event.wake_lease.is_none());
1437 assert!(cloned_event.wake_lease.is_none());
1438 }
1439
1440 #[fuchsia::test]
1441 async fn clone_event_creates_new_trace_id() {
1442 let event = fidl_ui_input::TouchButtonsEvent {
1443 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1444 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1445 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1446 trace_flow_id: Some(123),
1447 ..Default::default()
1448 };
1449 let cloned_event = TouchInjectorHandler::clone_event(&event);
1450 assert_eq!(event.event_time, cloned_event.event_time);
1451 assert_eq!(event.device_info, cloned_event.device_info);
1452 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1453 assert!(cloned_event.trace_flow_id.is_some());
1454 assert_ne!(event.trace_flow_id, cloned_event.trace_flow_id);
1455 }
1456
1457 #[fuchsia::test]
1458 async fn handle_input_events_batches_events() {
1459 let mut fixtures = TestFixtures::new().await;
1460
1461 let (injector_device_proxy, mut injector_device_request_stream) =
1463 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1464 fixtures
1465 .touch_handler
1466 .mutable_state
1467 .borrow_mut()
1468 .injectors
1469 .insert(1, injector_device_proxy);
1470
1471 let _watch_viewport_task =
1473 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1474
1475 match fixtures.configuration_request_stream.next().await {
1477 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1478 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1479 }
1480 other => panic!("Received unexpected value: {:?}", other),
1481 };
1482
1483 match injector_device_request_stream.next().await {
1485 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1486 assert_eq!(events.len(), 1);
1487 assert!(events[0].data.is_some());
1488 assert_eq!(
1489 events[0].data,
1490 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1491 );
1492 }
1493 other => panic!("Received unexpected value: {:?}", other),
1494 }
1495
1496 let event_time1 = zx::MonotonicInstant::get();
1498 let contact1 = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1499 let descriptor = get_touch_screen_device_descriptor();
1500 let input_event1 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1501 hashmap! {
1502 fidl_ui_input::PointerEventPhase::Add
1503 => vec![contact1.clone()],
1504 },
1505 event_time1,
1506 &descriptor,
1507 ))
1508 .unwrap();
1509
1510 let event_time2 = event_time1 + zx::MonotonicDuration::from_millis(10);
1511 let contact2 = create_touch_contact(TOUCH_ID, Position { x: 25.0, y: 45.0 });
1512 let input_event2 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1513 hashmap! {
1514 fidl_ui_input::PointerEventPhase::Move
1515 => vec![contact2.clone()],
1516 },
1517 event_time2,
1518 &descriptor,
1519 ))
1520 .unwrap();
1521
1522 let handle_event_fut = fixtures
1524 .touch_handler
1525 .clone()
1526 .handle_input_events(vec![input_event1.into(), input_event2.into()]);
1527
1528 let expected_event1 = create_touch_pointer_sample_event(
1530 pointerinjector::EventPhase::Add,
1531 &contact1,
1532 Position { x: 20.0, y: 40.0 },
1533 event_time1,
1534 );
1535 let expected_event2 = create_touch_pointer_sample_event(
1536 pointerinjector::EventPhase::Change,
1537 &contact2,
1538 Position { x: 25.0, y: 45.0 },
1539 event_time2,
1540 );
1541
1542 let device_fut = async move {
1543 match injector_device_request_stream.next().await {
1544 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1545 assert_eq!(events.len(), 2);
1546 assert_eq!(events[0].timestamp, expected_event1.timestamp);
1547 assert_eq!(events[0].data, expected_event1.data);
1548 assert_eq!(events[1].timestamp, expected_event2.timestamp);
1549 assert_eq!(events[1].data, expected_event2.data);
1550 }
1551 other => panic!("Received unexpected value: {:?}", other),
1552 }
1553 };
1554
1555 let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1556
1557 assert_matches!(
1559 handle_result.as_slice(),
1560 [
1561 input_device::InputEvent { handled: input_device::Handled::Yes, .. },
1562 input_device::InputEvent { handled: input_device::Handled::Yes, .. }
1563 ]
1564 );
1565 }
1566}