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::new();
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
306 .duplicate_handle(zx::Rights::SAME_RIGHTS)
307 .expect("failed to duplicate event pair")
308 }),
309 trace_flow_id: Some(trace_flow_id.into()),
310 ..Default::default()
311 }
312 }
313
314 async fn handle_single_input_event(
315 self: Rc<Self>,
316 mut input_event: input_device::InputEvent,
317 ) -> (Vec<input_device::InputEvent>, Vec<pointerinjector::Event>) {
318 match input_event {
319 input_device::InputEvent {
320 device_event: input_device::InputDeviceEvent::TouchScreen(ref mut touch_event),
321 device_descriptor:
322 input_device::InputDeviceDescriptor::TouchScreen(ref touch_device_descriptor),
323 event_time,
324 handled: input_device::Handled::No,
325 trace_id,
326 } => {
327 self.inspect_status.count_received_event(&event_time);
328 fuchsia_trace::duration!("input", "touch_injector_handler[processing]");
329 if let Some(trace_id) = trace_id {
330 fuchsia_trace::flow_step!("input", "event_in_input_pipeline", trace_id.into());
331 }
332
333 let mut scenic_events = vec![];
334 if touch_event.injector_contacts.iter().all(|(_, vec)| vec.is_empty()) {
335 let mut touch_buttons_event = Self::create_touch_buttons_event(
336 touch_event,
337 event_time,
338 &touch_device_descriptor,
339 );
340
341 self.send_event_to_listeners(&touch_buttons_event).await;
343
344 std::mem::drop(touch_buttons_event.wake_lease.take());
346 self.mutable_state.borrow_mut().last_button_event = Some(touch_buttons_event);
347 } else if touch_event.pressed_buttons.is_empty() {
348 if let Err(e) = self.ensure_injector_registered(&touch_device_descriptor).await
350 {
351 self.metrics_logger.log_error(
352 InputPipelineErrorMetricDimensionEvent::TouchInjectorEnsureInjectorRegisteredFailed,
353 std::format!("ensure_injector_registered failed: {}", e));
354 }
355
356 scenic_events = self.create_pointer_events(
358 touch_event,
359 &touch_device_descriptor,
360 event_time,
361 );
362 }
363
364 self.inspect_status.count_handled_event();
366 (vec![input_event.into_handled()], scenic_events)
367 }
368 input_device::InputEvent {
369 device_event: input_device::InputDeviceEvent::TouchScreen(_),
370 handled: input_device::Handled::Yes,
371 ..
372 } => {
373 (vec![input_event], vec![])
375 }
376 _ => {
377 log::warn!("Unhandled input event: {:?}", input_event.get_event_type());
378 (vec![input_event], vec![])
379 }
380 }
381 }
382
383 async fn ensure_injector_registered(
389 self: &Rc<Self>,
390 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
391 ) -> Result<(), anyhow::Error> {
392 if self.mutable_state.borrow().injectors.contains_key(&touch_descriptor.device_id) {
393 return Ok(());
394 }
395
396 let device_proxy;
398 let device_server;
399 #[cfg(feature = "dso")]
400 {
401 let (client, server) = DriverTransport::create_with_dispatcher(fdf::CurrentDispatcher);
402 device_proxy =
403 fidl_next::ClientEnd::<pointerinjector_dso::Device, DriverTransport>::from_untyped(
404 client,
405 )
406 .spawn();
407 device_server =
408 fidl_next::ServerEnd::<pointerinjector_dso::Device, DriverTransport>::from_untyped(
409 server,
410 );
411 }
412 #[cfg(not(feature = "dso"))]
413 {
414 let (client, server) = fidl_next::fuchsia::create_channel::<pointerinjector::Device>();
415 device_proxy = Dispatcher::client_from_zx_channel(client).spawn();
416 device_server = server;
417 }
418 let context = utils::duplicate_view_ref_next(&self.context_view_ref)
419 .context("Failed to duplicate context view ref.")?;
420 let context = fidl_next_fuchsia_ui_views::ViewRef { reference: context.reference };
421 let target = utils::duplicate_view_ref_next(&self.target_view_ref)
422 .context("Failed to duplicate target view ref.")?;
423 let target = fidl_next_fuchsia_ui_views::ViewRef { reference: target.reference };
424 let viewport = self.mutable_state.borrow().viewport.clone();
425 if viewport.is_none() {
426 return Err(anyhow::format_err!(
429 "Received a touch event without a viewport to inject into."
430 ));
431 }
432 let config = pointerinjector::Config {
433 device_id: Some(touch_descriptor.device_id),
434 device_type: Some(pointerinjector::DeviceType::Touch),
435 context: Some(pointerinjector::Context::View(context)),
436 target: Some(pointerinjector::Target::View(target)),
437 viewport,
438 dispatch_policy: Some(pointerinjector::DispatchPolicy::TopHitAndAncestorsInTarget),
439 scroll_v_range: None,
440 scroll_h_range: None,
441 buttons: None,
442 ..Default::default()
443 };
444
445 self.mutable_state.borrow_mut().injectors.insert(touch_descriptor.device_id, device_proxy);
447
448 self.injector_registry_proxy
450 .register(config, device_server)
451 .await
452 .context("Failed to register injector.")?;
453 log::info!("Registered injector with device id {:?}", touch_descriptor.device_id);
454
455 Ok(())
456 }
457
458 fn create_pointer_events(
465 &self,
466 touch_event: &mut touch_binding::TouchScreenEvent,
467 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
468 event_time: zx::MonotonicInstant,
469 ) -> Vec<pointerinjector::Event> {
470 let ordered_phases = vec![
471 pointerinjector::EventPhase::Add,
472 pointerinjector::EventPhase::Change,
473 pointerinjector::EventPhase::Remove,
474 ];
475
476 let mut events: Vec<pointerinjector::Event> = vec![];
477 for phase in ordered_phases {
478 let contacts: Vec<touch_binding::TouchContact> = touch_event
479 .injector_contacts
480 .get(&phase)
481 .map_or(vec![], |contacts| contacts.to_owned());
482 let new_events = contacts.into_iter().map(|contact| {
483 Self::create_pointer_sample_event(
484 phase,
485 &contact,
486 touch_descriptor,
487 &self.display_size,
488 event_time,
489 touch_event.wake_lease.take(),
490 )
491 });
492 events.extend(new_events);
493 }
494
495 events
496 }
497
498 async fn inject_pointer_events(
504 &self,
505 events: Vec<pointerinjector::Event>,
506 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
507 ) -> Result<(), anyhow::Error> {
508 fuchsia_trace::duration!("input", "touch-inject-into-scenic");
509
510 let injector =
511 self.mutable_state.borrow().injectors.get(&touch_descriptor.device_id).cloned();
512 if let Some(injector) = injector {
513 _ = injector.inject_events(events).send_immediately();
514 Ok(())
515 } else {
516 Err(anyhow::format_err!(
517 "No injector found for touch device {}.",
518 touch_descriptor.device_id
519 ))
520 }
521 }
522
523 fn create_pointer_sample_event(
533 phase: pointerinjector::EventPhase,
534 contact: &touch_binding::TouchContact,
535 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
536 display_size: &Size,
537 event_time: zx::MonotonicInstant,
538 wake_lease: Option<zx::EventPair>,
539 ) -> pointerinjector::Event {
540 let position =
541 Self::display_coordinate_from_contact(&contact, &touch_descriptor, display_size);
542 let pointer_sample = pointerinjector::PointerSample {
543 pointer_id: Some(contact.id),
544 phase: Some(phase),
545 position_in_viewport: Some([position.x, position.y]),
546 scroll_v: None,
547 scroll_h: None,
548 pressed_buttons: None,
549 ..Default::default()
550 };
551 let data = pointerinjector::Data::PointerSample(pointer_sample);
552
553 let trace_flow_id = fuchsia_trace::Id::new();
554 let event = pointerinjector::Event {
555 timestamp: Some(event_time.into_nanos()),
556 data: Some(data),
557 trace_flow_id: Some(trace_flow_id.into()),
558 wake_lease,
559 ..Default::default()
560 };
561
562 fuchsia_trace::flow_begin!("input", "dispatch_event_to_scenic", trace_flow_id);
563
564 event
565 }
566
567 fn display_coordinate_from_contact(
581 contact: &touch_binding::TouchContact,
582 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
583 display_size: &Size,
584 ) -> Position {
585 if let Some(contact_descriptor) = touch_descriptor.contacts.first() {
586 let x_range: f32 =
588 contact_descriptor.x_range.max as f32 - contact_descriptor.x_range.min as f32;
589 let x_wrt_range: f32 = contact.position.x - contact_descriptor.x_range.min as f32;
590 let x: f32 = (display_size.width * x_wrt_range) / x_range;
591
592 let y_range: f32 =
594 contact_descriptor.y_range.max as f32 - contact_descriptor.y_range.min as f32;
595 let y_wrt_range: f32 = contact.position.y - contact_descriptor.y_range.min as f32;
596 let y: f32 = (display_size.height * y_wrt_range) / y_range;
597
598 Position { x, y }
599 } else {
600 return contact.position;
601 }
602 }
603
604 pub async fn watch_viewport(self: Rc<Self>) {
606 let configuration_proxy = self.configuration_proxy.clone();
607 let mut viewport_stream = HangingGetStream::new(
608 configuration_proxy,
609 pointerinjector_config::SetupProxy::watch_viewport,
610 );
611 loop {
612 match viewport_stream.next().await {
613 Some(Ok(new_viewport)) => {
614 self.mutable_state.borrow_mut().viewport =
616 Some(utils::viewport_to_next(&new_viewport));
617
618 let injectors: Vec<fidl_next::Client<_, _>> = self
620 .mutable_state
621 .borrow()
622 .injectors
623 .iter()
624 .map(|(_, v)| v)
625 .cloned()
626 .collect();
627 for injector in injectors {
628 let events = vec![pointerinjector::Event {
629 timestamp: Some(MonotonicInstant::now().into_nanos()),
630 data: Some(pointerinjector::Data::Viewport(utils::viewport_to_next(
631 &new_viewport,
632 ))),
633 trace_flow_id: Some(fuchsia_trace::Id::new().into()),
634 ..Default::default()
635 }];
636 injector
637 .inject_events(events)
638 .send_immediately()
639 .expect("Failed to inject updated viewport.");
640 }
641 }
642 Some(Err(e)) => {
643 self.metrics_logger.log_error(
644 InputPipelineErrorMetricDimensionEvent::TouchInjectorErrorWhileReadingViewportUpdate,
645 std::format!("Error while reading viewport update: {}", e));
646 return;
647 }
648 None => {
649 self.metrics_logger.log_error(
650 InputPipelineErrorMetricDimensionEvent::TouchInjectorViewportUpdateStreamTerminatedUnexpectedly,
651 "Viewport update stream terminated unexpectedly");
652 return;
653 }
654 }
655 }
656 }
657
658 fn create_touch_buttons_event(
665 event: &mut touch_binding::TouchScreenEvent,
666 event_time: zx::MonotonicInstant,
667 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
668 ) -> fidl_ui_input::TouchButtonsEvent {
669 let pressed_buttons = match event.pressed_buttons.len() {
670 0 => None,
671 _ => Some(
672 event
673 .pressed_buttons
674 .clone()
675 .into_iter()
676 .map(|button| match button {
677 fidl_next_fuchsia_input_report::TouchButton::Palm => {
678 fidl_ui_input::TouchButton::Palm
679 }
680 fidl_next_fuchsia_input_report::TouchButton::SwipeUp => {
681 fidl_ui_input::TouchButton::SwipeUp
682 }
683 fidl_next_fuchsia_input_report::TouchButton::SwipeLeft => {
684 fidl_ui_input::TouchButton::SwipeLeft
685 }
686 fidl_next_fuchsia_input_report::TouchButton::SwipeRight => {
687 fidl_ui_input::TouchButton::SwipeRight
688 }
689 fidl_next_fuchsia_input_report::TouchButton::SwipeDown => {
690 fidl_ui_input::TouchButton::SwipeDown
691 }
692 fidl_next_fuchsia_input_report::TouchButton::UnknownOrdinal_(n) => {
693 fidl_ui_input::TouchButton::__SourceBreaking {
694 unknown_ordinal: n as u32,
695 }
696 }
697 })
698 .collect::<Vec<_>>(),
699 ),
700 };
701 fidl_ui_input::TouchButtonsEvent {
702 event_time: Some(event_time),
703 device_info: Some(fidl_ui_input::TouchDeviceInfo {
704 id: Some(touch_descriptor.device_id),
705 ..Default::default()
706 }),
707 pressed_buttons,
708 wake_lease: event.wake_lease.take(),
709 ..Default::default()
710 }
711 }
712
713 async fn send_event_to_listeners(self: &Rc<Self>, event: &fidl_ui_input::TouchButtonsEvent) {
718 let tracker = &self.mutable_state.borrow().send_event_task_tracker;
719
720 for (handle, listener) in self.mutable_state.borrow().listeners.iter() {
721 let weak_handler = Rc::downgrade(&self);
722 let listener_clone = listener.clone();
723 let handle_clone = handle.clone();
724 let event_to_send = Self::clone_event(event);
725 let fut = async move {
726 match listener_clone.on_event(event_to_send).await {
727 Ok(_) => {}
728 Err(e) => {
729 if let Some(handler) = weak_handler.upgrade() {
730 handler.mutable_state.borrow_mut().listeners.remove(&handle_clone);
731 log::info!(
732 "Unregistering listener; unable to send TouchButtonsEvent: {:?}",
733 e
734 )
735 }
736 }
737 }
738 };
739
740 let metrics_logger_clone = self.metrics_logger.clone();
741 tracker.track(metrics_logger_clone, Dispatcher::spawn_local(fut));
742 }
743 }
744
745 pub async fn register_listener_proxy(
750 self: &Rc<Self>,
751 proxy: fidl_ui_policy::TouchButtonsListenerProxy,
752 ) {
753 self.mutable_state
754 .borrow_mut()
755 .listeners
756 .insert(proxy.as_channel().as_handle_ref().raw_handle(), proxy.clone());
757
758 if let Some(event) = &self.mutable_state.borrow().last_button_event {
760 let event_to_send = Self::clone_event(event);
761 let fut = async move {
762 match proxy.on_event(event_to_send).await {
763 Ok(_) => {}
764 Err(e) => {
765 log::info!("Failed to send touch buttons event to listener {:?}", e)
766 }
767 }
768 };
769 let metrics_logger_clone = self.metrics_logger.clone();
770 self.mutable_state
771 .borrow()
772 .send_event_task_tracker
773 .track(metrics_logger_clone, Dispatcher::spawn_local(fut));
774 }
775 }
776}
777
778#[derive(Debug)]
781pub struct LocalTaskTracker {
782 sender: mpsc::UnboundedSender<TaskHandle<()>>,
783 _receiver_task: TaskHandle<()>,
784}
785
786impl LocalTaskTracker {
787 pub fn new() -> Self {
788 let (sender, receiver) = mpsc::unbounded();
789 let _receiver_task = Dispatcher::spawn_local(async move {
790 receiver.for_each_concurrent(None, |task: TaskHandle<()>| task).await
792 });
793
794 Self { sender, _receiver_task }
795 }
796
797 pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: TaskHandle<()>) {
799 match self.sender.unbounded_send(task) {
800 Ok(_) => {}
801 Err(e) => {
805 metrics_logger.log_error(
806 InputPipelineErrorMetricDimensionEvent::TouchFailedToSendTouchScreenEvent,
807 std::format!("Unexpected {e:?} while pushing task"),
808 );
809 }
810 };
811 }
812}
813
814#[cfg(test)]
815mod tests {
816 use super::*;
817 use crate::input_handler::BatchInputHandler;
818 use crate::testing_utilities::{
819 create_fake_input_event, create_touch_contact, create_touch_pointer_sample_event,
820 create_touch_screen_event, create_touch_screen_event_with_handled, create_touchpad_event,
821 get_touch_screen_device_descriptor, next_client_old_stream,
822 };
823 use assert_matches::assert_matches;
824 use fidl_fuchsia_input_report as fidl_input_report;
825 use fidl_fuchsia_ui_input as fidl_ui_input;
826 use fidl_fuchsia_ui_pointerinjector as pointerinjector;
827 use fidl_fuchsia_ui_policy as fidl_ui_policy;
828 use fidl_next_fuchsia_ui_pointerinjector as pointerinjector_next;
829 use fuchsia_async as fasync;
830 use futures::{FutureExt, TryStreamExt};
831 use pretty_assertions::assert_eq;
832 use sorted_vec_map::SortedVecSet;
833 use std::convert::TryFrom as _;
834 use std::ops::Add;
835
836 const TOUCH_ID: u32 = 1;
837 const DISPLAY_WIDTH: f32 = 100.0;
838 const DISPLAY_HEIGHT: f32 = 100.0;
839
840 struct TestFixtures {
841 touch_handler: Rc<TouchInjectorHandler>,
842 device_listener_proxy: fidl_ui_policy::DeviceListenerRegistryProxy,
843 injector_registry_request_stream: pointerinjector::RegistryRequestStream,
844 configuration_request_stream: pointerinjector_config::SetupRequestStream,
845 inspector: fuchsia_inspect::Inspector,
846 _test_node: fuchsia_inspect::Node,
847 }
848
849 fn spawn_device_listener_registry_server(
850 handler: Rc<TouchInjectorHandler>,
851 ) -> fidl_ui_policy::DeviceListenerRegistryProxy {
852 let (device_listener_proxy, mut device_listener_stream) =
853 fidl::endpoints::create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>(
854 );
855
856 fasync::Task::local(async move {
857 loop {
858 match device_listener_stream.try_next().await {
859 Ok(Some(
860 fidl_ui_policy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
861 listener,
862 responder,
863 },
864 )) => {
865 handler.register_listener_proxy(listener.into_proxy()).await;
866 let _ = responder.send();
867 }
868 Ok(Some(_)) => {
869 panic!("Unexpected registration");
870 }
871 Ok(None) => {
872 break;
873 }
874 Err(e) => {
875 panic!("Error handling device listener registry request stream: {}", e);
876 }
877 }
878 }
879 })
880 .detach();
881
882 device_listener_proxy
883 }
884
885 impl TestFixtures {
886 async fn new() -> Self {
887 let inspector = fuchsia_inspect::Inspector::default();
888 let test_node = inspector.root().create_child("test_node");
889 let (configuration_proxy, mut configuration_request_stream) =
890 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
891 let (injector_registry_proxy, injector_registry_request_stream) =
892 next_client_old_stream::<
893 pointerinjector::RegistryMarker,
894 pointerinjector_next::Registry,
895 >();
896
897 let touch_handler_fut = TouchInjectorHandler::new_handler(
898 configuration_proxy,
899 injector_registry_proxy,
900 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
901 &test_node,
902 metrics::MetricsLogger::default(),
903 );
904
905 let handle_initial_request_fut = async {
906 match configuration_request_stream.next().await {
907 Some(Ok(pointerinjector_config::SetupRequest::GetViewRefs {
908 responder,
909 ..
910 })) => {
911 let context = fuchsia_scenic::ViewRefPair::new()
912 .expect("Failed to create viewrefpair.")
913 .view_ref;
914 let target = fuchsia_scenic::ViewRefPair::new()
915 .expect("Failed to create viewrefpair.")
916 .view_ref;
917 let _ = responder.send(context, target);
918 }
919 other => panic!("Expected GetViewRefs request, got {:?}", other),
920 }
921 };
922
923 let (touch_handler_res, _) =
924 futures::future::join(touch_handler_fut, handle_initial_request_fut).await;
925
926 let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
927 let device_listener_proxy =
928 spawn_device_listener_registry_server(touch_handler.clone());
929
930 TestFixtures {
931 touch_handler,
932 device_listener_proxy,
933 injector_registry_request_stream,
934 configuration_request_stream,
935 inspector,
936 _test_node: test_node,
937 }
938 }
939 }
940
941 fn get_touchpad_device_descriptor() -> input_device::InputDeviceDescriptor {
943 input_device::InputDeviceDescriptor::Touchpad(touch_binding::TouchpadDeviceDescriptor {
944 device_id: 1,
945 contacts: vec![touch_binding::ContactDeviceDescriptor {
946 x_range: fidl_input_report::Range { min: 0, max: 100 },
947 y_range: fidl_input_report::Range { min: 0, max: 100 },
948 x_unit: fidl_input_report::Unit {
949 type_: fidl_input_report::UnitType::Meters,
950 exponent: -6,
951 },
952 y_unit: fidl_input_report::Unit {
953 type_: fidl_input_report::UnitType::Meters,
954 exponent: -6,
955 },
956 pressure_range: None,
957 width_range: None,
958 height_range: None,
959 }],
960 })
961 }
962
963 async fn handle_device_request_stream(
966 mut injector_stream: pointerinjector::DeviceRequestStream,
967 expected_event: pointerinjector::Event,
968 ) {
969 match injector_stream.next().await {
970 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
971 panic!("DeviceRequest::Inject is deprecated.");
972 }
973 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
974 assert_eq!(events.len(), 1);
975 assert_eq!(events[0].timestamp, expected_event.timestamp);
976 assert_eq!(events[0].data, expected_event.data);
977 }
978 Some(Err(e)) => panic!("FIDL error {}", e),
979 None => panic!("Expected another event."),
980 }
981 }
982
983 fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
984 pointerinjector::Viewport {
985 extents: Some([[min, min], [max, max]]),
986 viewport_to_context_transform: None,
987 ..Default::default()
988 }
989 }
990
991 fn create_viewport_next(min: f32, max: f32) -> pointerinjector_next::Viewport {
992 pointerinjector_next::Viewport {
993 extents: Some([[min, min], [max, max]]),
994 viewport_to_context_transform: None,
995 ..Default::default()
996 }
997 }
998
999 #[fuchsia::test]
1000 async fn events_with_pressed_buttons_are_sent_to_listener() {
1001 let fixtures = TestFixtures::new().await;
1002 let (listener, mut listener_stream) =
1003 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1004 fixtures
1005 .device_listener_proxy
1006 .register_touch_buttons_listener(listener)
1007 .await
1008 .expect("Failed to register listener.");
1009
1010 let descriptor = get_touch_screen_device_descriptor();
1011 let event_time = zx::MonotonicInstant::get();
1012 let input_event = create_touch_screen_event(SortedVecMap::new(), event_time, &descriptor);
1013
1014 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1015
1016 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
1017 event_time: Some(event_time),
1018 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1019 ..Default::default()
1020 };
1021
1022 assert_matches!(
1023 listener_stream.next().await,
1024 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1025 event,
1026 responder,
1027 })) => {
1028 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1029 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1030 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1031 assert!(event.trace_flow_id.is_some());
1032 let _ = responder.send();
1033 }
1034 );
1035 }
1036
1037 #[fuchsia::test]
1038 async fn events_with_contacts_are_not_sent_to_listener() {
1039 let fixtures = TestFixtures::new().await;
1040 let (listener, mut listener_stream) =
1041 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1042 fixtures
1043 .device_listener_proxy
1044 .register_touch_buttons_listener(listener)
1045 .await
1046 .expect("Failed to register listener.");
1047
1048 let descriptor = get_touch_screen_device_descriptor();
1049 let event_time = zx::MonotonicInstant::get();
1050 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1051 let input_event = create_touch_screen_event(
1052 SortedVecMap::from_iter(vec![(
1053 fidl_ui_input::PointerEventPhase::Add,
1054 vec![contact.clone()],
1055 )]),
1056 event_time,
1057 &descriptor,
1058 );
1059
1060 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1061
1062 assert!(listener_stream.next().now_or_never().is_none());
1063 }
1064
1065 #[fuchsia::test]
1066 async fn multiple_listeners_receive_pressed_button_events() {
1067 let fixtures = TestFixtures::new().await;
1068 let (first_listener, mut first_listener_stream) =
1069 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1070 let (second_listener, mut second_listener_stream) =
1071 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1072 fixtures
1073 .device_listener_proxy
1074 .register_touch_buttons_listener(first_listener)
1075 .await
1076 .expect("Failed to register listener.");
1077 fixtures
1078 .device_listener_proxy
1079 .register_touch_buttons_listener(second_listener)
1080 .await
1081 .expect("Failed to register listener.");
1082
1083 let descriptor = get_touch_screen_device_descriptor();
1084 let event_time = zx::MonotonicInstant::get();
1085 let input_event = create_touch_screen_event(SortedVecMap::new(), event_time, &descriptor);
1086
1087 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1088
1089 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
1090 event_time: Some(event_time),
1091 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1092 ..Default::default()
1093 };
1094
1095 assert_matches!(
1096 first_listener_stream.next().await,
1097 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1098 event,
1099 responder,
1100 })) => {
1101 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1102 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1103 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1104 assert!(event.trace_flow_id.is_some());
1105 let _ = responder.send();
1106 }
1107 );
1108 assert_matches!(
1109 second_listener_stream.next().await,
1110 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1111 event,
1112 responder,
1113 })) => {
1114 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1115 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1116 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1117 assert!(event.trace_flow_id.is_some());
1118 let _ = responder.send();
1119 }
1120 );
1121 }
1122
1123 #[fuchsia::test]
1126 async fn receives_viewport_updates() {
1127 let mut fixtures = TestFixtures::new().await;
1128
1129 let (injector_device_proxy, mut injector_device_request_stream) =
1131 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1132 fixtures
1133 .touch_handler
1134 .mutable_state
1135 .borrow_mut()
1136 .injectors
1137 .insert(1, injector_device_proxy);
1138
1139 {
1141 let _watch_viewport_task =
1143 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1144
1145 match fixtures.configuration_request_stream.next().await {
1147 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1148 responder, ..
1149 })) => {
1150 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1151 }
1152 other => panic!("Received unexpected value: {:?}", other),
1153 };
1154
1155 match injector_device_request_stream.next().await {
1157 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1158 panic!("DeviceRequest::Inject is deprecated.");
1159 }
1160 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1161 assert_eq!(events.len(), 1);
1162 assert!(events[0].data.is_some());
1163 assert_eq!(
1164 events[0].data,
1165 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1166 );
1167 }
1168 other => panic!("Received unexpected value: {:?}", other),
1169 }
1170
1171 match fixtures.configuration_request_stream.next().await {
1174 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1175 responder, ..
1176 })) => {
1177 responder
1178 .send(&create_viewport(100.0, 200.0))
1179 .expect("Failed to send viewport.");
1180 }
1181 other => panic!("Received unexpected value: {:?}", other),
1182 };
1183
1184 match injector_device_request_stream.next().await {
1186 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1187 panic!("DeviceRequest::Inject is deprecated.");
1188 }
1189 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1190 assert_eq!(events.len(), 1);
1191 assert!(events[0].data.is_some());
1192 assert_eq!(
1193 events[0].data,
1194 Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
1195 );
1196 }
1197 other => panic!("Received unexpected value: {:?}", other),
1198 }
1199 }
1200
1201 let expected_viewport = create_viewport_next(100.0, 200.0);
1203 assert_eq!(fixtures.touch_handler.mutable_state.borrow().viewport, Some(expected_viewport));
1204 }
1205
1206 #[fuchsia::test]
1208 async fn add_contact_drops_without_viewport() {
1209 let mut fixtures = TestFixtures::new().await;
1210
1211 let event_time = zx::MonotonicInstant::get();
1213 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1214 let descriptor = get_touch_screen_device_descriptor();
1215 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1216 SortedVecMap::from_iter(vec![(
1217 fidl_ui_input::PointerEventPhase::Add,
1218 vec![contact.clone()],
1219 )]),
1220 event_time,
1221 &descriptor,
1222 ))
1223 .unwrap();
1224
1225 fixtures.touch_handler.mutable_state.borrow_mut().viewport = None;
1227
1228 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]).await;
1230
1231 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1233 }
1234
1235 #[fuchsia::test]
1237 async fn add_contact_succeeds_with_viewport() {
1238 let mut fixtures = TestFixtures::new().await;
1239
1240 let (injector_device_proxy, mut injector_device_request_stream) =
1242 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1243 fixtures
1244 .touch_handler
1245 .mutable_state
1246 .borrow_mut()
1247 .injectors
1248 .insert(1, injector_device_proxy);
1249
1250 let _watch_viewport_task =
1252 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1253
1254 match fixtures.configuration_request_stream.next().await {
1256 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1257 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1258 }
1259 other => panic!("Received unexpected value: {:?}", other),
1260 };
1261
1262 match injector_device_request_stream.next().await {
1264 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1265 panic!("DeviceRequest::Inject is deprecated.");
1266 }
1267 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1268 assert_eq!(events.len(), 1);
1269 assert!(events[0].data.is_some());
1270 assert_eq!(
1271 events[0].data,
1272 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1273 );
1274 }
1275 other => panic!("Received unexpected value: {:?}", other),
1276 }
1277
1278 let event_time = zx::MonotonicInstant::get();
1280 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1281 let descriptor = get_touch_screen_device_descriptor();
1282 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1283 SortedVecMap::from_iter(vec![(
1284 fidl_ui_input::PointerEventPhase::Add,
1285 vec![contact.clone()],
1286 )]),
1287 event_time,
1288 &descriptor,
1289 ))
1290 .unwrap();
1291
1292 let handle_event_fut =
1294 fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1295
1296 let expected_event = create_touch_pointer_sample_event(
1298 pointerinjector::EventPhase::Add,
1299 &contact,
1300 Position { x: 20.0, y: 40.0 },
1301 event_time,
1302 );
1303
1304 let device_fut =
1307 handle_device_request_stream(injector_device_request_stream, expected_event);
1308 let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1309
1310 assert_matches!(
1312 handle_result.as_slice(),
1313 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1314 );
1315 }
1316
1317 #[fuchsia::test]
1319 async fn add_touchpad_contact_with_viewport() {
1320 let mut fixtures = TestFixtures::new().await;
1321
1322 let (injector_device_proxy, mut injector_device_request_stream) =
1324 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1325 fixtures
1326 .touch_handler
1327 .mutable_state
1328 .borrow_mut()
1329 .injectors
1330 .insert(1, injector_device_proxy);
1331
1332 let _watch_viewport_task =
1334 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1335
1336 match fixtures.configuration_request_stream.next().await {
1338 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1339 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1340 }
1341 other => panic!("Received unexpected value: {:?}", other),
1342 };
1343
1344 match injector_device_request_stream.next().await {
1346 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1347 panic!("DeviceRequest::Inject is deprecated.");
1348 }
1349 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1350 assert_eq!(events.len(), 1);
1351 assert!(events[0].data.is_some());
1352 assert_eq!(
1353 events[0].data,
1354 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1355 );
1356 }
1357 other => panic!("Received unexpected value: {:?}", other),
1358 }
1359
1360 let event_time = zx::MonotonicInstant::get();
1362 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1363 let descriptor = get_touchpad_device_descriptor();
1364 let input_event = input_device::UnhandledInputEvent::try_from(create_touchpad_event(
1365 vec![contact.clone()],
1366 SortedVecSet::new(),
1367 event_time,
1368 &descriptor,
1369 ))
1370 .unwrap();
1371
1372 let handle_event_fut =
1374 fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1375
1376 let handle_result = handle_event_fut.await;
1377
1378 assert_matches!(
1380 handle_result.as_slice(),
1381 [input_device::InputEvent { handled: input_device::Handled::No, .. }]
1382 );
1383
1384 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1386 }
1387
1388 #[fuchsia::test(allow_stalls = false)]
1389 async fn touch_injector_handler_initialized_with_inspect_node() {
1390 let fixtures = TestFixtures::new().await;
1391 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1392 test_node: {
1393 touch_injector_handler: {
1394 events_received_count: 0u64,
1395 events_handled_count: 0u64,
1396 last_received_timestamp_ns: 0u64,
1397 "fuchsia.inspect.Health": {
1398 status: "STARTING_UP",
1399 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1402 },
1403 }
1404 }
1405 });
1406 }
1407
1408 #[fuchsia::test(allow_stalls = false)]
1409 async fn touch_injector_handler_inspect_counts_events() {
1410 let fixtures = TestFixtures::new().await;
1411
1412 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1413 let descriptor = get_touch_screen_device_descriptor();
1414 let event_time1 = zx::MonotonicInstant::get();
1415 let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1416 let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1417
1418 let input_events = vec![
1419 create_touch_screen_event(
1420 SortedVecMap::from_iter(vec![(
1421 fidl_ui_input::PointerEventPhase::Add,
1422 vec![contact.clone()],
1423 )]),
1424 event_time1,
1425 &descriptor,
1426 ),
1427 create_touch_screen_event(
1428 SortedVecMap::from_iter(vec![(
1429 fidl_ui_input::PointerEventPhase::Move,
1430 vec![contact.clone()],
1431 )]),
1432 event_time2,
1433 &descriptor,
1434 ),
1435 create_fake_input_event(event_time2),
1437 create_touch_screen_event_with_handled(
1439 SortedVecMap::from_iter(vec![(
1440 fidl_ui_input::PointerEventPhase::Move,
1441 vec![contact.clone()],
1442 )]),
1443 event_time2,
1444 &descriptor,
1445 input_device::Handled::Yes,
1446 ),
1447 create_touch_screen_event(
1448 SortedVecMap::from_iter(vec![(
1449 fidl_ui_input::PointerEventPhase::Remove,
1450 vec![contact.clone()],
1451 )]),
1452 event_time3,
1453 &descriptor,
1454 ),
1455 ];
1456
1457 for input_event in input_events {
1458 fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1459 }
1460
1461 let last_received_event_time: u64 = event_time3.into_nanos().try_into().unwrap();
1462
1463 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1464 test_node: {
1465 touch_injector_handler: {
1466 events_received_count: 3u64,
1467 events_handled_count: 3u64,
1468 last_received_timestamp_ns: last_received_event_time,
1469 "fuchsia.inspect.Health": {
1470 status: "STARTING_UP",
1471 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1474 },
1475 }
1476 }
1477 });
1478 }
1479
1480 #[fuchsia::test]
1481 async fn clone_event_with_lease_duplicates_lease() {
1482 let (event_pair, _) = fidl::EventPair::create();
1483 let event = fidl_ui_input::TouchButtonsEvent {
1484 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1485 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1486 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1487 wake_lease: Some(event_pair),
1488 ..Default::default()
1489 };
1490 let cloned_event = TouchInjectorHandler::clone_event(&event);
1491 assert_eq!(event.event_time, cloned_event.event_time);
1492 assert_eq!(event.device_info, cloned_event.device_info);
1493 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1494 assert!(event.wake_lease.is_some());
1495 assert!(cloned_event.wake_lease.is_some());
1496 assert_ne!(
1497 event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
1498 cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
1499 );
1500 }
1501
1502 #[fuchsia::test]
1503 async fn clone_event_without_lease_has_no_lease() {
1504 let event = fidl_ui_input::TouchButtonsEvent {
1505 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1506 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1507 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1508 wake_lease: None,
1509 ..Default::default()
1510 };
1511 let cloned_event = TouchInjectorHandler::clone_event(&event);
1512 assert_eq!(event.event_time, cloned_event.event_time);
1513 assert_eq!(event.device_info, cloned_event.device_info);
1514 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1515 assert!(event.wake_lease.is_none());
1516 assert!(cloned_event.wake_lease.is_none());
1517 }
1518
1519 #[fuchsia::test]
1520 async fn clone_event_creates_new_trace_id() {
1521 let event = fidl_ui_input::TouchButtonsEvent {
1522 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1523 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1524 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1525 trace_flow_id: Some(123),
1526 ..Default::default()
1527 };
1528 let cloned_event = TouchInjectorHandler::clone_event(&event);
1529 assert_eq!(event.event_time, cloned_event.event_time);
1530 assert_eq!(event.device_info, cloned_event.device_info);
1531 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1532 assert!(cloned_event.trace_flow_id.is_some());
1533 assert_ne!(event.trace_flow_id, cloned_event.trace_flow_id);
1534 }
1535
1536 #[fuchsia::test]
1537 async fn handle_input_events_batches_events() {
1538 let mut fixtures = TestFixtures::new().await;
1539
1540 let (injector_device_proxy, mut injector_device_request_stream) =
1542 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1543 fixtures
1544 .touch_handler
1545 .mutable_state
1546 .borrow_mut()
1547 .injectors
1548 .insert(1, injector_device_proxy);
1549
1550 let _watch_viewport_task =
1552 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1553
1554 match fixtures.configuration_request_stream.next().await {
1556 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1557 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1558 }
1559 other => panic!("Received unexpected value: {:?}", other),
1560 };
1561
1562 match injector_device_request_stream.next().await {
1564 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1565 assert_eq!(events.len(), 1);
1566 assert!(events[0].data.is_some());
1567 assert_eq!(
1568 events[0].data,
1569 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1570 );
1571 }
1572 other => panic!("Received unexpected value: {:?}", other),
1573 }
1574
1575 let event_time1 = zx::MonotonicInstant::get();
1577 let contact1 = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1578 let descriptor = get_touch_screen_device_descriptor();
1579 let input_event1 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1580 SortedVecMap::from_iter(vec![(
1581 fidl_ui_input::PointerEventPhase::Add,
1582 vec![contact1.clone()],
1583 )]),
1584 event_time1,
1585 &descriptor,
1586 ))
1587 .unwrap();
1588
1589 let event_time2 = event_time1 + zx::MonotonicDuration::from_millis(10);
1590 let contact2 = create_touch_contact(TOUCH_ID, Position { x: 25.0, y: 45.0 });
1591 let input_event2 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1592 SortedVecMap::from_iter(vec![(
1593 fidl_ui_input::PointerEventPhase::Move,
1594 vec![contact2.clone()],
1595 )]),
1596 event_time2,
1597 &descriptor,
1598 ))
1599 .unwrap();
1600
1601 let handle_event_fut = fixtures
1603 .touch_handler
1604 .clone()
1605 .handle_input_events(vec![input_event1.into(), input_event2.into()]);
1606
1607 let expected_event1 = create_touch_pointer_sample_event(
1609 pointerinjector::EventPhase::Add,
1610 &contact1,
1611 Position { x: 20.0, y: 40.0 },
1612 event_time1,
1613 );
1614 let expected_event2 = create_touch_pointer_sample_event(
1615 pointerinjector::EventPhase::Change,
1616 &contact2,
1617 Position { x: 25.0, y: 45.0 },
1618 event_time2,
1619 );
1620
1621 let device_fut = async move {
1622 match injector_device_request_stream.next().await {
1623 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1624 assert_eq!(events.len(), 2);
1625 assert_eq!(events[0].timestamp, expected_event1.timestamp);
1626 assert_eq!(events[0].data, expected_event1.data);
1627 assert_eq!(events[1].timestamp, expected_event2.timestamp);
1628 assert_eq!(events[1].data, expected_event2.data);
1629 }
1630 other => panic!("Received unexpected value: {:?}", other),
1631 }
1632 };
1633
1634 let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1635
1636 assert_matches!(
1638 handle_result.as_slice(),
1639 [
1640 input_device::InputEvent { handled: input_device::Handled::Yes, .. },
1641 input_device::InputEvent { handled: input_device::Handled::Yes, .. }
1642 ]
1643 );
1644 }
1645}