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