1#![warn(clippy::await_holding_refcell_ref)]
6use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
7use crate::utils::{Position, Size};
8use crate::{input_device, metrics, touch_binding};
9use anyhow::{Context, Error, Result};
10use async_trait::async_trait;
11use async_utils::hanging_get::client::HangingGetStream;
12use fidl::endpoints::{Proxy, create_proxy};
13use fidl::{AsHandleRef, HandleBased};
14use fuchsia_component::client::connect_to_protocol;
15use fuchsia_inspect::health::Reporter;
16use futures::channel::mpsc;
17use futures::stream::StreamExt;
18use metrics_registry::*;
19use std::cell::RefCell;
20use std::collections::HashMap;
21use std::rc::Rc;
22use {
23 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
24 fidl_fuchsia_ui_pointerinjector as pointerinjector,
25 fidl_fuchsia_ui_pointerinjector_configuration as pointerinjector_config,
26 fidl_fuchsia_ui_policy as fidl_ui_policy, fuchsia_async as fasync,
27};
28
29pub struct TouchInjectorHandler {
32 mutable_state: RefCell<MutableState>,
34
35 context_view_ref: fidl_fuchsia_ui_views::ViewRef,
38
39 target_view_ref: fidl_fuchsia_ui_views::ViewRef,
42
43 display_size: Size,
47
48 injector_registry_proxy: pointerinjector::RegistryProxy,
50
51 configuration_proxy: pointerinjector_config::SetupProxy,
53
54 pub inspect_status: InputHandlerStatus,
56
57 metrics_logger: metrics::MetricsLogger,
59}
60
61#[derive(Debug)]
62struct MutableState {
63 viewport: Option<pointerinjector::Viewport>,
66
67 injectors: HashMap<u32, pointerinjector::DeviceProxy>,
69
70 pub listeners: HashMap<u32, fidl_ui_policy::TouchButtonsListenerProxy>,
72
73 pub last_button_event: Option<fidl_ui_input::TouchButtonsEvent>,
76
77 pub send_event_task_tracker: LocalTaskTracker,
78}
79
80#[async_trait(?Send)]
81impl UnhandledInputHandler for TouchInjectorHandler {
82 async fn handle_unhandled_input_event(
83 self: Rc<Self>,
84 mut unhandled_input_event: input_device::UnhandledInputEvent,
85 ) -> Vec<input_device::InputEvent> {
86 fuchsia_trace::duration!(c"input", c"touch_injector_handler");
87 match unhandled_input_event {
88 input_device::UnhandledInputEvent {
89 device_event: input_device::InputDeviceEvent::TouchScreen(ref mut touch_event),
90 device_descriptor:
91 input_device::InputDeviceDescriptor::TouchScreen(ref touch_device_descriptor),
92 event_time,
93 trace_id,
94 } => {
95 self.inspect_status.count_received_event(&event_time);
96 fuchsia_trace::duration!(c"input", c"touch_injector_handler[processing]");
97 if let Some(trace_id) = trace_id {
98 fuchsia_trace::flow_end!(c"input", c"event_in_input_pipeline", trace_id.into());
99 }
100 if touch_event.injector_contacts.values().all(|vec| vec.is_empty()) {
101 let mut touch_buttons_event = Self::create_touch_buttons_event(
102 touch_event,
103 event_time,
104 &touch_device_descriptor,
105 );
106
107 self.send_event_to_listeners(&touch_buttons_event).await;
109
110 std::mem::drop(touch_buttons_event.wake_lease.take());
112 self.mutable_state.borrow_mut().last_button_event = Some(touch_buttons_event);
113 } else if touch_event.pressed_buttons.is_empty() {
114 if let Err(e) = self.ensure_injector_registered(&touch_device_descriptor).await
116 {
117 self.metrics_logger.log_error(
118 InputPipelineErrorMetricDimensionEvent::TouchInjectorEnsureInjectorRegisteredFailed,
119 std::format!("ensure_injector_registered failed: {}", e));
120 }
121
122 if let Err(e) =
124 self.send_event_to_scenic(touch_event, &touch_device_descriptor, event_time)
125 {
126 self.metrics_logger.log_error(
127 InputPipelineErrorMetricDimensionEvent::TouchInjectorSendEventToScenicFailed,
128 std::format!("send_event_to_scenic failed: {}", e));
129 }
130 }
131
132 self.inspect_status.count_handled_event();
134 vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
135 }
136 _ => vec![input_device::InputEvent::from(unhandled_input_event)],
137 }
138 }
139
140 fn set_handler_healthy(self: std::rc::Rc<Self>) {
141 self.inspect_status.health_node.borrow_mut().set_ok();
142 }
143
144 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
145 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
146 }
147}
148
149impl TouchInjectorHandler {
150 pub async fn new(
162 display_size: Size,
163 input_handlers_node: &fuchsia_inspect::Node,
164 metrics_logger: metrics::MetricsLogger,
165 ) -> Result<Rc<Self>, Error> {
166 let configuration_proxy = connect_to_protocol::<pointerinjector_config::SetupMarker>()?;
167 let injector_registry_proxy = connect_to_protocol::<pointerinjector::RegistryMarker>()?;
168
169 Self::new_handler(
170 configuration_proxy,
171 injector_registry_proxy,
172 display_size,
173 input_handlers_node,
174 metrics_logger,
175 )
176 .await
177 }
178
179 pub async fn new_with_config_proxy(
194 configuration_proxy: pointerinjector_config::SetupProxy,
195 display_size: Size,
196 input_handlers_node: &fuchsia_inspect::Node,
197 metrics_logger: metrics::MetricsLogger,
198 ) -> Result<Rc<Self>, Error> {
199 let injector_registry_proxy = connect_to_protocol::<pointerinjector::RegistryMarker>()?;
200 Self::new_handler(
201 configuration_proxy,
202 injector_registry_proxy,
203 display_size,
204 input_handlers_node,
205 metrics_logger,
206 )
207 .await
208 }
209
210 async fn new_handler(
226 configuration_proxy: pointerinjector_config::SetupProxy,
227 injector_registry_proxy: pointerinjector::RegistryProxy,
228 display_size: Size,
229 input_handlers_node: &fuchsia_inspect::Node,
230 metrics_logger: metrics::MetricsLogger,
231 ) -> Result<Rc<Self>, Error> {
232 let (context_view_ref, target_view_ref) = configuration_proxy.get_view_refs().await?;
234
235 let inspect_status = InputHandlerStatus::new(
236 input_handlers_node,
237 "touch_injector_handler",
238 false,
239 );
240 let handler = Rc::new(Self {
241 mutable_state: RefCell::new(MutableState {
242 viewport: None,
243 injectors: HashMap::new(),
244 listeners: HashMap::new(),
245 last_button_event: None,
246 send_event_task_tracker: LocalTaskTracker::new(),
247 }),
248 context_view_ref,
249 target_view_ref,
250 display_size,
251 injector_registry_proxy,
252 configuration_proxy,
253 inspect_status,
254 metrics_logger,
255 });
256
257 Ok(handler)
258 }
259
260 fn clone_event(event: &fidl_ui_input::TouchButtonsEvent) -> fidl_ui_input::TouchButtonsEvent {
261 fidl_ui_input::TouchButtonsEvent {
262 event_time: event.event_time,
263 device_info: event.device_info.clone(),
264 pressed_buttons: event.pressed_buttons.clone(),
265 wake_lease: event.wake_lease.as_ref().map(|lease| {
266 fidl::EventPair::from_handle(
267 lease
268 .as_handle_ref()
269 .duplicate(zx::Rights::SAME_RIGHTS)
270 .expect("failed to duplicate event pair")
271 .into_handle(),
272 )
273 }),
274 ..Default::default()
275 }
276 }
277
278 async fn ensure_injector_registered(
284 self: &Rc<Self>,
285 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
286 ) -> Result<(), anyhow::Error> {
287 if self.mutable_state.borrow().injectors.contains_key(&touch_descriptor.device_id) {
288 return Ok(());
289 }
290
291 let (device_proxy, device_server) = create_proxy::<pointerinjector::DeviceMarker>();
293 let context = fuchsia_scenic::duplicate_view_ref(&self.context_view_ref)
294 .context("Failed to duplicate context view ref.")?;
295 let target = fuchsia_scenic::duplicate_view_ref(&self.target_view_ref)
296 .context("Failed to duplicate target view ref.")?;
297 let viewport = self.mutable_state.borrow().viewport.clone();
298 if viewport.is_none() {
299 return Err(anyhow::format_err!(
302 "Received a touch event without a viewport to inject into."
303 ));
304 }
305 let config = pointerinjector::Config {
306 device_id: Some(touch_descriptor.device_id),
307 device_type: Some(pointerinjector::DeviceType::Touch),
308 context: Some(pointerinjector::Context::View(context)),
309 target: Some(pointerinjector::Target::View(target)),
310 viewport,
311 dispatch_policy: Some(pointerinjector::DispatchPolicy::TopHitAndAncestorsInTarget),
312 scroll_v_range: None,
313 scroll_h_range: None,
314 buttons: None,
315 ..Default::default()
316 };
317
318 self.mutable_state.borrow_mut().injectors.insert(touch_descriptor.device_id, device_proxy);
320
321 self.injector_registry_proxy
323 .register(config, device_server)
324 .await
325 .context("Failed to register injector.")?;
326 log::info!("Registered injector with device id {:?}", touch_descriptor.device_id);
327
328 Ok(())
329 }
330
331 fn send_event_to_scenic(
338 &self,
339 touch_event: &mut touch_binding::TouchScreenEvent,
340 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
341 event_time: zx::MonotonicInstant,
342 ) -> Result<(), anyhow::Error> {
343 let ordered_phases = vec![
345 pointerinjector::EventPhase::Add,
346 pointerinjector::EventPhase::Change,
347 pointerinjector::EventPhase::Remove,
348 ];
349
350 fuchsia_trace::duration_begin!(c"input", c"touch-inject-into-scenic");
355
356 let mut events: Vec<pointerinjector::Event> = vec![];
357 for phase in ordered_phases {
358 let contacts: Vec<touch_binding::TouchContact> = touch_event
359 .injector_contacts
360 .get(&phase)
361 .map_or(vec![], |contacts| contacts.to_owned());
362 let new_events = contacts.into_iter().map(|contact| {
363 Self::create_pointer_sample_event(
364 phase,
365 &contact,
366 touch_descriptor,
367 &self.display_size,
368 event_time,
369 touch_event.wake_lease.take(),
370 )
371 });
372 events.extend(new_events);
373 }
374
375 let injector =
376 self.mutable_state.borrow().injectors.get(&touch_descriptor.device_id).cloned();
377 if let Some(injector) = injector {
378 fuchsia_trace::duration_end!(c"input", c"touch-inject-into-scenic");
380 let _ = injector.inject(events);
381 Ok(())
382 } else {
383 fuchsia_trace::duration_end!(c"input", c"touch-inject-into-scenic");
384 Err(anyhow::format_err!(
385 "No injector found for touch device {}.",
386 touch_descriptor.device_id
387 ))
388 }
389 }
390
391 fn create_pointer_sample_event(
401 phase: pointerinjector::EventPhase,
402 contact: &touch_binding::TouchContact,
403 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
404 display_size: &Size,
405 event_time: zx::MonotonicInstant,
406 wake_lease: Option<zx::EventPair>,
407 ) -> pointerinjector::Event {
408 let position =
409 Self::display_coordinate_from_contact(&contact, &touch_descriptor, display_size);
410 let pointer_sample = pointerinjector::PointerSample {
411 pointer_id: Some(contact.id),
412 phase: Some(phase),
413 position_in_viewport: Some([position.x, position.y]),
414 scroll_v: None,
415 scroll_h: None,
416 pressed_buttons: None,
417 ..Default::default()
418 };
419 let data = pointerinjector::Data::PointerSample(pointer_sample);
420
421 let trace_flow_id = fuchsia_trace::Id::random();
422 let event = pointerinjector::Event {
423 timestamp: Some(event_time.into_nanos()),
424 data: Some(data),
425 trace_flow_id: Some(trace_flow_id.into()),
426 wake_lease,
427 ..Default::default()
428 };
429
430 fuchsia_trace::flow_begin!(c"input", c"dispatch_event_to_scenic", trace_flow_id);
431
432 event
433 }
434
435 fn display_coordinate_from_contact(
449 contact: &touch_binding::TouchContact,
450 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
451 display_size: &Size,
452 ) -> Position {
453 if let Some(contact_descriptor) = touch_descriptor.contacts.first() {
454 let x_range: f32 =
456 contact_descriptor.x_range.max as f32 - contact_descriptor.x_range.min as f32;
457 let x_wrt_range: f32 = contact.position.x - contact_descriptor.x_range.min as f32;
458 let x: f32 = (display_size.width * x_wrt_range) / x_range;
459
460 let y_range: f32 =
462 contact_descriptor.y_range.max as f32 - contact_descriptor.y_range.min as f32;
463 let y_wrt_range: f32 = contact.position.y - contact_descriptor.y_range.min as f32;
464 let y: f32 = (display_size.height * y_wrt_range) / y_range;
465
466 Position { x, y }
467 } else {
468 return contact.position;
469 }
470 }
471
472 pub async fn watch_viewport(self: Rc<Self>) {
474 let configuration_proxy = self.configuration_proxy.clone();
475 let mut viewport_stream = HangingGetStream::new(
476 configuration_proxy,
477 pointerinjector_config::SetupProxy::watch_viewport,
478 );
479 loop {
480 match viewport_stream.next().await {
481 Some(Ok(new_viewport)) => {
482 self.mutable_state.borrow_mut().viewport = Some(new_viewport.clone());
484
485 let injectors: Vec<pointerinjector::DeviceProxy> =
487 self.mutable_state.borrow_mut().injectors.values().cloned().collect();
488 for injector in injectors {
489 let events = vec![pointerinjector::Event {
490 timestamp: Some(fuchsia_async::MonotonicInstant::now().into_nanos()),
491 data: Some(pointerinjector::Data::Viewport(new_viewport.clone())),
492 trace_flow_id: Some(fuchsia_trace::Id::random().into()),
493 ..Default::default()
494 }];
495 injector.inject(events).await.expect("Failed to inject updated viewport.");
496 }
497 }
498 Some(Err(e)) => {
499 self.metrics_logger.log_error(
500 InputPipelineErrorMetricDimensionEvent::TouchInjectorErrorWhileReadingViewportUpdate,
501 std::format!("Error while reading viewport update: {}", e));
502 return;
503 }
504 None => {
505 self.metrics_logger.log_error(
506 InputPipelineErrorMetricDimensionEvent::TouchInjectorViewportUpdateStreamTerminatedUnexpectedly,
507 "Viewport update stream terminated unexpectedly");
508 return;
509 }
510 }
511 }
512 }
513
514 fn create_touch_buttons_event(
521 event: &mut touch_binding::TouchScreenEvent,
522 event_time: zx::MonotonicInstant,
523 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
524 ) -> fidl_ui_input::TouchButtonsEvent {
525 let pressed_buttons = match event.pressed_buttons.len() {
526 0 => None,
527 _ => Some(
528 event
529 .pressed_buttons
530 .clone()
531 .into_iter()
532 .map(|button| match button {
533 fidl_input_report::TouchButton::Palm => fidl_ui_input::TouchButton::Palm,
534 fidl_input_report::TouchButton::__SourceBreaking { unknown_ordinal: n } => {
535 fidl_ui_input::TouchButton::__SourceBreaking {
536 unknown_ordinal: n as u32,
537 }
538 }
539 })
540 .collect::<Vec<_>>(),
541 ),
542 };
543 fidl_ui_input::TouchButtonsEvent {
544 event_time: Some(event_time),
545 device_info: Some(fidl_ui_input::TouchDeviceInfo {
546 id: Some(touch_descriptor.device_id),
547 ..Default::default()
548 }),
549 pressed_buttons,
550 wake_lease: event.wake_lease.take(),
551 ..Default::default()
552 }
553 }
554
555 async fn send_event_to_listeners(self: &Rc<Self>, event: &fidl_ui_input::TouchButtonsEvent) {
560 let tracker = &self.mutable_state.borrow().send_event_task_tracker;
561
562 for (handle, listener) in &self.mutable_state.borrow().listeners {
563 let weak_handler = Rc::downgrade(&self);
564 let listener_clone = listener.clone();
565 let handle_clone = handle.clone();
566 let event_to_send = Self::clone_event(event);
567 let fut = async move {
568 match listener_clone.on_event(event_to_send).await {
569 Ok(_) => {}
570 Err(e) => {
571 if let Some(handler) = weak_handler.upgrade() {
572 handler.mutable_state.borrow_mut().listeners.remove(&handle_clone);
573 log::info!(
574 "Unregistering listener; unable to send TouchButtonsEvent: {:?}",
575 e
576 )
577 }
578 }
579 }
580 };
581
582 let metrics_logger_clone = self.metrics_logger.clone();
583 tracker.track(metrics_logger_clone, fasync::Task::local(fut));
584 }
585 }
586
587 pub async fn register_listener_proxy(
592 self: &Rc<Self>,
593 proxy: fidl_ui_policy::TouchButtonsListenerProxy,
594 ) {
595 self.mutable_state
596 .borrow_mut()
597 .listeners
598 .insert(proxy.as_channel().raw_handle(), proxy.clone());
599
600 if let Some(event) = &self.mutable_state.borrow().last_button_event {
602 let event_to_send = Self::clone_event(event);
603 let fut = async move {
604 match proxy.on_event(event_to_send).await {
605 Ok(_) => {}
606 Err(e) => {
607 log::info!("Failed to send touch buttons event to listener {:?}", e)
608 }
609 }
610 };
611 let metrics_logger_clone = self.metrics_logger.clone();
612 self.mutable_state
613 .borrow()
614 .send_event_task_tracker
615 .track(metrics_logger_clone, fasync::Task::local(fut));
616 }
617 }
618}
619
620#[derive(Debug)]
623pub struct LocalTaskTracker {
624 sender: mpsc::UnboundedSender<fasync::Task<()>>,
625 _receiver_task: fasync::Task<()>,
626}
627
628impl LocalTaskTracker {
629 pub fn new() -> Self {
630 let (sender, receiver) = mpsc::unbounded();
631 let receiver_task = fasync::Task::local(async move {
632 receiver.for_each_concurrent(None, |task: fasync::Task<()>| task).await
634 });
635
636 Self { sender, _receiver_task: receiver_task }
637 }
638
639 pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: fasync::Task<()>) {
641 match self.sender.unbounded_send(task) {
642 Ok(_) => {}
643 Err(e) => {
647 metrics_logger.log_error(
648 InputPipelineErrorMetricDimensionEvent::TouchFailedToSendTouchScreenEvent,
649 std::format!("Unexpected {e:?} while pushing task"),
650 );
651 }
652 };
653 }
654}
655
656#[cfg(test)]
657mod tests {
658 use super::*;
659 use crate::input_handler::InputHandler;
660 use crate::testing_utilities::{
661 create_fake_input_event, create_touch_contact, create_touch_pointer_sample_event,
662 create_touch_screen_event, create_touch_screen_event_with_handled, create_touchpad_event,
663 get_touch_screen_device_descriptor,
664 };
665 use assert_matches::assert_matches;
666 use futures::{FutureExt, TryStreamExt};
667 use maplit::hashmap;
668 use pretty_assertions::assert_eq;
669 use std::collections::HashSet;
670 use std::convert::TryFrom as _;
671 use std::ops::Add;
672 use {
673 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
674 fidl_fuchsia_ui_policy as fidl_ui_policy, fuchsia_async as fasync,
675 };
676
677 const TOUCH_ID: u32 = 1;
678 const DISPLAY_WIDTH: f32 = 100.0;
679 const DISPLAY_HEIGHT: f32 = 100.0;
680
681 struct TestFixtures {
682 touch_handler: Rc<TouchInjectorHandler>,
683 device_listener_proxy: fidl_ui_policy::DeviceListenerRegistryProxy,
684 injector_registry_request_stream: pointerinjector::RegistryRequestStream,
685 configuration_request_stream: pointerinjector_config::SetupRequestStream,
686 inspector: fuchsia_inspect::Inspector,
687 _test_node: fuchsia_inspect::Node,
688 }
689
690 fn spawn_device_listener_registry_server(
691 handler: Rc<TouchInjectorHandler>,
692 ) -> fidl_ui_policy::DeviceListenerRegistryProxy {
693 let (device_listener_proxy, mut device_listener_stream) =
694 fidl::endpoints::create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>(
695 );
696
697 fasync::Task::local(async move {
698 loop {
699 match device_listener_stream.try_next().await {
700 Ok(Some(
701 fidl_ui_policy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
702 listener,
703 responder,
704 },
705 )) => {
706 handler.register_listener_proxy(listener.into_proxy()).await;
707 let _ = responder.send();
708 }
709 Ok(Some(_)) => {
710 panic!("Unexpected registration");
711 }
712 Ok(None) => {
713 break;
714 }
715 Err(e) => {
716 panic!("Error handling device listener registry request stream: {}", e);
717 }
718 }
719 }
720 })
721 .detach();
722
723 device_listener_proxy
724 }
725
726 impl TestFixtures {
727 async fn new() -> Self {
728 let inspector = fuchsia_inspect::Inspector::default();
729 let test_node = inspector.root().create_child("test_node");
730 let (configuration_proxy, mut configuration_request_stream) =
731 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
732 let (injector_registry_proxy, injector_registry_request_stream) =
733 fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
734
735 let touch_handler_fut = TouchInjectorHandler::new_handler(
736 configuration_proxy,
737 injector_registry_proxy,
738 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
739 &test_node,
740 metrics::MetricsLogger::default(),
741 );
742
743 let handle_initial_request_fut = async {
744 match configuration_request_stream.next().await {
745 Some(Ok(pointerinjector_config::SetupRequest::GetViewRefs {
746 responder,
747 ..
748 })) => {
749 let context = fuchsia_scenic::ViewRefPair::new()
750 .expect("Failed to create viewrefpair.")
751 .view_ref;
752 let target = fuchsia_scenic::ViewRefPair::new()
753 .expect("Failed to create viewrefpair.")
754 .view_ref;
755 let _ = responder.send(context, target);
756 }
757 other => panic!("Expected GetViewRefs request, got {:?}", other),
758 }
759 };
760
761 let (touch_handler_res, _) =
762 futures::future::join(touch_handler_fut, handle_initial_request_fut).await;
763
764 let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
765 let device_listener_proxy =
766 spawn_device_listener_registry_server(touch_handler.clone());
767
768 TestFixtures {
769 touch_handler,
770 device_listener_proxy,
771 injector_registry_request_stream,
772 configuration_request_stream,
773 inspector,
774 _test_node: test_node,
775 }
776 }
777 }
778
779 fn get_touchpad_device_descriptor() -> input_device::InputDeviceDescriptor {
781 input_device::InputDeviceDescriptor::Touchpad(touch_binding::TouchpadDeviceDescriptor {
782 device_id: 1,
783 contacts: vec![touch_binding::ContactDeviceDescriptor {
784 x_range: fidl_input_report::Range { min: 0, max: 100 },
785 y_range: fidl_input_report::Range { min: 0, max: 100 },
786 x_unit: fidl_input_report::Unit {
787 type_: fidl_input_report::UnitType::Meters,
788 exponent: -6,
789 },
790 y_unit: fidl_input_report::Unit {
791 type_: fidl_input_report::UnitType::Meters,
792 exponent: -6,
793 },
794 pressure_range: None,
795 width_range: None,
796 height_range: None,
797 }],
798 })
799 }
800
801 async fn handle_device_request_stream(
804 mut injector_stream: pointerinjector::DeviceRequestStream,
805 expected_event: pointerinjector::Event,
806 ) {
807 match injector_stream.next().await {
808 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
809 assert_eq!(events.len(), 1);
810 assert_eq!(events[0].timestamp, expected_event.timestamp);
811 assert_eq!(events[0].data, expected_event.data);
812 responder.send().expect("failed to respond");
813 }
814 Some(Err(e)) => panic!("FIDL error {}", e),
815 None => panic!("Expected another event."),
816 }
817 }
818
819 fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
821 pointerinjector::Viewport {
822 extents: Some([[min, min], [max, max]]),
823 viewport_to_context_transform: None,
824 ..Default::default()
825 }
826 }
827
828 #[fuchsia::test]
829 async fn events_with_pressed_buttons_are_sent_to_listener() {
830 let fixtures = TestFixtures::new().await;
831 let (listener, mut listener_stream) =
832 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
833 fixtures
834 .device_listener_proxy
835 .register_touch_buttons_listener(listener)
836 .await
837 .expect("Failed to register listener.");
838
839 let descriptor = get_touch_screen_device_descriptor();
840 let event_time = zx::MonotonicInstant::get();
841 let input_event = create_touch_screen_event(hashmap! {}, event_time, &descriptor);
842
843 let _ = fixtures.touch_handler.clone().handle_input_event(input_event).await;
844
845 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
846 event_time: Some(event_time),
847 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
848 ..Default::default()
849 };
850
851 assert_matches!(
852 listener_stream.next().await,
853 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
854 event,
855 responder,
856 })) => {
857 assert_eq!(event, expected_touch_buttons_event);
858 let _ = responder.send();
859 }
860 );
861 }
862
863 #[fuchsia::test]
864 async fn events_with_contacts_are_not_sent_to_listener() {
865 let fixtures = TestFixtures::new().await;
866 let (listener, mut listener_stream) =
867 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
868 fixtures
869 .device_listener_proxy
870 .register_touch_buttons_listener(listener)
871 .await
872 .expect("Failed to register listener.");
873
874 let descriptor = get_touch_screen_device_descriptor();
875 let event_time = zx::MonotonicInstant::get();
876 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
877 let input_event = create_touch_screen_event(
878 hashmap! {
879 fidl_ui_input::PointerEventPhase::Add
880 => vec![contact.clone()],
881 },
882 event_time,
883 &descriptor,
884 );
885
886 let _ = fixtures.touch_handler.clone().handle_input_event(input_event).await;
887
888 assert!(listener_stream.next().now_or_never().is_none());
889 }
890
891 #[fuchsia::test]
892 async fn multiple_listeners_receive_pressed_button_events() {
893 let fixtures = TestFixtures::new().await;
894 let (first_listener, mut first_listener_stream) =
895 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
896 let (second_listener, mut second_listener_stream) =
897 fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
898 fixtures
899 .device_listener_proxy
900 .register_touch_buttons_listener(first_listener)
901 .await
902 .expect("Failed to register listener.");
903 fixtures
904 .device_listener_proxy
905 .register_touch_buttons_listener(second_listener)
906 .await
907 .expect("Failed to register listener.");
908
909 let descriptor = get_touch_screen_device_descriptor();
910 let event_time = zx::MonotonicInstant::get();
911 let input_event = create_touch_screen_event(hashmap! {}, event_time, &descriptor);
912
913 let _ = fixtures.touch_handler.clone().handle_input_event(input_event).await;
914
915 let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
916 event_time: Some(event_time),
917 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
918 ..Default::default()
919 };
920
921 assert_matches!(
922 first_listener_stream.next().await,
923 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
924 event,
925 responder,
926 })) => {
927 assert_eq!(event, expected_touch_buttons_event);
928 let _ = responder.send();
929 }
930 );
931 assert_matches!(
932 second_listener_stream.next().await,
933 Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
934 event,
935 responder,
936 })) => {
937 assert_eq!(event, expected_touch_buttons_event);
938 let _ = responder.send();
939 }
940 );
941 }
942
943 #[fuchsia::test]
946 async fn receives_viewport_updates() {
947 let mut fixtures = TestFixtures::new().await;
948
949 let (injector_device_proxy, mut injector_device_request_stream) =
951 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
952 fixtures
953 .touch_handler
954 .mutable_state
955 .borrow_mut()
956 .injectors
957 .insert(1, injector_device_proxy);
958
959 {
961 let _watch_viewport_task =
963 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
964
965 match fixtures.configuration_request_stream.next().await {
967 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
968 responder, ..
969 })) => {
970 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
971 }
972 other => panic!("Received unexpected value: {:?}", other),
973 };
974
975 match injector_device_request_stream.next().await {
977 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
978 assert_eq!(events.len(), 1);
979 assert!(events[0].data.is_some());
980 assert_eq!(
981 events[0].data,
982 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
983 );
984 responder.send().expect("injector stream failed to respond.");
985 }
986 other => panic!("Received unexpected value: {:?}", other),
987 }
988
989 match fixtures.configuration_request_stream.next().await {
992 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
993 responder, ..
994 })) => {
995 responder
996 .send(&create_viewport(100.0, 200.0))
997 .expect("Failed to send viewport.");
998 }
999 other => panic!("Received unexpected value: {:?}", other),
1000 };
1001
1002 match injector_device_request_stream.next().await {
1004 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
1005 assert_eq!(events.len(), 1);
1006 assert!(events[0].data.is_some());
1007 assert_eq!(
1008 events[0].data,
1009 Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
1010 );
1011 responder.send().expect("injector stream failed to respond.");
1012 }
1013 other => panic!("Received unexpected value: {:?}", other),
1014 }
1015 }
1016
1017 let expected_viewport = create_viewport(100.0, 200.0);
1019 assert_eq!(fixtures.touch_handler.mutable_state.borrow().viewport, Some(expected_viewport));
1020 }
1021
1022 #[fuchsia::test]
1024 async fn add_contact_drops_without_viewport() {
1025 let mut fixtures = TestFixtures::new().await;
1026
1027 let event_time = zx::MonotonicInstant::get();
1029 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1030 let descriptor = get_touch_screen_device_descriptor();
1031 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1032 hashmap! {
1033 fidl_ui_input::PointerEventPhase::Add
1034 => vec![contact.clone()],
1035 },
1036 event_time,
1037 &descriptor,
1038 ))
1039 .unwrap();
1040
1041 fixtures.touch_handler.mutable_state.borrow_mut().viewport = None;
1043
1044 let _ = fixtures.touch_handler.clone().handle_unhandled_input_event(input_event).await;
1046
1047 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1049 }
1050
1051 #[fuchsia::test]
1053 async fn add_contact_succeeds_with_viewport() {
1054 let mut fixtures = TestFixtures::new().await;
1055
1056 let (injector_device_proxy, mut injector_device_request_stream) =
1058 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1059 fixtures
1060 .touch_handler
1061 .mutable_state
1062 .borrow_mut()
1063 .injectors
1064 .insert(1, injector_device_proxy);
1065
1066 let _watch_viewport_task =
1068 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1069
1070 match fixtures.configuration_request_stream.next().await {
1072 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1073 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1074 }
1075 other => panic!("Received unexpected value: {:?}", other),
1076 };
1077
1078 match injector_device_request_stream.next().await {
1080 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
1081 assert_eq!(events.len(), 1);
1082 assert!(events[0].data.is_some());
1083 assert_eq!(
1084 events[0].data,
1085 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1086 );
1087 responder.send().expect("injector stream failed to respond.");
1088 }
1089 other => panic!("Received unexpected value: {:?}", other),
1090 }
1091
1092 let event_time = zx::MonotonicInstant::get();
1094 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1095 let descriptor = get_touch_screen_device_descriptor();
1096 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1097 hashmap! {
1098 fidl_ui_input::PointerEventPhase::Add
1099 => vec![contact.clone()],
1100 },
1101 event_time,
1102 &descriptor,
1103 ))
1104 .unwrap();
1105
1106 let handle_event_fut =
1108 fixtures.touch_handler.clone().handle_unhandled_input_event(input_event);
1109
1110 let expected_event = create_touch_pointer_sample_event(
1112 pointerinjector::EventPhase::Add,
1113 &contact,
1114 Position { x: 20.0, y: 40.0 },
1115 event_time,
1116 );
1117
1118 let device_fut =
1121 handle_device_request_stream(injector_device_request_stream, expected_event);
1122 let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1123
1124 assert_matches!(
1126 handle_result.as_slice(),
1127 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1128 );
1129 }
1130
1131 #[fuchsia::test]
1133 async fn add_touchpad_contact_with_viewport() {
1134 let mut fixtures = TestFixtures::new().await;
1135
1136 let (injector_device_proxy, mut injector_device_request_stream) =
1138 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1139 fixtures
1140 .touch_handler
1141 .mutable_state
1142 .borrow_mut()
1143 .injectors
1144 .insert(1, injector_device_proxy);
1145
1146 let _watch_viewport_task =
1148 fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1149
1150 match fixtures.configuration_request_stream.next().await {
1152 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1153 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1154 }
1155 other => panic!("Received unexpected value: {:?}", other),
1156 };
1157
1158 match injector_device_request_stream.next().await {
1160 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
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 responder.send().expect("injector stream failed to respond.");
1168 }
1169 other => panic!("Received unexpected value: {:?}", other),
1170 }
1171
1172 let event_time = zx::MonotonicInstant::get();
1174 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1175 let descriptor = get_touchpad_device_descriptor();
1176 let input_event = input_device::UnhandledInputEvent::try_from(create_touchpad_event(
1177 vec![contact.clone()],
1178 HashSet::new(),
1179 event_time,
1180 &descriptor,
1181 ))
1182 .unwrap();
1183
1184 let handle_event_fut =
1186 fixtures.touch_handler.clone().handle_unhandled_input_event(input_event);
1187
1188 let handle_result = handle_event_fut.await;
1189
1190 assert_matches!(
1192 handle_result.as_slice(),
1193 [input_device::InputEvent { handled: input_device::Handled::No, .. }]
1194 );
1195
1196 assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1198 }
1199
1200 #[fuchsia::test(allow_stalls = false)]
1201 async fn touch_injector_handler_initialized_with_inspect_node() {
1202 let fixtures = TestFixtures::new().await;
1203 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1204 test_node: {
1205 touch_injector_handler: {
1206 events_received_count: 0u64,
1207 events_handled_count: 0u64,
1208 last_received_timestamp_ns: 0u64,
1209 "fuchsia.inspect.Health": {
1210 status: "STARTING_UP",
1211 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1214 },
1215 }
1216 }
1217 });
1218 }
1219
1220 #[fuchsia::test(allow_stalls = false)]
1221 async fn touch_injector_handler_inspect_counts_events() {
1222 let fixtures = TestFixtures::new().await;
1223
1224 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1225 let descriptor = get_touch_screen_device_descriptor();
1226 let event_time1 = zx::MonotonicInstant::get();
1227 let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1228 let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1229
1230 let input_events = vec![
1231 create_touch_screen_event(
1232 hashmap! {
1233 fidl_ui_input::PointerEventPhase::Add
1234 => vec![contact.clone()],
1235 },
1236 event_time1,
1237 &descriptor,
1238 ),
1239 create_touch_screen_event(
1240 hashmap! {
1241 fidl_ui_input::PointerEventPhase::Move
1242 => vec![contact.clone()],
1243 },
1244 event_time2,
1245 &descriptor,
1246 ),
1247 create_fake_input_event(event_time2),
1249 create_touch_screen_event_with_handled(
1251 hashmap! {
1252 fidl_ui_input::PointerEventPhase::Move
1253 => vec![contact.clone()],
1254 },
1255 event_time2,
1256 &descriptor,
1257 input_device::Handled::Yes,
1258 ),
1259 create_touch_screen_event(
1260 hashmap! {
1261 fidl_ui_input::PointerEventPhase::Remove
1262 => vec![contact.clone()],
1263 },
1264 event_time3,
1265 &descriptor,
1266 ),
1267 ];
1268
1269 for input_event in input_events {
1270 fixtures.touch_handler.clone().handle_input_event(input_event).await;
1271 }
1272
1273 let last_received_event_time: u64 = event_time3.into_nanos().try_into().unwrap();
1274
1275 diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1276 test_node: {
1277 touch_injector_handler: {
1278 events_received_count: 3u64,
1279 events_handled_count: 3u64,
1280 last_received_timestamp_ns: last_received_event_time,
1281 "fuchsia.inspect.Health": {
1282 status: "STARTING_UP",
1283 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1286 },
1287 }
1288 }
1289 });
1290 }
1291
1292 #[fuchsia::test]
1293 async fn clone_event_with_lease_duplicates_lease() {
1294 let (event_pair, _) = fidl::EventPair::create();
1295 let event = fidl_ui_input::TouchButtonsEvent {
1296 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1297 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1298 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1299 wake_lease: Some(event_pair),
1300 ..Default::default()
1301 };
1302 let cloned_event = TouchInjectorHandler::clone_event(&event);
1303 assert_eq!(event.event_time, cloned_event.event_time);
1304 assert_eq!(event.device_info, cloned_event.device_info);
1305 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1306 assert!(event.wake_lease.is_some());
1307 assert!(cloned_event.wake_lease.is_some());
1308 assert_ne!(
1309 event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
1310 cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
1311 );
1312 }
1313
1314 #[fuchsia::test]
1315 async fn clone_event_without_lease_has_no_lease() {
1316 let event = fidl_ui_input::TouchButtonsEvent {
1317 event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1318 device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1319 pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1320 wake_lease: None,
1321 ..Default::default()
1322 };
1323 let cloned_event = TouchInjectorHandler::clone_event(&event);
1324 assert_eq!(event.event_time, cloned_event.event_time);
1325 assert_eq!(event.device_info, cloned_event.device_info);
1326 assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1327 assert!(event.wake_lease.is_none());
1328 assert!(cloned_event.wake_lease.is_none());
1329 }
1330}