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::create_proxy;
13use fuchsia_component::client::connect_to_protocol;
14use fuchsia_inspect::health::Reporter;
15use futures::stream::StreamExt;
16use metrics_registry::*;
17use std::cell::RefCell;
18use std::collections::HashMap;
19use std::rc::Rc;
20use {
21 fidl_fuchsia_ui_pointerinjector as pointerinjector,
22 fidl_fuchsia_ui_pointerinjector_configuration as pointerinjector_config,
23};
24
25pub struct TouchInjectorHandler {
28 mutable_state: RefCell<MutableState>,
30
31 context_view_ref: fidl_fuchsia_ui_views::ViewRef,
34
35 target_view_ref: fidl_fuchsia_ui_views::ViewRef,
38
39 display_size: Size,
43
44 injector_registry_proxy: pointerinjector::RegistryProxy,
46
47 configuration_proxy: pointerinjector_config::SetupProxy,
49
50 pub inspect_status: InputHandlerStatus,
52
53 metrics_logger: metrics::MetricsLogger,
55}
56
57#[derive(Debug)]
58struct MutableState {
59 viewport: Option<pointerinjector::Viewport>,
62
63 injectors: HashMap<u32, pointerinjector::DeviceProxy>,
65}
66
67#[async_trait(?Send)]
68impl UnhandledInputHandler for TouchInjectorHandler {
69 async fn handle_unhandled_input_event(
70 self: Rc<Self>,
71 unhandled_input_event: input_device::UnhandledInputEvent,
72 ) -> Vec<input_device::InputEvent> {
73 fuchsia_trace::duration!(c"input", c"presentation_on_event");
74 match unhandled_input_event {
75 input_device::UnhandledInputEvent {
76 device_event: input_device::InputDeviceEvent::TouchScreen(ref touch_event),
77 device_descriptor:
78 input_device::InputDeviceDescriptor::TouchScreen(ref touch_device_descriptor),
79 event_time,
80 trace_id,
81 } => {
82 self.inspect_status.count_received_event(input_device::InputEvent::from(
83 unhandled_input_event.clone(),
84 ));
85 fuchsia_trace::flow_end!(
86 c"input",
87 c"report-to-event",
88 trace_id.unwrap_or_else(|| 0.into())
89 );
90 if let Err(e) = self.ensure_injector_registered(&touch_device_descriptor).await {
92 self.metrics_logger.log_error(
93 InputPipelineErrorMetricDimensionEvent::TouchInjectorEnsureInjectorRegisteredFailed,
94 std::format!("ensure_injector_registered failed: {}", e));
95 }
96
97 if let Err(e) = self
99 .send_event_to_scenic(&touch_event, &touch_device_descriptor, event_time)
100 .await
101 {
102 self.metrics_logger.log_error(
103 InputPipelineErrorMetricDimensionEvent::TouchInjectorSendEventToScenicFailed,
104 std::format!("send_event_to_scenic failed: {}", e));
105 }
106
107 self.inspect_status.count_handled_event();
109 vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
110 }
111 _ => vec![input_device::InputEvent::from(unhandled_input_event)],
112 }
113 }
114
115 fn set_handler_healthy(self: std::rc::Rc<Self>) {
116 self.inspect_status.health_node.borrow_mut().set_ok();
117 }
118
119 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
120 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
121 }
122}
123
124impl TouchInjectorHandler {
125 pub async fn new(
137 display_size: Size,
138 input_handlers_node: &fuchsia_inspect::Node,
139 metrics_logger: metrics::MetricsLogger,
140 ) -> Result<Rc<Self>, Error> {
141 let configuration_proxy = connect_to_protocol::<pointerinjector_config::SetupMarker>()?;
142 let injector_registry_proxy = connect_to_protocol::<pointerinjector::RegistryMarker>()?;
143
144 Self::new_handler(
145 configuration_proxy,
146 injector_registry_proxy,
147 display_size,
148 input_handlers_node,
149 metrics_logger,
150 )
151 .await
152 }
153
154 pub async fn new_with_config_proxy(
169 configuration_proxy: pointerinjector_config::SetupProxy,
170 display_size: Size,
171 input_handlers_node: &fuchsia_inspect::Node,
172 metrics_logger: metrics::MetricsLogger,
173 ) -> Result<Rc<Self>, Error> {
174 let injector_registry_proxy = connect_to_protocol::<pointerinjector::RegistryMarker>()?;
175 Self::new_handler(
176 configuration_proxy,
177 injector_registry_proxy,
178 display_size,
179 input_handlers_node,
180 metrics_logger,
181 )
182 .await
183 }
184
185 async fn new_handler(
201 configuration_proxy: pointerinjector_config::SetupProxy,
202 injector_registry_proxy: pointerinjector::RegistryProxy,
203 display_size: Size,
204 input_handlers_node: &fuchsia_inspect::Node,
205 metrics_logger: metrics::MetricsLogger,
206 ) -> Result<Rc<Self>, Error> {
207 let (context_view_ref, target_view_ref) = configuration_proxy.get_view_refs().await?;
209
210 let inspect_status = InputHandlerStatus::new(
211 input_handlers_node,
212 "touch_injector_handler",
213 false,
214 );
215 let handler = Rc::new(Self {
216 mutable_state: RefCell::new(MutableState { viewport: None, injectors: HashMap::new() }),
217 context_view_ref,
218 target_view_ref,
219 display_size,
220 injector_registry_proxy,
221 configuration_proxy,
222 inspect_status,
223 metrics_logger,
224 });
225
226 Ok(handler)
227 }
228
229 async fn ensure_injector_registered(
235 self: &Rc<Self>,
236 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
237 ) -> Result<(), anyhow::Error> {
238 if self.mutable_state.borrow().injectors.contains_key(&touch_descriptor.device_id) {
239 return Ok(());
240 }
241
242 let (device_proxy, device_server) = create_proxy::<pointerinjector::DeviceMarker>();
244 let context = fuchsia_scenic::duplicate_view_ref(&self.context_view_ref)
245 .context("Failed to duplicate context view ref.")?;
246 let target = fuchsia_scenic::duplicate_view_ref(&self.target_view_ref)
247 .context("Failed to duplicate target view ref.")?;
248 let viewport = self.mutable_state.borrow().viewport.clone();
249 if viewport.is_none() {
250 return Err(anyhow::format_err!(
253 "Received a touch event without a viewport to inject into."
254 ));
255 }
256 let config = pointerinjector::Config {
257 device_id: Some(touch_descriptor.device_id),
258 device_type: Some(pointerinjector::DeviceType::Touch),
259 context: Some(pointerinjector::Context::View(context)),
260 target: Some(pointerinjector::Target::View(target)),
261 viewport,
262 dispatch_policy: Some(pointerinjector::DispatchPolicy::TopHitAndAncestorsInTarget),
263 scroll_v_range: None,
264 scroll_h_range: None,
265 buttons: None,
266 ..Default::default()
267 };
268
269 self.mutable_state.borrow_mut().injectors.insert(touch_descriptor.device_id, device_proxy);
271
272 self.injector_registry_proxy
274 .register(config, device_server)
275 .await
276 .context("Failed to register injector.")?;
277 log::info!("Registered injector with device id {:?}", touch_descriptor.device_id);
278
279 Ok(())
280 }
281
282 async fn send_event_to_scenic(
289 &self,
290 touch_event: &touch_binding::TouchScreenEvent,
291 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
292 event_time: zx::MonotonicInstant,
293 ) -> Result<(), anyhow::Error> {
294 let ordered_phases = vec![
296 pointerinjector::EventPhase::Add,
297 pointerinjector::EventPhase::Change,
298 pointerinjector::EventPhase::Remove,
299 ];
300
301 fuchsia_trace::duration_begin!(c"input", c"touch-inject-into-scenic");
306
307 let mut events: Vec<pointerinjector::Event> = vec![];
308 for phase in ordered_phases {
309 let contacts: Vec<touch_binding::TouchContact> = touch_event
310 .injector_contacts
311 .get(&phase)
312 .map_or(vec![], |contacts| contacts.to_owned());
313 let new_events = contacts.into_iter().map(|contact| {
314 Self::create_pointer_sample_event(
315 phase,
316 &contact,
317 touch_descriptor,
318 &self.display_size,
319 event_time,
320 )
321 });
322 events.extend(new_events);
323 }
324
325 let injector =
326 self.mutable_state.borrow().injectors.get(&touch_descriptor.device_id).cloned();
327 if let Some(injector) = injector {
328 let fut = injector.inject(&events);
329 fuchsia_trace::duration_end!(c"input", c"touch-inject-into-scenic");
331 let _ = fut.await;
332 Ok(())
333 } else {
334 fuchsia_trace::duration_end!(c"input", c"touch-inject-into-scenic");
335 Err(anyhow::format_err!(
336 "No injector found for touch device {}.",
337 touch_descriptor.device_id
338 ))
339 }
340 }
341
342 fn create_pointer_sample_event(
351 phase: pointerinjector::EventPhase,
352 contact: &touch_binding::TouchContact,
353 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
354 display_size: &Size,
355 event_time: zx::MonotonicInstant,
356 ) -> pointerinjector::Event {
357 let position =
358 Self::display_coordinate_from_contact(&contact, &touch_descriptor, display_size);
359 let pointer_sample = pointerinjector::PointerSample {
360 pointer_id: Some(contact.id),
361 phase: Some(phase),
362 position_in_viewport: Some([position.x, position.y]),
363 scroll_v: None,
364 scroll_h: None,
365 pressed_buttons: None,
366 ..Default::default()
367 };
368 let data = pointerinjector::Data::PointerSample(pointer_sample);
369
370 let trace_flow_id = fuchsia_trace::Id::new();
371 let event = pointerinjector::Event {
372 timestamp: Some(event_time.into_nanos()),
373 data: Some(data),
374 trace_flow_id: Some(trace_flow_id.into()),
375 ..Default::default()
376 };
377
378 fuchsia_trace::flow_begin!(c"input", c"dispatch_event_to_scenic", trace_flow_id);
379
380 event
381 }
382
383 fn display_coordinate_from_contact(
397 contact: &touch_binding::TouchContact,
398 touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
399 display_size: &Size,
400 ) -> Position {
401 if let Some(contact_descriptor) = touch_descriptor.contacts.first() {
402 let x_range: f32 =
404 contact_descriptor.x_range.max as f32 - contact_descriptor.x_range.min as f32;
405 let x_wrt_range: f32 = contact.position.x - contact_descriptor.x_range.min as f32;
406 let x: f32 = (display_size.width * x_wrt_range) / x_range;
407
408 let y_range: f32 =
410 contact_descriptor.y_range.max as f32 - contact_descriptor.y_range.min as f32;
411 let y_wrt_range: f32 = contact.position.y - contact_descriptor.y_range.min as f32;
412 let y: f32 = (display_size.height * y_wrt_range) / y_range;
413
414 Position { x, y }
415 } else {
416 return contact.position;
417 }
418 }
419
420 pub async fn watch_viewport(self: Rc<Self>) {
422 let configuration_proxy = self.configuration_proxy.clone();
423 let mut viewport_stream = HangingGetStream::new(
424 configuration_proxy,
425 pointerinjector_config::SetupProxy::watch_viewport,
426 );
427 loop {
428 match viewport_stream.next().await {
429 Some(Ok(new_viewport)) => {
430 self.mutable_state.borrow_mut().viewport = Some(new_viewport.clone());
432
433 let injectors: Vec<pointerinjector::DeviceProxy> =
435 self.mutable_state.borrow_mut().injectors.values().cloned().collect();
436 for injector in injectors {
437 let events = &[pointerinjector::Event {
438 timestamp: Some(fuchsia_async::MonotonicInstant::now().into_nanos()),
439 data: Some(pointerinjector::Data::Viewport(new_viewport.clone())),
440 trace_flow_id: Some(fuchsia_trace::Id::new().into()),
441 ..Default::default()
442 }];
443 injector.inject(events).await.expect("Failed to inject updated viewport.");
444 }
445 }
446 Some(Err(e)) => {
447 self.metrics_logger.log_error(
448 InputPipelineErrorMetricDimensionEvent::TouchInjectorErrorWhileReadingViewportUpdate,
449 std::format!("Error while reading viewport update: {}", e));
450 return;
451 }
452 None => {
453 self.metrics_logger.log_error(
454 InputPipelineErrorMetricDimensionEvent::TouchInjectorViewportUpdateStreamTerminatedUnexpectedly,
455 "Viewport update stream terminated unexpectedly");
456 return;
457 }
458 }
459 }
460 }
461}
462
463#[cfg(test)]
464mod tests {
465 use super::*;
466 use crate::input_handler::InputHandler;
467 use crate::testing_utilities::{
468 create_fake_input_event, create_touch_contact, create_touch_pointer_sample_event,
469 create_touch_screen_event, create_touch_screen_event_with_handled, create_touchpad_event,
470 get_touch_screen_device_descriptor,
471 };
472 use assert_matches::assert_matches;
473 use maplit::hashmap;
474 use pretty_assertions::assert_eq;
475 use std::collections::HashSet;
476 use std::convert::TryFrom as _;
477 use std::ops::Add;
478 use {
479 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
480 fuchsia_async as fasync,
481 };
482
483 const TOUCH_ID: u32 = 1;
484 const DISPLAY_WIDTH: f32 = 100.0;
485 const DISPLAY_HEIGHT: f32 = 100.0;
486
487 fn get_touchpad_device_descriptor() -> input_device::InputDeviceDescriptor {
489 input_device::InputDeviceDescriptor::Touchpad(touch_binding::TouchpadDeviceDescriptor {
490 device_id: 1,
491 contacts: vec![touch_binding::ContactDeviceDescriptor {
492 x_range: fidl_input_report::Range { min: 0, max: 100 },
493 y_range: fidl_input_report::Range { min: 0, max: 100 },
494 x_unit: fidl_input_report::Unit {
495 type_: fidl_input_report::UnitType::Meters,
496 exponent: -6,
497 },
498 y_unit: fidl_input_report::Unit {
499 type_: fidl_input_report::UnitType::Meters,
500 exponent: -6,
501 },
502 pressure_range: None,
503 width_range: None,
504 height_range: None,
505 }],
506 })
507 }
508
509 async fn handle_configuration_request_stream(
511 stream: &mut pointerinjector_config::SetupRequestStream,
512 ) {
513 if let Some(Ok(request)) = stream.next().await {
514 match request {
515 pointerinjector_config::SetupRequest::GetViewRefs { responder, .. } => {
516 let context = fuchsia_scenic::ViewRefPair::new()
517 .expect("Failed to create viewrefpair.")
518 .view_ref;
519 let target = fuchsia_scenic::ViewRefPair::new()
520 .expect("Failed to create viewrefpair.")
521 .view_ref;
522 let _ = responder.send(context, target);
523 }
524 _ => {}
525 };
526 }
527 }
528
529 async fn handle_device_request_stream(
532 mut injector_stream: pointerinjector::DeviceRequestStream,
533 expected_event: pointerinjector::Event,
534 ) {
535 match injector_stream.next().await {
536 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
537 assert_eq!(events.len(), 1);
538 assert_eq!(events[0].timestamp, expected_event.timestamp);
539 assert_eq!(events[0].data, expected_event.data);
540 responder.send().expect("failed to respond");
541 }
542 Some(Err(e)) => panic!("FIDL error {}", e),
543 None => panic!("Expected another event."),
544 }
545 }
546
547 fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
549 pointerinjector::Viewport {
550 extents: Some([[min, min], [max, max]]),
551 viewport_to_context_transform: None,
552 ..Default::default()
553 }
554 }
555
556 #[fuchsia::test]
559 fn receives_viewport_updates() {
560 let mut exec = fasync::TestExecutor::new();
561
562 let (configuration_proxy, mut configuration_request_stream) =
564 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
565 let (injector_registry_proxy, _injector_registry_request_stream) =
566 fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
567 let inspector = fuchsia_inspect::Inspector::default();
568 let test_node = inspector.root().create_child("test_node");
569 let touch_handler_fut = TouchInjectorHandler::new_handler(
570 configuration_proxy,
571 injector_registry_proxy,
572 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
573 &test_node,
574 metrics::MetricsLogger::default(),
575 );
576 let config_request_stream_fut =
577 handle_configuration_request_stream(&mut configuration_request_stream);
578 let (touch_handler_res, _) = exec.run_singlethreaded(futures::future::join(
579 touch_handler_fut,
580 config_request_stream_fut,
581 ));
582 let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
583
584 let (injector_device_proxy, mut injector_device_request_stream) =
586 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
587 touch_handler.mutable_state.borrow_mut().injectors.insert(1, injector_device_proxy);
588
589 {
591 let watch_viewport_fut = touch_handler.clone().watch_viewport();
593 futures::pin_mut!(watch_viewport_fut);
594 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
595
596 match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
598 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
599 responder, ..
600 })) => {
601 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
602 }
603 other => panic!("Received unexpected value: {:?}", other),
604 };
605 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
606
607 exec.run_singlethreaded(async {
609 match injector_device_request_stream.next().await {
610 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
611 assert_eq!(events.len(), 1);
612 assert!(events[0].data.is_some());
613 assert_eq!(
614 events[0].data,
615 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
616 );
617 responder.send().expect("injector stream failed to respond.");
618 }
619 other => panic!("Received unexpected value: {:?}", other),
620 }
621 });
622
623 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
625
626 match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
628 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
629 responder, ..
630 })) => {
631 responder
632 .send(&create_viewport(100.0, 200.0))
633 .expect("Failed to send viewport.");
634 }
635 other => panic!("Received unexpected value: {:?}", other),
636 };
637
638 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
640
641 exec.run_singlethreaded(async {
643 match injector_device_request_stream.next().await {
644 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
645 assert_eq!(events.len(), 1);
646 assert!(events[0].data.is_some());
647 assert_eq!(
648 events[0].data,
649 Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
650 );
651 responder.send().expect("injector stream failed to respond.");
652 }
653 other => panic!("Received unexpected value: {:?}", other),
654 }
655 });
656 }
657
658 let expected_viewport = create_viewport(100.0, 200.0);
660 assert_eq!(touch_handler.mutable_state.borrow().viewport, Some(expected_viewport));
661 }
662
663 #[fuchsia::test]
665 fn add_contact_drops_without_viewport() {
666 let mut exec = fasync::TestExecutor::new();
667
668 let (configuration_proxy, mut configuration_request_stream) =
670 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
671 let (injector_registry_proxy, mut injector_registry_request_stream) =
672 fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
673 let config_request_stream_fut =
674 handle_configuration_request_stream(&mut configuration_request_stream);
675
676 let inspector = fuchsia_inspect::Inspector::default();
677 let test_node = inspector.root().create_child("test_node");
678
679 let touch_handler_fut = TouchInjectorHandler::new_handler(
681 configuration_proxy,
682 injector_registry_proxy,
683 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
684 &test_node,
685 metrics::MetricsLogger::default(),
686 );
687 let (touch_handler_res, _) = exec.run_singlethreaded(futures::future::join(
688 touch_handler_fut,
689 config_request_stream_fut,
690 ));
691 let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
692
693 let event_time = zx::MonotonicInstant::get();
695 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
696 let descriptor = get_touch_screen_device_descriptor();
697 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
698 hashmap! {
699 fidl_ui_input::PointerEventPhase::Add
700 => vec![contact.clone()],
701 },
702 event_time,
703 &descriptor,
704 ))
705 .unwrap();
706
707 let mut handle_event_fut = touch_handler.clone().handle_unhandled_input_event(input_event);
712 let _ = exec.run_until_stalled(&mut handle_event_fut);
713
714 let mut ir_fut = injector_registry_request_stream.next();
716 assert_matches!(exec.run_until_stalled(&mut ir_fut), futures::task::Poll::Pending);
717 }
718
719 #[fuchsia::test]
721 fn add_contact_succeeds_with_viewport() {
722 let mut exec = fasync::TestExecutor::new();
723
724 let (configuration_proxy, mut configuration_request_stream) =
726 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
727 let (injector_registry_proxy, _injector_registry_request_stream) =
728 fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
729 let inspector = fuchsia_inspect::Inspector::default();
730 let test_node = inspector.root().create_child("test_node");
731 let touch_handler_fut = TouchInjectorHandler::new_handler(
732 configuration_proxy,
733 injector_registry_proxy,
734 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
735 &test_node,
736 metrics::MetricsLogger::default(),
737 );
738 let config_request_stream_fut =
739 handle_configuration_request_stream(&mut configuration_request_stream);
740 let (touch_handler_res, _) = exec.run_singlethreaded(futures::future::join(
741 touch_handler_fut,
742 config_request_stream_fut,
743 ));
744 let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
745
746 let (injector_device_proxy, mut injector_device_request_stream) =
748 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
749 touch_handler.mutable_state.borrow_mut().injectors.insert(1, injector_device_proxy);
750
751 let watch_viewport_fut = fasync::Task::local(touch_handler.clone().watch_viewport());
753 futures::pin_mut!(watch_viewport_fut);
754 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
755
756 match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
758 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
759 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
760 }
761 other => panic!("Received unexpected value: {:?}", other),
762 };
763 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
764
765 exec.run_singlethreaded(async {
767 match injector_device_request_stream.next().await {
768 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
769 assert_eq!(events.len(), 1);
770 assert!(events[0].data.is_some());
771 assert_eq!(
772 events[0].data,
773 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
774 );
775 responder.send().expect("injector stream failed to respond.");
776 }
777 other => panic!("Received unexpected value: {:?}", other),
778 }
779 });
780
781 let event_time = zx::MonotonicInstant::get();
783 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
784 let descriptor = get_touch_screen_device_descriptor();
785 let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
786 hashmap! {
787 fidl_ui_input::PointerEventPhase::Add
788 => vec![contact.clone()],
789 },
790 event_time,
791 &descriptor,
792 ))
793 .unwrap();
794
795 let handle_event_fut = touch_handler.clone().handle_unhandled_input_event(input_event);
797
798 let expected_event = create_touch_pointer_sample_event(
800 pointerinjector::EventPhase::Add,
801 &contact,
802 Position { x: 20.0, y: 40.0 },
803 event_time,
804 );
805
806 let device_fut =
809 handle_device_request_stream(injector_device_request_stream, expected_event);
810 let (handle_result, _) =
811 exec.run_singlethreaded(futures::future::join(handle_event_fut, device_fut));
812
813 assert_matches!(
815 handle_result.as_slice(),
816 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
817 );
818 }
819
820 #[fuchsia::test]
822 fn add_touchpad_contact_with_viewport() {
823 let mut exec = fasync::TestExecutor::new();
824
825 let (configuration_proxy, mut configuration_request_stream) =
827 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
828 let (injector_registry_proxy, mut injector_registry_request_stream) =
829 fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
830 let inspector = fuchsia_inspect::Inspector::default();
831 let test_node = inspector.root().create_child("test_node");
832 let touch_handler_fut = TouchInjectorHandler::new_handler(
833 configuration_proxy,
834 injector_registry_proxy,
835 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
836 &test_node,
837 metrics::MetricsLogger::default(),
838 );
839 let config_request_stream_fut =
840 handle_configuration_request_stream(&mut configuration_request_stream);
841 let (touch_handler_res, _) = exec.run_singlethreaded(futures::future::join(
842 touch_handler_fut,
843 config_request_stream_fut,
844 ));
845 let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
846
847 let (injector_device_proxy, mut injector_device_request_stream) =
849 fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
850 touch_handler.mutable_state.borrow_mut().injectors.insert(1, injector_device_proxy);
851
852 let watch_viewport_fut = fasync::Task::local(touch_handler.clone().watch_viewport());
854 futures::pin_mut!(watch_viewport_fut);
855 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
856
857 match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
859 Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
860 responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
861 }
862 other => panic!("Received unexpected value: {:?}", other),
863 };
864 assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
865
866 exec.run_singlethreaded(async {
868 match injector_device_request_stream.next().await {
869 Some(Ok(pointerinjector::DeviceRequest::Inject { events, responder })) => {
870 assert_eq!(events.len(), 1);
871 assert!(events[0].data.is_some());
872 assert_eq!(
873 events[0].data,
874 Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
875 );
876 responder.send().expect("injector stream failed to respond.");
877 }
878 other => panic!("Received unexpected value: {:?}", other),
879 }
880 });
881
882 let event_time = zx::MonotonicInstant::get();
884 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
885 let descriptor = get_touchpad_device_descriptor();
886 let input_event = input_device::UnhandledInputEvent::try_from(create_touchpad_event(
887 vec![contact.clone()],
888 HashSet::new(),
889 event_time,
890 &descriptor,
891 ))
892 .unwrap();
893
894 let handle_event_fut = touch_handler.clone().handle_unhandled_input_event(input_event);
896
897 let handle_result = exec.run_singlethreaded(handle_event_fut);
898
899 assert_matches!(
901 handle_result.as_slice(),
902 [input_device::InputEvent { handled: input_device::Handled::No, .. }]
903 );
904
905 let mut ir_fut = injector_registry_request_stream.next();
907 assert_matches!(exec.run_until_stalled(&mut ir_fut), futures::task::Poll::Pending);
908 }
909
910 #[fuchsia::test(allow_stalls = false)]
911 async fn touch_injector_handler_initialized_with_inspect_node() {
912 let (configuration_proxy, mut configuration_request_stream) =
913 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
914 let inspector = fuchsia_inspect::Inspector::default();
915 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
916 let touch_handler_fut = TouchInjectorHandler::new_with_config_proxy(
917 configuration_proxy,
918 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
919 &fake_handlers_node,
920 metrics::MetricsLogger::default(),
921 );
922 let config_request_stream_fut =
923 handle_configuration_request_stream(&mut configuration_request_stream);
924 let (touch_handler_res, _) = futures::join!(touch_handler_fut, config_request_stream_fut,);
925 let _handler = touch_handler_res.expect("Failed to create touch handler.");
926 diagnostics_assertions::assert_data_tree!(inspector, root: {
927 input_handlers_node: {
928 touch_injector_handler: {
929 events_received_count: 0u64,
930 events_handled_count: 0u64,
931 last_received_timestamp_ns: 0u64,
932 "fuchsia.inspect.Health": {
933 status: "STARTING_UP",
934 start_timestamp_nanos: diagnostics_assertions::AnyProperty
937 },
938 }
939 }
940 });
941 }
942
943 #[fuchsia::test(allow_stalls = false)]
944 async fn touch_injector_handler_inspect_counts_events() {
945 let (configuration_proxy, mut configuration_request_stream) =
947 fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
948 let (injector_registry_proxy, _) =
949 fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
950
951 let inspector = fuchsia_inspect::Inspector::default();
952 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
953
954 let touch_handler_fut = TouchInjectorHandler::new_handler(
956 configuration_proxy,
957 injector_registry_proxy,
958 Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
959 &fake_handlers_node,
960 metrics::MetricsLogger::default(),
961 );
962 let config_request_stream_fut =
963 handle_configuration_request_stream(&mut configuration_request_stream);
964 let (touch_handler_res, _) = futures::join!(touch_handler_fut, config_request_stream_fut);
965 let touch_handler = touch_handler_res.expect("Failed to create touch handler");
966
967 let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
968 let descriptor = get_touch_screen_device_descriptor();
969 let event_time1 = zx::MonotonicInstant::get();
970 let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
971 let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
972
973 let input_events = vec![
974 create_touch_screen_event(
975 hashmap! {
976 fidl_ui_input::PointerEventPhase::Add
977 => vec![contact.clone()],
978 },
979 event_time1,
980 &descriptor,
981 ),
982 create_touch_screen_event(
983 hashmap! {
984 fidl_ui_input::PointerEventPhase::Move
985 => vec![contact.clone()],
986 },
987 event_time2,
988 &descriptor,
989 ),
990 create_fake_input_event(event_time2),
992 create_touch_screen_event_with_handled(
994 hashmap! {
995 fidl_ui_input::PointerEventPhase::Move
996 => vec![contact.clone()],
997 },
998 event_time2,
999 &descriptor,
1000 input_device::Handled::Yes,
1001 ),
1002 create_touch_screen_event(
1003 hashmap! {
1004 fidl_ui_input::PointerEventPhase::Remove
1005 => vec![contact.clone()],
1006 },
1007 event_time3,
1008 &descriptor,
1009 ),
1010 ];
1011
1012 for input_event in input_events {
1013 touch_handler.clone().handle_input_event(input_event).await;
1014 }
1015
1016 let last_received_event_time: u64 = event_time3.into_nanos().try_into().unwrap();
1017
1018 diagnostics_assertions::assert_data_tree!(inspector, root: {
1019 input_handlers_node: {
1020 touch_injector_handler: {
1021 events_received_count: 3u64,
1022 events_handled_count: 3u64,
1023 last_received_timestamp_ns: last_received_event_time,
1024 "fuchsia.inspect.Health": {
1025 status: "STARTING_UP",
1026 start_timestamp_nanos: diagnostics_assertions::AnyProperty
1029 },
1030 }
1031 }
1032 });
1033 }
1034}