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)
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 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 _server_task: fasync::Task<()>,
848 }
849
850 fn spawn_device_listener_registry_server(
851 handler: Rc<TouchInjectorHandler>,
852 ) -> (fidl_ui_policy::DeviceListenerRegistryProxy, fasync::Task<()>) {
853 let (device_listener_proxy, mut device_listener_stream) =
854 fidl::endpoints::create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>(
855 );
856
857 let task = fasync::Task::local(async move {
858 loop {
859 match device_listener_stream.try_next().await {
860 Ok(Some(
861 fidl_ui_policy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
862 listener,
863 responder,
864 },
865 )) => {
866 handler.register_listener_proxy(listener.into_proxy()).await;
867 let _ = responder.send();
868 }
869 Ok(Some(_)) => {
870 panic!("Unexpected registration");
871 }
872 Ok(None) => {
873 break;
874 }
875 Err(e) => {
876 panic!("Error handling device listener registry request stream: {}", e);
877 }
878 }
879 }
880 });
881
882 (device_listener_proxy, task)
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, server_task) =
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 _server_task: server_task,
938 }
939 }
940 }
941
942 fn get_touchpad_device_descriptor() -> input_device::InputDeviceDescriptor {
944 input_device::InputDeviceDescriptor::Touchpad(touch_binding::TouchpadDeviceDescriptor {
945 device_id: 1,
946 contacts: vec![touch_binding::ContactDeviceDescriptor {
947 x_range: fidl_input_report::Range { min: 0, max: 100 },
948 y_range: fidl_input_report::Range { min: 0, max: 100 },
949 x_unit: fidl_input_report::Unit {
950 type_: fidl_input_report::UnitType::Meters,
951 exponent: -6,
952 },
953 y_unit: fidl_input_report::Unit {
954 type_: fidl_input_report::UnitType::Meters,
955 exponent: -6,
956 },
957 pressure_range: None,
958 width_range: None,
959 height_range: None,
960 }],
961 })
962 }
963
964 async fn handle_device_request_stream(
967 mut injector_stream: pointerinjector::DeviceRequestStream,
968 expected_event: pointerinjector::Event,
969 ) {
970 match injector_stream.next().await {
971 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
972 panic!("DeviceRequest::Inject is deprecated.");
973 }
974 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
975 assert_eq!(events.len(), 1);
976 assert_eq!(events[0].timestamp, expected_event.timestamp);
977 assert_eq!(events[0].data, expected_event.data);
978 }
979 Some(Err(e)) => panic!("FIDL error {}", e),
980 None => panic!("Expected another event."),
981 }
982 }
983
984 fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
985 pointerinjector::Viewport {
986 extents: Some([[min, min], [max, max]]),
987 viewport_to_context_transform: None,
988 ..Default::default()
989 }
990 }
991
992 fn create_viewport_next(min: f32, max: f32) -> pointerinjector_next::Viewport {
993 pointerinjector_next::Viewport {
994 extents: Some([[min, min], [max, max]]),
995 viewport_to_context_transform: None,
996 ..Default::default()
997 }
998 }
999
1000 #[fuchsia::test]
1001 async fn events_with_pressed_buttons_are_sent_to_listener() {
1002 let fixtures = TestFixtures::new().await;
1003 let (listener, mut listener_stream) =
1004 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1005 fixtures
1006 .device_listener_proxy
1007 .register_touch_buttons_listener(listener)
1008 .await
1009 .expect("Failed to register listener.");
1010
1011 let descriptor = get_touch_screen_device_descriptor();
1012 let event_time = zx::MonotonicInstant::get();
1013 let input_event = create_touch_screen_event(SortedVecMap::new(), event_time, &descriptor);
1014
1015 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1016
1017 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
1018 event_time: Some(event_time),
1019 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1020 ..Default::default()
1021 };
1022
1023 assert_matches!(
1024 listener_stream.next().await,
1025 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1026 event,
1027 responder,
1028 })) => {
1029 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1030 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1031 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1032 assert!(event.trace_flow_id.is_some());
1033 let _ = responder.send();
1034 }
1035 );
1036 }
1037
1038 #[fuchsia::test]
1039 async fn events_with_contacts_are_not_sent_to_listener() {
1040 let fixtures = TestFixtures::new().await;
1041 let (listener, mut listener_stream) =
1042 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1043 fixtures
1044 .device_listener_proxy
1045 .register_touch_buttons_listener(listener)
1046 .await
1047 .expect("Failed to register listener.");
1048
1049 let descriptor = get_touch_screen_device_descriptor();
1050 let event_time = zx::MonotonicInstant::get();
1051 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1052 let input_event = create_touch_screen_event(
1053 SortedVecMap::from_iter(vec![(
1054 fidl_ui_input::PointerEventPhase::Add,
1055 vec![contact.clone()],
1056 )]),
1057 event_time,
1058 &descriptor,
1059 );
1060
1061 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1062
1063 assert!(listener_stream.next().now_or_never().is_none());
1064 }
1065
1066 #[fuchsia::test]
1067 async fn multiple_listeners_receive_pressed_button_events() {
1068 let fixtures = TestFixtures::new().await;
1069 let (first_listener, mut first_listener_stream) =
1070 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1071 let (second_listener, mut second_listener_stream) =
1072 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
1073 fixtures
1074 .device_listener_proxy
1075 .register_touch_buttons_listener(first_listener)
1076 .await
1077 .expect("Failed to register listener.");
1078 fixtures
1079 .device_listener_proxy
1080 .register_touch_buttons_listener(second_listener)
1081 .await
1082 .expect("Failed to register listener.");
1083
1084 let descriptor = get_touch_screen_device_descriptor();
1085 let event_time = zx::MonotonicInstant::get();
1086 let input_event = create_touch_screen_event(SortedVecMap::new(), event_time, &descriptor);
1087
1088 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1089
1090 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
1091 event_time: Some(event_time),
1092 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1093 ..Default::default()
1094 };
1095
1096 assert_matches!(
1097 first_listener_stream.next().await,
1098 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1099 event,
1100 responder,
1101 })) => {
1102 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1103 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1104 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1105 assert!(event.trace_flow_id.is_some());
1106 let _ = responder.send();
1107 }
1108 );
1109 assert_matches!(
1110 second_listener_stream.next().await,
1111 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1112 event,
1113 responder,
1114 })) => {
1115 assert_eq!(event.event_time, expected_touch_buttons_event.event_time);
1116 assert_eq!(event.device_info, expected_touch_buttons_event.device_info);
1117 assert_eq!(event.pressed_buttons, expected_touch_buttons_event.pressed_buttons);
1118 assert!(event.trace_flow_id.is_some());
1119 let _ = responder.send();
1120 }
1121 );
1122 }
1123
1124 #[fuchsia::test]
1127 async fn receives_viewport_updates() {
1128 let mut fixtures = TestFixtures::new().await;
1129
1130 let (injector_device_proxy, mut injector_device_request_stream) =
1132 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1133 fixtures
1134 .touch_handler
1135 .mutable_state
1136 .borrow_mut()
1137 .injectors
1138 .insert(1, injector_device_proxy);
1139
1140 {
1142 let _watch_viewport_task =
1144 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1145
1146 match fixtures.configuration_request_stream.next().await {
1148 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1149 responder, ..
1150 })) => {
1151 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1152 }
1153 other => panic!("Received unexpected value: {:?}", other),
1154 };
1155
1156 match injector_device_request_stream.next().await {
1158 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1159 panic!("DeviceRequest::Inject is deprecated.");
1160 }
1161 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1162 assert_eq!(events.len(), 1);
1163 assert!(events[0].data.is_some());
1164 assert_eq!(
1165 events[0].data,
1166 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1167 );
1168 }
1169 other => panic!("Received unexpected value: {:?}", other),
1170 }
1171
1172 match fixtures.configuration_request_stream.next().await {
1175 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1176 responder, ..
1177 })) => {
1178 responder
1179 .send(&create_viewport(100.0, 200.0))
1180 .expect("Failed to send viewport.");
1181 }
1182 other => panic!("Received unexpected value: {:?}", other),
1183 };
1184
1185 match injector_device_request_stream.next().await {
1187 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1188 panic!("DeviceRequest::Inject is deprecated.");
1189 }
1190 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1191 assert_eq!(events.len(), 1);
1192 assert!(events[0].data.is_some());
1193 assert_eq!(
1194 events[0].data,
1195 Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
1196 );
1197 }
1198 other => panic!("Received unexpected value: {:?}", other),
1199 }
1200 }
1201
1202 let expected_viewport = create_viewport_next(100.0, 200.0);
1204 assert_eq!(fixtures.touch_handler.mutable_state.borrow().viewport, Some(expected_viewport));
1205 }
1206
1207 #[fuchsia::test]
1209 async fn add_contact_drops_without_viewport() {
1210 let mut fixtures = TestFixtures::new().await;
1211
1212 let event_time = zx::MonotonicInstant::get();
1214 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1215 let descriptor = get_touch_screen_device_descriptor();
1216 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1217 SortedVecMap::from_iter(vec![(
1218 fidl_ui_input::PointerEventPhase::Add,
1219 vec![contact.clone()],
1220 )]),
1221 event_time,
1222 &descriptor,
1223 ))
1224 .unwrap();
1225
1226 fixtures.touch_handler.mutable_state.borrow_mut().viewport = None;
1228
1229 let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]).await;
1231
1232 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1234 }
1235
1236 #[fuchsia::test]
1238 async fn add_contact_succeeds_with_viewport() {
1239 let mut fixtures = TestFixtures::new().await;
1240
1241 let (injector_device_proxy, mut injector_device_request_stream) =
1243 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1244 fixtures
1245 .touch_handler
1246 .mutable_state
1247 .borrow_mut()
1248 .injectors
1249 .insert(1, injector_device_proxy);
1250
1251 let _watch_viewport_task =
1253 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1254
1255 match fixtures.configuration_request_stream.next().await {
1257 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1258 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1259 }
1260 other => panic!("Received unexpected value: {:?}", other),
1261 };
1262
1263 match injector_device_request_stream.next().await {
1265 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1266 panic!("DeviceRequest::Inject is deprecated.");
1267 }
1268 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1269 assert_eq!(events.len(), 1);
1270 assert!(events[0].data.is_some());
1271 assert_eq!(
1272 events[0].data,
1273 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1274 );
1275 }
1276 other => panic!("Received unexpected value: {:?}", other),
1277 }
1278
1279 let event_time = zx::MonotonicInstant::get();
1281 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1282 let descriptor = get_touch_screen_device_descriptor();
1283 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1284 SortedVecMap::from_iter(vec![(
1285 fidl_ui_input::PointerEventPhase::Add,
1286 vec![contact.clone()],
1287 )]),
1288 event_time,
1289 &descriptor,
1290 ))
1291 .unwrap();
1292
1293 let handle_event_fut =
1295 fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1296
1297 let expected_event = create_touch_pointer_sample_event(
1299 pointerinjector::EventPhase::Add,
1300 &contact,
1301 Position { x: 20.0, y: 40.0 },
1302 event_time,
1303 );
1304
1305 let device_fut =
1308 handle_device_request_stream(injector_device_request_stream, expected_event);
1309 let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1310
1311 assert_matches!(
1313 handle_result.as_slice(),
1314 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1315 );
1316 }
1317
1318 #[fuchsia::test]
1320 async fn add_touchpad_contact_with_viewport() {
1321 let mut fixtures = TestFixtures::new().await;
1322
1323 let (injector_device_proxy, mut injector_device_request_stream) =
1325 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1326 fixtures
1327 .touch_handler
1328 .mutable_state
1329 .borrow_mut()
1330 .injectors
1331 .insert(1, injector_device_proxy);
1332
1333 let _watch_viewport_task =
1335 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1336
1337 match fixtures.configuration_request_stream.next().await {
1339 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1340 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1341 }
1342 other => panic!("Received unexpected value: {:?}", other),
1343 };
1344
1345 match injector_device_request_stream.next().await {
1347 Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1348 panic!("DeviceRequest::Inject is deprecated.");
1349 }
1350 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1351 assert_eq!(events.len(), 1);
1352 assert!(events[0].data.is_some());
1353 assert_eq!(
1354 events[0].data,
1355 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1356 );
1357 }
1358 other => panic!("Received unexpected value: {:?}", other),
1359 }
1360
1361 let event_time = zx::MonotonicInstant::get();
1363 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1364 let descriptor = get_touchpad_device_descriptor();
1365 let input_event = input_device::UnhandledInputEvent::try_from(create_touchpad_event(
1366 vec![contact.clone()],
1367 SortedVecSet::new(),
1368 event_time,
1369 &descriptor,
1370 ))
1371 .unwrap();
1372
1373 let handle_event_fut =
1375 fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1376
1377 let handle_result = handle_event_fut.await;
1378
1379 assert_matches!(
1381 handle_result.as_slice(),
1382 [input_device::InputEvent { handled: input_device::Handled::No, .. }]
1383 );
1384
1385 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1387 }
1388
1389 #[fuchsia::test(allow_stalls = false)]
1390 async fn touch_injector_handler_initialized_with_inspect_node() {
1391 let fixtures = TestFixtures::new().await;
1392 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1393 test_node: {
1394 touch_injector_handler: {
1395 events_received_count: 0u64,
1396 events_handled_count: 0u64,
1397 last_received_timestamp_ns: 0u64,
1398 "fuchsia.inspect.Health": {
1399 status: "STARTING_UP",
1400 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1403 },
1404 }
1405 }
1406 });
1407 }
1408
1409 #[fuchsia::test(allow_stalls = false)]
1410 async fn touch_injector_handler_inspect_counts_events() {
1411 let fixtures = TestFixtures::new().await;
1412
1413 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1414 let descriptor = get_touch_screen_device_descriptor();
1415 let event_time1 = zx::MonotonicInstant::get();
1416 let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1417 let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1418
1419 let input_events = vec![
1420 create_touch_screen_event(
1421 SortedVecMap::from_iter(vec![(
1422 fidl_ui_input::PointerEventPhase::Add,
1423 vec![contact.clone()],
1424 )]),
1425 event_time1,
1426 &descriptor,
1427 ),
1428 create_touch_screen_event(
1429 SortedVecMap::from_iter(vec![(
1430 fidl_ui_input::PointerEventPhase::Move,
1431 vec![contact.clone()],
1432 )]),
1433 event_time2,
1434 &descriptor,
1435 ),
1436 create_fake_input_event(event_time2),
1438 create_touch_screen_event_with_handled(
1440 SortedVecMap::from_iter(vec![(
1441 fidl_ui_input::PointerEventPhase::Move,
1442 vec![contact.clone()],
1443 )]),
1444 event_time2,
1445 &descriptor,
1446 input_device::Handled::Yes,
1447 ),
1448 create_touch_screen_event(
1449 SortedVecMap::from_iter(vec![(
1450 fidl_ui_input::PointerEventPhase::Remove,
1451 vec![contact.clone()],
1452 )]),
1453 event_time3,
1454 &descriptor,
1455 ),
1456 ];
1457
1458 for input_event in input_events {
1459 fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1460 }
1461
1462 let last_received_event_time: u64 = event_time3.into_nanos().try_into().unwrap();
1463
1464 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1465 test_node: {
1466 touch_injector_handler: {
1467 events_received_count: 3u64,
1468 events_handled_count: 3u64,
1469 last_received_timestamp_ns: last_received_event_time,
1470 "fuchsia.inspect.Health": {
1471 status: "STARTING_UP",
1472 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1475 },
1476 }
1477 }
1478 });
1479 }
1480
1481 #[fuchsia::test]
1482 async fn clone_event_with_lease_duplicates_lease() {
1483 let (event_pair, _) = fidl::EventPair::create();
1484 let event = fidl_ui_input::TouchButtonsEvent {
1485 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1486 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1487 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1488 wake_lease: Some(event_pair),
1489 ..Default::default()
1490 };
1491 let cloned_event = TouchInjectorHandler::clone_event(&event);
1492 assert_eq!(event.event_time, cloned_event.event_time);
1493 assert_eq!(event.device_info, cloned_event.device_info);
1494 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1495 assert!(event.wake_lease.is_some());
1496 assert!(cloned_event.wake_lease.is_some());
1497 assert_ne!(
1498 event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
1499 cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
1500 );
1501 }
1502
1503 #[fuchsia::test]
1504 async fn clone_event_without_lease_has_no_lease() {
1505 let event = fidl_ui_input::TouchButtonsEvent {
1506 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1507 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1508 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1509 wake_lease: None,
1510 ..Default::default()
1511 };
1512 let cloned_event = TouchInjectorHandler::clone_event(&event);
1513 assert_eq!(event.event_time, cloned_event.event_time);
1514 assert_eq!(event.device_info, cloned_event.device_info);
1515 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1516 assert!(event.wake_lease.is_none());
1517 assert!(cloned_event.wake_lease.is_none());
1518 }
1519
1520 #[fuchsia::test]
1521 async fn clone_event_creates_new_trace_id() {
1522 let event = fidl_ui_input::TouchButtonsEvent {
1523 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1524 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1525 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1526 trace_flow_id: Some(123),
1527 ..Default::default()
1528 };
1529 let cloned_event = TouchInjectorHandler::clone_event(&event);
1530 assert_eq!(event.event_time, cloned_event.event_time);
1531 assert_eq!(event.device_info, cloned_event.device_info);
1532 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1533 assert!(cloned_event.trace_flow_id.is_some());
1534 assert_ne!(event.trace_flow_id, cloned_event.trace_flow_id);
1535 }
1536
1537 #[fuchsia::test]
1538 async fn handle_input_events_batches_events() {
1539 let mut fixtures = TestFixtures::new().await;
1540
1541 let (injector_device_proxy, mut injector_device_request_stream) =
1543 next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
1544 fixtures
1545 .touch_handler
1546 .mutable_state
1547 .borrow_mut()
1548 .injectors
1549 .insert(1, injector_device_proxy);
1550
1551 let _watch_viewport_task =
1553 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1554
1555 match fixtures.configuration_request_stream.next().await {
1557 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1558 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1559 }
1560 other => panic!("Received unexpected value: {:?}", other),
1561 };
1562
1563 match injector_device_request_stream.next().await {
1565 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1566 assert_eq!(events.len(), 1);
1567 assert!(events[0].data.is_some());
1568 assert_eq!(
1569 events[0].data,
1570 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1571 );
1572 }
1573 other => panic!("Received unexpected value: {:?}", other),
1574 }
1575
1576 let event_time1 = zx::MonotonicInstant::get();
1578 let contact1 = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1579 let descriptor = get_touch_screen_device_descriptor();
1580 let input_event1 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1581 SortedVecMap::from_iter(vec![(
1582 fidl_ui_input::PointerEventPhase::Add,
1583 vec![contact1.clone()],
1584 )]),
1585 event_time1,
1586 &descriptor,
1587 ))
1588 .unwrap();
1589
1590 let event_time2 = event_time1 + zx::MonotonicDuration::from_millis(10);
1591 let contact2 = create_touch_contact(TOUCH_ID, Position { x: 25.0, y: 45.0 });
1592 let input_event2 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1593 SortedVecMap::from_iter(vec![(
1594 fidl_ui_input::PointerEventPhase::Move,
1595 vec![contact2.clone()],
1596 )]),
1597 event_time2,
1598 &descriptor,
1599 ))
1600 .unwrap();
1601
1602 let handle_event_fut = fixtures
1604 .touch_handler
1605 .clone()
1606 .handle_input_events(vec![input_event1.into(), input_event2.into()]);
1607
1608 let expected_event1 = create_touch_pointer_sample_event(
1610 pointerinjector::EventPhase::Add,
1611 &contact1,
1612 Position { x: 20.0, y: 40.0 },
1613 event_time1,
1614 );
1615 let expected_event2 = create_touch_pointer_sample_event(
1616 pointerinjector::EventPhase::Change,
1617 &contact2,
1618 Position { x: 25.0, y: 45.0 },
1619 event_time2,
1620 );
1621
1622 let device_fut = async move {
1623 match injector_device_request_stream.next().await {
1624 Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1625 assert_eq!(events.len(), 2);
1626 assert_eq!(events[0].timestamp, expected_event1.timestamp);
1627 assert_eq!(events[0].data, expected_event1.data);
1628 assert_eq!(events[1].timestamp, expected_event2.timestamp);
1629 assert_eq!(events[1].data, expected_event2.data);
1630 }
1631 other => panic!("Received unexpected value: {:?}", other),
1632 }
1633 };
1634
1635 let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1636
1637 assert_matches!(
1639 handle_result.as_slice(),
1640 [
1641 input_device::InputEvent { handled: input_device::Handled::Yes, .. },
1642 input_device::InputEvent { handled: input_device::Handled::Yes, .. }
1643 ]
1644 );
1645 }
1646}