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