Skip to main content

input_pipeline/
touch_injector_handler.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#![warn(clippy::await_holding_refcell_ref)]
6use crate::input_handler::{BatchInputHandler, Handler, InputHandlerStatus};
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
29/// An input handler that parses touch events and forwards them to Scenic through the
30/// fidl_fuchsia_pointerinjector protocols.
31pub struct TouchInjectorHandler {
32    /// The mutable fields of this handler.
33    mutable_state: RefCell<MutableState>,
34
35    /// The scope and coordinate system of injection.
36    /// See fidl_fuchsia_pointerinjector::Context for more details.
37    context_view_ref: fidl_fuchsia_ui_views::ViewRef,
38
39    /// The region where dispatch is attempted for injected events.
40    /// See fidl_fuchsia_pointerinjector::Target for more details.
41    target_view_ref: fidl_fuchsia_ui_views::ViewRef,
42
43    /// The size of the display associated with the touch device, used to convert
44    /// coordinates from the touch input report to device coordinates (which is what
45    /// Scenic expects).
46    display_size: Size,
47
48    /// The FIDL proxy to register new injectors.
49    injector_registry_proxy: pointerinjector::RegistryProxy,
50
51    /// The FIDL proxy used to get configuration details for pointer injection.
52    configuration_proxy: pointerinjector_config::SetupProxy,
53
54    /// The inventory of this handler's Inspect status.
55    pub inspect_status: InputHandlerStatus,
56
57    /// The metrics logger.
58    metrics_logger: metrics::MetricsLogger,
59}
60
61#[derive(Debug)]
62struct MutableState {
63    /// A rectangular region that directs injected events into a target.
64    /// See fidl_fuchsia_pointerinjector::Viewport for more details.
65    viewport: Option<pointerinjector::Viewport>,
66
67    /// The injectors registered with Scenic, indexed by their device ids.
68    injectors: HashMap<u32, pointerinjector::DeviceProxy>,
69
70    /// The touch button listeners, key referenced by proxy channel's raw handle.
71    pub listeners: HashMap<u32, fidl_ui_policy::TouchButtonsListenerProxy>,
72
73    /// The last TouchButtonsEvent sent to all listeners.
74    /// This is used to send new listeners the state of the touchscreen buttons.
75    pub last_button_event: Option<fidl_ui_input::TouchButtonsEvent>,
76
77    pub send_event_task_tracker: LocalTaskTracker,
78}
79
80impl Handler for TouchInjectorHandler {
81    fn set_handler_healthy(self: std::rc::Rc<Self>) {
82        self.inspect_status.health_node.borrow_mut().set_ok();
83    }
84
85    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
86        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
87    }
88
89    fn get_name(&self) -> &'static str {
90        "TouchInjectorHandler"
91    }
92
93    fn interest(&self) -> Vec<input_device::InputEventType> {
94        vec![input_device::InputEventType::TouchScreen]
95    }
96}
97
98#[async_trait(?Send)]
99impl BatchInputHandler for TouchInjectorHandler {
100    async fn handle_input_events(
101        self: Rc<Self>,
102        events: Vec<input_device::InputEvent>,
103    ) -> Vec<input_device::InputEvent> {
104        if events.is_empty() {
105            return events;
106        }
107
108        fuchsia_trace::duration!("input", "touch_injector_handler");
109
110        let mut result: Vec<input_device::InputEvent> = Vec::new();
111        let mut pending_scenic_events: Vec<pointerinjector::Event> = Vec::new();
112
113        let device_id = events[0].device_descriptor.device_id();
114        let has_different_device_events =
115            events.iter().any(|e| e.device_descriptor.device_id() != device_id);
116        if has_different_device_events {
117            self.metrics_logger.log_error(
118                InputPipelineErrorMetricDimensionEvent::TouchInjectorReceivedInputFrameContainsEventsFromMultipleDevices,
119                std::format!("TouchInjectorHandler: Received events from different devices"),
120            );
121            return events;
122        }
123
124        for event in events {
125            let (out_events, scenic_events) = self.clone().handle_single_input_event(event).await;
126            result.extend(out_events);
127            pending_scenic_events.extend(scenic_events);
128        }
129
130        if !pending_scenic_events.is_empty() {
131            if let input_device::InputDeviceDescriptor::TouchScreen(ref touch_device_descriptor) =
132                result[0].device_descriptor
133            {
134                if let Err(e) =
135                    self.inject_pointer_events(pending_scenic_events, touch_device_descriptor)
136                {
137                    self.metrics_logger.log_error(
138                        InputPipelineErrorMetricDimensionEvent::TouchInjectorSendEventToScenicFailed,
139                        std::format!("inject_pointer_events failed: {}", e),
140                    );
141                }
142            }
143        }
144
145        result
146    }
147}
148
149impl TouchInjectorHandler {
150    /// Creates a new touch handler that holds touch pointer injectors.
151    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
152    /// Example:
153    /// let handler = TouchInjectorHandler::new(display_size).await?;
154    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
155    ///
156    /// # Parameters
157    /// - `display_size`: The size of the associated touch display.
158    ///
159    /// # Errors
160    /// If unable to connect to pointerinjector protocols.
161    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    /// Creates a new touch handler that holds touch pointer injectors.
180    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
181    /// Example:
182    /// let handler = TouchInjectorHandler::new_with_config_proxy(config_proxy, display_size).await?;
183    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
184    ///
185    /// # Parameters
186    /// - `configuration_proxy`: A proxy used to get configuration details for pointer
187    ///    injection.
188    /// - `display_size`: The size of the associated touch display.
189    ///
190    /// # Errors
191    /// If unable to get injection view refs from `configuration_proxy`.
192    /// If unable to connect to pointerinjector Registry protocol.
193    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    /// Creates a new touch handler that holds touch pointer injectors.
211    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
212    /// Example:
213    /// let handler = TouchInjectorHandler::new_handler(None, None, display_size).await?;
214    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
215    ///
216    /// # Parameters
217    /// - `configuration_proxy`: A proxy used to get configuration details for pointer
218    ///    injection.
219    /// - `injector_registry_proxy`: A proxy used to register new pointer injectors.  If
220    ///    none is provided, connect to protocol routed to this component.
221    /// - `display_size`: The size of the associated touch display.
222    ///
223    /// # Errors
224    /// If unable to get injection view refs from `configuration_proxy`.
225    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        // Get the context and target views to inject into.
233        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            /* generates_events */ 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 handle_single_input_event(
279        self: Rc<Self>,
280        mut input_event: input_device::InputEvent,
281    ) -> (Vec<input_device::InputEvent>, Vec<pointerinjector::Event>) {
282        match input_event {
283            input_device::InputEvent {
284                device_event: input_device::InputDeviceEvent::TouchScreen(ref mut touch_event),
285                device_descriptor:
286                    input_device::InputDeviceDescriptor::TouchScreen(ref touch_device_descriptor),
287                event_time,
288                handled: input_device::Handled::No,
289                trace_id,
290            } => {
291                self.inspect_status.count_received_event(&event_time);
292                fuchsia_trace::duration!("input", "touch_injector_handler[processing]");
293                if let Some(trace_id) = trace_id {
294                    fuchsia_trace::flow_step!("input", "event_in_input_pipeline", trace_id.into());
295                }
296
297                let mut scenic_events = vec![];
298                if touch_event.injector_contacts.values().all(|vec| vec.is_empty()) {
299                    let mut touch_buttons_event = Self::create_touch_buttons_event(
300                        touch_event,
301                        event_time,
302                        &touch_device_descriptor,
303                    );
304
305                    // Send the event if the touch buttons are supported.
306                    self.send_event_to_listeners(&touch_buttons_event).await;
307
308                    // Store the sent event without any wake leases.
309                    std::mem::drop(touch_buttons_event.wake_lease.take());
310                    self.mutable_state.borrow_mut().last_button_event = Some(touch_buttons_event);
311                } else if touch_event.pressed_buttons.is_empty() {
312                    // Create a new injector if this is the first time seeing device_id.
313                    if let Err(e) = self.ensure_injector_registered(&touch_device_descriptor).await
314                    {
315                        self.metrics_logger.log_error(
316                        InputPipelineErrorMetricDimensionEvent::TouchInjectorEnsureInjectorRegisteredFailed,
317                        std::format!("ensure_injector_registered failed: {}", e));
318                    }
319
320                    // Handle the event.
321                    scenic_events = self.create_pointer_events(
322                        touch_event,
323                        &touch_device_descriptor,
324                        event_time,
325                    );
326                }
327
328                // Consume the input event.
329                self.inspect_status.count_handled_event();
330                (vec![input_event.into_handled()], scenic_events)
331            }
332            input_device::InputEvent {
333                device_event: input_device::InputDeviceEvent::TouchScreen(_),
334                handled: input_device::Handled::Yes,
335                ..
336            } => {
337                // If a touch event is handled but reached to TouchInjectorHandler, it's expected.
338                (vec![input_event], vec![])
339            }
340            _ => {
341                log::warn!("Unhandled input event: {:?}", input_event.get_event_type());
342                (vec![input_event], vec![])
343            }
344        }
345    }
346
347    /// Adds a new pointer injector and tracks it in `self.injectors` if one doesn't exist at
348    /// `touch_descriptor.device_id`.
349    ///
350    /// # Parameters
351    /// - `touch_descriptor`: The descriptor of the new touch device.
352    async fn ensure_injector_registered(
353        self: &Rc<Self>,
354        touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
355    ) -> Result<(), anyhow::Error> {
356        if self.mutable_state.borrow().injectors.contains_key(&touch_descriptor.device_id) {
357            return Ok(());
358        }
359
360        // Create a new injector.
361        let (device_proxy, device_server) = create_proxy::<pointerinjector::DeviceMarker>();
362        let context = fuchsia_scenic::duplicate_view_ref(&self.context_view_ref)
363            .context("Failed to duplicate context view ref.")?;
364        let target = fuchsia_scenic::duplicate_view_ref(&self.target_view_ref)
365            .context("Failed to duplicate target view ref.")?;
366        let viewport = self.mutable_state.borrow().viewport.clone();
367        if viewport.is_none() {
368            // An injector without a viewport is not valid. The event will be dropped
369            // since the handler will not have a registered injector to inject into.
370            return Err(anyhow::format_err!(
371                "Received a touch event without a viewport to inject into."
372            ));
373        }
374        let config = pointerinjector::Config {
375            device_id: Some(touch_descriptor.device_id),
376            device_type: Some(pointerinjector::DeviceType::Touch),
377            context: Some(pointerinjector::Context::View(context)),
378            target: Some(pointerinjector::Target::View(target)),
379            viewport,
380            dispatch_policy: Some(pointerinjector::DispatchPolicy::TopHitAndAncestorsInTarget),
381            scroll_v_range: None,
382            scroll_h_range: None,
383            buttons: None,
384            ..Default::default()
385        };
386
387        // Keep track of the injector.
388        self.mutable_state.borrow_mut().injectors.insert(touch_descriptor.device_id, device_proxy);
389
390        // Register the new injector.
391        self.injector_registry_proxy
392            .register(config, device_server)
393            .await
394            .context("Failed to register injector.")?;
395        log::info!("Registered injector with device id {:?}", touch_descriptor.device_id);
396
397        Ok(())
398    }
399
400    /// Converts the given touch event into a list of Scenic events.
401    ///
402    /// # Parameters
403    /// - `touch_event`: The touch event to send to Scenic.
404    /// - `touch_descriptor`: The descriptor for the device that sent the touch event.
405    /// - `event_time`: The time when the event was first recorded.
406    fn create_pointer_events(
407        &self,
408        touch_event: &mut touch_binding::TouchScreenEvent,
409        touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
410        event_time: zx::MonotonicInstant,
411    ) -> Vec<pointerinjector::Event> {
412        let ordered_phases = vec![
413            pointerinjector::EventPhase::Add,
414            pointerinjector::EventPhase::Change,
415            pointerinjector::EventPhase::Remove,
416        ];
417
418        let mut events: Vec<pointerinjector::Event> = vec![];
419        for phase in ordered_phases {
420            let contacts: Vec<touch_binding::TouchContact> = touch_event
421                .injector_contacts
422                .get(&phase)
423                .map_or(vec![], |contacts| contacts.to_owned());
424            let new_events = contacts.into_iter().map(|contact| {
425                Self::create_pointer_sample_event(
426                    phase,
427                    &contact,
428                    touch_descriptor,
429                    &self.display_size,
430                    event_time,
431                    touch_event.wake_lease.take(),
432                )
433            });
434            events.extend(new_events);
435        }
436
437        events
438    }
439
440    /// Injects the given events into Scenic.
441    ///
442    /// # Parameters
443    /// - `events`: The events to inject.
444    /// - `touch_descriptor`: The descriptor for the device that sent the touch event.
445    fn inject_pointer_events(
446        &self,
447        events: Vec<pointerinjector::Event>,
448        touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
449    ) -> Result<(), anyhow::Error> {
450        fuchsia_trace::duration!("input", "touch-inject-into-scenic");
451
452        let injector =
453            self.mutable_state.borrow().injectors.get(&touch_descriptor.device_id).cloned();
454        if let Some(injector) = injector {
455            let _ = injector.inject_events(events);
456            Ok(())
457        } else {
458            Err(anyhow::format_err!(
459                "No injector found for touch device {}.",
460                touch_descriptor.device_id
461            ))
462        }
463    }
464
465    /// Creates a [`fidl_fuchsia_ui_pointerinjector::Event`] representing the given touch contact.
466    ///
467    /// # Parameters
468    /// - `phase`: The phase of the touch contact.
469    /// - `contact`: The touch contact to create the event for.
470    /// - `touch_descriptor`: The device descriptor for the device that generated the event.
471    /// - `display_size`: The size of the associated touch display.
472    /// - `event_time`: The time in nanoseconds when the event was first recorded.
473    /// - `wake_lease`: The wake lease for this event.
474    fn create_pointer_sample_event(
475        phase: pointerinjector::EventPhase,
476        contact: &touch_binding::TouchContact,
477        touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
478        display_size: &Size,
479        event_time: zx::MonotonicInstant,
480        wake_lease: Option<zx::EventPair>,
481    ) -> pointerinjector::Event {
482        let position =
483            Self::display_coordinate_from_contact(&contact, &touch_descriptor, display_size);
484        let pointer_sample = pointerinjector::PointerSample {
485            pointer_id: Some(contact.id),
486            phase: Some(phase),
487            position_in_viewport: Some([position.x, position.y]),
488            scroll_v: None,
489            scroll_h: None,
490            pressed_buttons: None,
491            ..Default::default()
492        };
493        let data = pointerinjector::Data::PointerSample(pointer_sample);
494
495        let trace_flow_id = fuchsia_trace::Id::random();
496        let event = pointerinjector::Event {
497            timestamp: Some(event_time.into_nanos()),
498            data: Some(data),
499            trace_flow_id: Some(trace_flow_id.into()),
500            wake_lease,
501            ..Default::default()
502        };
503
504        fuchsia_trace::flow_begin!("input", "dispatch_event_to_scenic", trace_flow_id);
505
506        event
507    }
508
509    /// Converts an input event touch to a display coordinate, which is the coordinate space in
510    /// which Scenic handles events.
511    ///
512    /// The display coordinate is calculated by normalizing the contact position to the display
513    /// size. It does not account for the viewport position, which Scenic handles directly.
514    ///
515    /// # Parameters
516    /// - `contact`: The contact to get the display coordinate from.
517    /// - `touch_descriptor`: The device descriptor for the device that generated the event.
518    ///                       This is used to compute the device coordinate.
519    ///
520    /// # Returns
521    /// (x, y) coordinates.
522    fn display_coordinate_from_contact(
523        contact: &touch_binding::TouchContact,
524        touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
525        display_size: &Size,
526    ) -> Position {
527        if let Some(contact_descriptor) = touch_descriptor.contacts.first() {
528            // Scale the x position.
529            let x_range: f32 =
530                contact_descriptor.x_range.max as f32 - contact_descriptor.x_range.min as f32;
531            let x_wrt_range: f32 = contact.position.x - contact_descriptor.x_range.min as f32;
532            let x: f32 = (display_size.width * x_wrt_range) / x_range;
533
534            // Scale the y position.
535            let y_range: f32 =
536                contact_descriptor.y_range.max as f32 - contact_descriptor.y_range.min as f32;
537            let y_wrt_range: f32 = contact.position.y - contact_descriptor.y_range.min as f32;
538            let y: f32 = (display_size.height * y_wrt_range) / y_range;
539
540            Position { x, y }
541        } else {
542            return contact.position;
543        }
544    }
545
546    /// Watches for viewport updates from the scene manager.
547    pub async fn watch_viewport(self: Rc<Self>) {
548        let configuration_proxy = self.configuration_proxy.clone();
549        let mut viewport_stream = HangingGetStream::new(
550            configuration_proxy,
551            pointerinjector_config::SetupProxy::watch_viewport,
552        );
553        loop {
554            match viewport_stream.next().await {
555                Some(Ok(new_viewport)) => {
556                    // Update the viewport tracked by this handler.
557                    self.mutable_state.borrow_mut().viewport = Some(new_viewport.clone());
558
559                    // Update Scenic with the latest viewport.
560                    let injectors: Vec<pointerinjector::DeviceProxy> =
561                        self.mutable_state.borrow_mut().injectors.values().cloned().collect();
562                    for injector in injectors {
563                        let events = vec![pointerinjector::Event {
564                            timestamp: Some(fuchsia_async::MonotonicInstant::now().into_nanos()),
565                            data: Some(pointerinjector::Data::Viewport(new_viewport.clone())),
566                            trace_flow_id: Some(fuchsia_trace::Id::random().into()),
567                            ..Default::default()
568                        }];
569                        injector.inject_events(events).expect("Failed to inject updated viewport.");
570                    }
571                }
572                Some(Err(e)) => {
573                    self.metrics_logger.log_error(
574                        InputPipelineErrorMetricDimensionEvent::TouchInjectorErrorWhileReadingViewportUpdate,
575                        std::format!("Error while reading viewport update: {}", e));
576                    return;
577                }
578                None => {
579                    self.metrics_logger.log_error(
580                        InputPipelineErrorMetricDimensionEvent::TouchInjectorViewportUpdateStreamTerminatedUnexpectedly,
581                        "Viewport update stream terminated unexpectedly");
582                    return;
583                }
584            }
585        }
586    }
587
588    /// Creates a fidl_ui_input::TouchButtonsEvent from a touch_binding::TouchScreenEvent.
589    ///
590    /// # Parameters
591    /// - `event`: The TouchScreenEvent to create a TouchButtonsEvent from.
592    /// - `event_time`: The time when the event was first recorded.
593    /// - `touch_descriptor`: The descriptor of the new touch device.
594    fn create_touch_buttons_event(
595        event: &mut touch_binding::TouchScreenEvent,
596        event_time: zx::MonotonicInstant,
597        touch_descriptor: &touch_binding::TouchScreenDeviceDescriptor,
598    ) -> fidl_ui_input::TouchButtonsEvent {
599        let pressed_buttons = match event.pressed_buttons.len() {
600            0 => None,
601            _ => Some(
602                event
603                    .pressed_buttons
604                    .clone()
605                    .into_iter()
606                    .map(|button| match button {
607                        fidl_input_report::TouchButton::Palm => fidl_ui_input::TouchButton::Palm,
608                        fidl_input_report::TouchButton::SwipeUp => {
609                            fidl_ui_input::TouchButton::SwipeUp
610                        }
611                        fidl_input_report::TouchButton::SwipeLeft => {
612                            fidl_ui_input::TouchButton::SwipeLeft
613                        }
614                        fidl_input_report::TouchButton::SwipeRight => {
615                            fidl_ui_input::TouchButton::SwipeRight
616                        }
617                        fidl_input_report::TouchButton::SwipeDown => {
618                            fidl_ui_input::TouchButton::SwipeDown
619                        }
620                        fidl_input_report::TouchButton::__SourceBreaking { unknown_ordinal: n } => {
621                            fidl_ui_input::TouchButton::__SourceBreaking {
622                                unknown_ordinal: n as u32,
623                            }
624                        }
625                    })
626                    .collect::<Vec<_>>(),
627            ),
628        };
629        fidl_ui_input::TouchButtonsEvent {
630            event_time: Some(event_time),
631            device_info: Some(fidl_ui_input::TouchDeviceInfo {
632                id: Some(touch_descriptor.device_id),
633                ..Default::default()
634            }),
635            pressed_buttons,
636            wake_lease: event.wake_lease.take(),
637            ..Default::default()
638        }
639    }
640
641    /// Sends touch button events to touch button listeners.
642    ///
643    /// # Parameters
644    /// - `event`: The event to send to the listeners.
645    async fn send_event_to_listeners(self: &Rc<Self>, event: &fidl_ui_input::TouchButtonsEvent) {
646        let tracker = &self.mutable_state.borrow().send_event_task_tracker;
647
648        for (handle, listener) in &self.mutable_state.borrow().listeners {
649            let weak_handler = Rc::downgrade(&self);
650            let listener_clone = listener.clone();
651            let handle_clone = handle.clone();
652            let event_to_send = Self::clone_event(event);
653            let fut = async move {
654                match listener_clone.on_event(event_to_send).await {
655                    Ok(_) => {}
656                    Err(e) => {
657                        if let Some(handler) = weak_handler.upgrade() {
658                            handler.mutable_state.borrow_mut().listeners.remove(&handle_clone);
659                            log::info!(
660                                "Unregistering listener; unable to send TouchButtonsEvent: {:?}",
661                                e
662                            )
663                        }
664                    }
665                }
666            };
667
668            let metrics_logger_clone = self.metrics_logger.clone();
669            tracker.track(metrics_logger_clone, fasync::Task::local(fut));
670        }
671    }
672
673    // Add the listener to the registry.
674    ///
675    /// # Parameters
676    /// - `proxy`: A new listener proxy to send events to.
677    pub async fn register_listener_proxy(
678        self: &Rc<Self>,
679        proxy: fidl_ui_policy::TouchButtonsListenerProxy,
680    ) {
681        self.mutable_state
682            .borrow_mut()
683            .listeners
684            .insert(proxy.as_channel().as_handle_ref().raw_handle(), proxy.clone());
685
686        // Send the listener the last touch button event.
687        if let Some(event) = &self.mutable_state.borrow().last_button_event {
688            let event_to_send = Self::clone_event(event);
689            let fut = async move {
690                match proxy.on_event(event_to_send).await {
691                    Ok(_) => {}
692                    Err(e) => {
693                        log::info!("Failed to send touch buttons event to listener {:?}", e)
694                    }
695                }
696            };
697            let metrics_logger_clone = self.metrics_logger.clone();
698            self.mutable_state
699                .borrow()
700                .send_event_task_tracker
701                .track(metrics_logger_clone, fasync::Task::local(fut));
702        }
703    }
704}
705
706/// Maintains a collection of pending local [`Task`]s, allowing them to be dropped (and cancelled)
707/// en masse.
708#[derive(Debug)]
709pub struct LocalTaskTracker {
710    sender: mpsc::UnboundedSender<fasync::Task<()>>,
711    _receiver_task: fasync::Task<()>,
712}
713
714impl LocalTaskTracker {
715    pub fn new() -> Self {
716        let (sender, receiver) = mpsc::unbounded();
717        let receiver_task = fasync::Task::local(async move {
718            // Drop the tasks as they are completed.
719            receiver.for_each_concurrent(None, |task: fasync::Task<()>| task).await
720        });
721
722        Self { sender, _receiver_task: receiver_task }
723    }
724
725    /// Submits a new task to track.
726    pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: fasync::Task<()>) {
727        match self.sender.unbounded_send(task) {
728            Ok(_) => {}
729            // `Full` should never happen because this is unbounded.
730            // `Disconnected` might happen if the `Service` was dropped. However, it's not clear how
731            // to create such a race condition.
732            Err(e) => {
733                metrics_logger.log_error(
734                    InputPipelineErrorMetricDimensionEvent::TouchFailedToSendTouchScreenEvent,
735                    std::format!("Unexpected {e:?} while pushing task"),
736                );
737            }
738        };
739    }
740}
741
742#[cfg(test)]
743mod tests {
744    use super::*;
745    use crate::input_handler::BatchInputHandler;
746    use crate::testing_utilities::{
747        create_fake_input_event, create_touch_contact, create_touch_pointer_sample_event,
748        create_touch_screen_event, create_touch_screen_event_with_handled, create_touchpad_event,
749        get_touch_screen_device_descriptor,
750    };
751    use assert_matches::assert_matches;
752    use futures::{FutureExt, TryStreamExt};
753    use maplit::hashmap;
754    use pretty_assertions::assert_eq;
755    use std::collections::HashSet;
756    use std::convert::TryFrom as _;
757    use std::ops::Add;
758    use {
759        fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
760        fidl_fuchsia_ui_policy as fidl_ui_policy, fuchsia_async as fasync,
761    };
762
763    const TOUCH_ID: u32 = 1;
764    const DISPLAY_WIDTH: f32 = 100.0;
765    const DISPLAY_HEIGHT: f32 = 100.0;
766
767    struct TestFixtures {
768        touch_handler: Rc<TouchInjectorHandler>,
769        device_listener_proxy: fidl_ui_policy::DeviceListenerRegistryProxy,
770        injector_registry_request_stream: pointerinjector::RegistryRequestStream,
771        configuration_request_stream: pointerinjector_config::SetupRequestStream,
772        inspector: fuchsia_inspect::Inspector,
773        _test_node: fuchsia_inspect::Node,
774    }
775
776    fn spawn_device_listener_registry_server(
777        handler: Rc<TouchInjectorHandler>,
778    ) -> fidl_ui_policy::DeviceListenerRegistryProxy {
779        let (device_listener_proxy, mut device_listener_stream) =
780            fidl::endpoints::create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>(
781            );
782
783        fasync::Task::local(async move {
784            loop {
785                match device_listener_stream.try_next().await {
786                    Ok(Some(
787                        fidl_ui_policy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
788                            listener,
789                            responder,
790                        },
791                    )) => {
792                        handler.register_listener_proxy(listener.into_proxy()).await;
793                        let _ = responder.send();
794                    }
795                    Ok(Some(_)) => {
796                        panic!("Unexpected registration");
797                    }
798                    Ok(None) => {
799                        break;
800                    }
801                    Err(e) => {
802                        panic!("Error handling device listener registry request stream: {}", e);
803                    }
804                }
805            }
806        })
807        .detach();
808
809        device_listener_proxy
810    }
811
812    impl TestFixtures {
813        async fn new() -> Self {
814            let inspector = fuchsia_inspect::Inspector::default();
815            let test_node = inspector.root().create_child("test_node");
816            let (configuration_proxy, mut configuration_request_stream) =
817                fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
818            let (injector_registry_proxy, injector_registry_request_stream) =
819                fidl::endpoints::create_proxy_and_stream::<pointerinjector::RegistryMarker>();
820
821            let touch_handler_fut = TouchInjectorHandler::new_handler(
822                configuration_proxy,
823                injector_registry_proxy,
824                Size { width: DISPLAY_WIDTH, height: DISPLAY_HEIGHT },
825                &test_node,
826                metrics::MetricsLogger::default(),
827            );
828
829            let handle_initial_request_fut = async {
830                match configuration_request_stream.next().await {
831                    Some(Ok(pointerinjector_config::SetupRequest::GetViewRefs {
832                        responder,
833                        ..
834                    })) => {
835                        let context = fuchsia_scenic::ViewRefPair::new()
836                            .expect("Failed to create viewrefpair.")
837                            .view_ref;
838                        let target = fuchsia_scenic::ViewRefPair::new()
839                            .expect("Failed to create viewrefpair.")
840                            .view_ref;
841                        let _ = responder.send(context, target);
842                    }
843                    other => panic!("Expected GetViewRefs request, got {:?}", other),
844                }
845            };
846
847            let (touch_handler_res, _) =
848                futures::future::join(touch_handler_fut, handle_initial_request_fut).await;
849
850            let touch_handler = touch_handler_res.expect("Failed to create touch handler.");
851            let device_listener_proxy =
852                spawn_device_listener_registry_server(touch_handler.clone());
853
854            TestFixtures {
855                touch_handler,
856                device_listener_proxy,
857                injector_registry_request_stream,
858                configuration_request_stream,
859                inspector,
860                _test_node: test_node,
861            }
862        }
863    }
864
865    /// Returns an |input_device::InputDeviceDescriptor::Touchpad|.
866    fn get_touchpad_device_descriptor() -> input_device::InputDeviceDescriptor {
867        input_device::InputDeviceDescriptor::Touchpad(touch_binding::TouchpadDeviceDescriptor {
868            device_id: 1,
869            contacts: vec![touch_binding::ContactDeviceDescriptor {
870                x_range: fidl_input_report::Range { min: 0, max: 100 },
871                y_range: fidl_input_report::Range { min: 0, max: 100 },
872                x_unit: fidl_input_report::Unit {
873                    type_: fidl_input_report::UnitType::Meters,
874                    exponent: -6,
875                },
876                y_unit: fidl_input_report::Unit {
877                    type_: fidl_input_report::UnitType::Meters,
878                    exponent: -6,
879                },
880                pressure_range: None,
881                width_range: None,
882                height_range: None,
883            }],
884        })
885    }
886
887    /// Handles |fidl_fuchsia_pointerinjector::DeviceRequest|s by asserting the `injector_stream`
888    /// gets `expected_event`.
889    async fn handle_device_request_stream(
890        mut injector_stream: pointerinjector::DeviceRequestStream,
891        expected_event: pointerinjector::Event,
892    ) {
893        match injector_stream.next().await {
894            Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
895                panic!("DeviceRequest::Inject is deprecated.");
896            }
897            Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
898                assert_eq!(events.len(), 1);
899                assert_eq!(events[0].timestamp, expected_event.timestamp);
900                assert_eq!(events[0].data, expected_event.data);
901            }
902            Some(Err(e)) => panic!("FIDL error {}", e),
903            None => panic!("Expected another event."),
904        }
905    }
906
907    // Creates a |pointerinjector::Viewport|.
908    fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
909        pointerinjector::Viewport {
910            extents: Some([[min, min], [max, max]]),
911            viewport_to_context_transform: None,
912            ..Default::default()
913        }
914    }
915
916    #[fuchsia::test]
917    async fn events_with_pressed_buttons_are_sent_to_listener() {
918        let fixtures = TestFixtures::new().await;
919        let (listener, mut listener_stream) =
920            fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
921        fixtures
922            .device_listener_proxy
923            .register_touch_buttons_listener(listener)
924            .await
925            .expect("Failed to register listener.");
926
927        let descriptor = get_touch_screen_device_descriptor();
928        let event_time = zx::MonotonicInstant::get();
929        let input_event = create_touch_screen_event(hashmap! {}, event_time, &descriptor);
930
931        let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
932
933        let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
934            event_time: Some(event_time),
935            device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
936            ..Default::default()
937        };
938
939        assert_matches!(
940            listener_stream.next().await,
941            Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
942                event,
943                responder,
944            })) => {
945                assert_eq!(event, expected_touch_buttons_event);
946                let _ = responder.send();
947            }
948        );
949    }
950
951    #[fuchsia::test]
952    async fn events_with_contacts_are_not_sent_to_listener() {
953        let fixtures = TestFixtures::new().await;
954        let (listener, mut listener_stream) =
955            fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
956        fixtures
957            .device_listener_proxy
958            .register_touch_buttons_listener(listener)
959            .await
960            .expect("Failed to register listener.");
961
962        let descriptor = get_touch_screen_device_descriptor();
963        let event_time = zx::MonotonicInstant::get();
964        let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
965        let input_event = create_touch_screen_event(
966            hashmap! {
967                fidl_ui_input::PointerEventPhase::Add
968                    => vec![contact.clone()],
969            },
970            event_time,
971            &descriptor,
972        );
973
974        let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
975
976        assert!(listener_stream.next().now_or_never().is_none());
977    }
978
979    #[fuchsia::test]
980    async fn multiple_listeners_receive_pressed_button_events() {
981        let fixtures = TestFixtures::new().await;
982        let (first_listener, mut first_listener_stream) =
983            fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
984        let (second_listener, mut second_listener_stream) =
985            fidl::endpoints::create_request_stream::<fidl_ui_policy::TouchButtonsListenerMarker>();
986        fixtures
987            .device_listener_proxy
988            .register_touch_buttons_listener(first_listener)
989            .await
990            .expect("Failed to register listener.");
991        fixtures
992            .device_listener_proxy
993            .register_touch_buttons_listener(second_listener)
994            .await
995            .expect("Failed to register listener.");
996
997        let descriptor = get_touch_screen_device_descriptor();
998        let event_time = zx::MonotonicInstant::get();
999        let input_event = create_touch_screen_event(hashmap! {}, event_time, &descriptor);
1000
1001        let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1002
1003        let expected_touch_buttons_event = fidl_ui_input::TouchButtonsEvent {
1004            event_time: Some(event_time),
1005            device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1006            ..Default::default()
1007        };
1008
1009        assert_matches!(
1010            first_listener_stream.next().await,
1011            Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1012                event,
1013                responder,
1014            })) => {
1015                assert_eq!(event, expected_touch_buttons_event);
1016                let _ = responder.send();
1017            }
1018        );
1019        assert_matches!(
1020            second_listener_stream.next().await,
1021            Some(Ok(fidl_ui_policy::TouchButtonsListenerRequest::OnEvent {
1022                event,
1023                responder,
1024            })) => {
1025                assert_eq!(event, expected_touch_buttons_event);
1026                let _ = responder.send();
1027            }
1028        );
1029    }
1030
1031    // Tests that TouchInjectorHandler::watch_viewport() tracks viewport updates and notifies
1032    // injectors about said updates.
1033    #[fuchsia::test]
1034    async fn receives_viewport_updates() {
1035        let mut fixtures = TestFixtures::new().await;
1036
1037        // Add an injector.
1038        let (injector_device_proxy, mut injector_device_request_stream) =
1039            fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1040        fixtures
1041            .touch_handler
1042            .mutable_state
1043            .borrow_mut()
1044            .injectors
1045            .insert(1, injector_device_proxy);
1046
1047        // This nested block is used to bound the lifetime of `watch_viewport_fut`.
1048        {
1049            // Request a viewport update.
1050            let _watch_viewport_task =
1051                fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1052
1053            // Send a viewport update.
1054            match fixtures.configuration_request_stream.next().await {
1055                Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1056                    responder, ..
1057                })) => {
1058                    responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1059                }
1060                other => panic!("Received unexpected value: {:?}", other),
1061            };
1062
1063            // Check that the injector received an updated viewport
1064            match injector_device_request_stream.next().await {
1065                Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1066                    panic!("DeviceRequest::Inject is deprecated.");
1067                }
1068                Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1069                    assert_eq!(events.len(), 1);
1070                    assert!(events[0].data.is_some());
1071                    assert_eq!(
1072                        events[0].data,
1073                        Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1074                    );
1075                }
1076                other => panic!("Received unexpected value: {:?}", other),
1077            }
1078
1079            // Request viewport update.
1080            // Send viewport update.
1081            match fixtures.configuration_request_stream.next().await {
1082                Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
1083                    responder, ..
1084                })) => {
1085                    responder
1086                        .send(&create_viewport(100.0, 200.0))
1087                        .expect("Failed to send viewport.");
1088                }
1089                other => panic!("Received unexpected value: {:?}", other),
1090            };
1091
1092            // Check that the injector received an updated viewport
1093            match injector_device_request_stream.next().await {
1094                Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1095                    panic!("DeviceRequest::Inject is deprecated.");
1096                }
1097                Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1098                    assert_eq!(events.len(), 1);
1099                    assert!(events[0].data.is_some());
1100                    assert_eq!(
1101                        events[0].data,
1102                        Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
1103                    );
1104                }
1105                other => panic!("Received unexpected value: {:?}", other),
1106            }
1107        }
1108
1109        // Check the viewport on the handler is accurate.
1110        let expected_viewport = create_viewport(100.0, 200.0);
1111        assert_eq!(fixtures.touch_handler.mutable_state.borrow().viewport, Some(expected_viewport));
1112    }
1113
1114    // Tests that an add contact event is dropped without a viewport.
1115    #[fuchsia::test]
1116    async fn add_contact_drops_without_viewport() {
1117        let mut fixtures = TestFixtures::new().await;
1118
1119        // Create touch event.
1120        let event_time = zx::MonotonicInstant::get();
1121        let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1122        let descriptor = get_touch_screen_device_descriptor();
1123        let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1124            hashmap! {
1125                fidl_ui_input::PointerEventPhase::Add
1126                    => vec![contact.clone()],
1127            },
1128            event_time,
1129            &descriptor,
1130        ))
1131        .unwrap();
1132
1133        // Clear the viewport that was set during test fixture setup.
1134        fixtures.touch_handler.mutable_state.borrow_mut().viewport = None;
1135
1136        // Try to handle the event.
1137        let _ = fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]).await;
1138
1139        // Injector should not receive anything because the handler has no viewport.
1140        assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1141    }
1142
1143    // Tests that an add contact event is handled correctly with a viewport.
1144    #[fuchsia::test]
1145    async fn add_contact_succeeds_with_viewport() {
1146        let mut fixtures = TestFixtures::new().await;
1147
1148        // Add an injector.
1149        let (injector_device_proxy, mut injector_device_request_stream) =
1150            fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1151        fixtures
1152            .touch_handler
1153            .mutable_state
1154            .borrow_mut()
1155            .injectors
1156            .insert(1, injector_device_proxy);
1157
1158        // Request a viewport update.
1159        let _watch_viewport_task =
1160            fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1161
1162        // Send a viewport update.
1163        match fixtures.configuration_request_stream.next().await {
1164            Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1165                responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1166            }
1167            other => panic!("Received unexpected value: {:?}", other),
1168        };
1169
1170        // Check that the injector received an updated viewport
1171        match injector_device_request_stream.next().await {
1172            Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1173                panic!("DeviceRequest::Inject is deprecated.");
1174            }
1175            Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1176                assert_eq!(events.len(), 1);
1177                assert!(events[0].data.is_some());
1178                assert_eq!(
1179                    events[0].data,
1180                    Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1181                );
1182            }
1183            other => panic!("Received unexpected value: {:?}", other),
1184        }
1185
1186        // Create touch event.
1187        let event_time = zx::MonotonicInstant::get();
1188        let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1189        let descriptor = get_touch_screen_device_descriptor();
1190        let input_event = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1191            hashmap! {
1192                fidl_ui_input::PointerEventPhase::Add
1193                    => vec![contact.clone()],
1194            },
1195            event_time,
1196            &descriptor,
1197        ))
1198        .unwrap();
1199
1200        // Handle event.
1201        let handle_event_fut =
1202            fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1203
1204        // Declare expected event.
1205        let expected_event = create_touch_pointer_sample_event(
1206            pointerinjector::EventPhase::Add,
1207            &contact,
1208            Position { x: 20.0, y: 40.0 },
1209            event_time,
1210        );
1211
1212        // Await all futures concurrently. If this completes, then the touch event was handled and
1213        // matches `expected_event`.
1214        let device_fut =
1215            handle_device_request_stream(injector_device_request_stream, expected_event);
1216        let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1217
1218        // No unhandled events.
1219        assert_matches!(
1220            handle_result.as_slice(),
1221            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1222        );
1223    }
1224
1225    // Tests that an add touchpad contact event with viewport is unhandled and not send to scenic.
1226    #[fuchsia::test]
1227    async fn add_touchpad_contact_with_viewport() {
1228        let mut fixtures = TestFixtures::new().await;
1229
1230        // Add an injector.
1231        let (injector_device_proxy, mut injector_device_request_stream) =
1232            fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1233        fixtures
1234            .touch_handler
1235            .mutable_state
1236            .borrow_mut()
1237            .injectors
1238            .insert(1, injector_device_proxy);
1239
1240        // Request a viewport update.
1241        let _watch_viewport_task =
1242            fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1243
1244        // Send a viewport update.
1245        match fixtures.configuration_request_stream.next().await {
1246            Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1247                responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1248            }
1249            other => panic!("Received unexpected value: {:?}", other),
1250        };
1251
1252        // Check that the injector received an updated viewport
1253        match injector_device_request_stream.next().await {
1254            Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
1255                panic!("DeviceRequest::Inject is deprecated.");
1256            }
1257            Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1258                assert_eq!(events.len(), 1);
1259                assert!(events[0].data.is_some());
1260                assert_eq!(
1261                    events[0].data,
1262                    Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1263                );
1264            }
1265            other => panic!("Received unexpected value: {:?}", other),
1266        }
1267
1268        // Create touch event.
1269        let event_time = zx::MonotonicInstant::get();
1270        let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1271        let descriptor = get_touchpad_device_descriptor();
1272        let input_event = input_device::UnhandledInputEvent::try_from(create_touchpad_event(
1273            vec![contact.clone()],
1274            HashSet::new(),
1275            event_time,
1276            &descriptor,
1277        ))
1278        .unwrap();
1279
1280        // Handle event.
1281        let handle_event_fut =
1282            fixtures.touch_handler.clone().handle_input_events(vec![input_event.into()]);
1283
1284        let handle_result = handle_event_fut.await;
1285
1286        // Event is not handled.
1287        assert_matches!(
1288            handle_result.as_slice(),
1289            [input_device::InputEvent { handled: input_device::Handled::No, .. }]
1290        );
1291
1292        // Injector should not receive anything because the handler does not support touchpad yet.
1293        assert!(fixtures.injector_registry_request_stream.next().now_or_never().is_none());
1294    }
1295
1296    #[fuchsia::test(allow_stalls = false)]
1297    async fn touch_injector_handler_initialized_with_inspect_node() {
1298        let fixtures = TestFixtures::new().await;
1299        diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1300            test_node: {
1301                touch_injector_handler: {
1302                    events_received_count: 0u64,
1303                    events_handled_count: 0u64,
1304                    last_received_timestamp_ns: 0u64,
1305                    "fuchsia.inspect.Health": {
1306                        status: "STARTING_UP",
1307                        // Timestamp value is unpredictable and not relevant in this context,
1308                        // so we only assert that the property is present.
1309                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
1310                    },
1311                }
1312            }
1313        });
1314    }
1315
1316    #[fuchsia::test(allow_stalls = false)]
1317    async fn touch_injector_handler_inspect_counts_events() {
1318        let fixtures = TestFixtures::new().await;
1319
1320        let contact = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1321        let descriptor = get_touch_screen_device_descriptor();
1322        let event_time1 = zx::MonotonicInstant::get();
1323        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1324        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1325
1326        let input_events = vec![
1327            create_touch_screen_event(
1328                hashmap! {
1329                    fidl_ui_input::PointerEventPhase::Add
1330                        => vec![contact.clone()],
1331                },
1332                event_time1,
1333                &descriptor,
1334            ),
1335            create_touch_screen_event(
1336                hashmap! {
1337                    fidl_ui_input::PointerEventPhase::Move
1338                        => vec![contact.clone()],
1339                },
1340                event_time2,
1341                &descriptor,
1342            ),
1343            // Should not count non-touch input event.
1344            create_fake_input_event(event_time2),
1345            // Should not count received event that has already been handled.
1346            create_touch_screen_event_with_handled(
1347                hashmap! {
1348                    fidl_ui_input::PointerEventPhase::Move
1349                        => vec![contact.clone()],
1350                },
1351                event_time2,
1352                &descriptor,
1353                input_device::Handled::Yes,
1354            ),
1355            create_touch_screen_event(
1356                hashmap! {
1357                    fidl_ui_input::PointerEventPhase::Remove
1358                        => vec![contact.clone()],
1359                },
1360                event_time3,
1361                &descriptor,
1362            ),
1363        ];
1364
1365        for input_event in input_events {
1366            fixtures.touch_handler.clone().handle_input_events(vec![input_event]).await;
1367        }
1368
1369        let last_received_event_time: u64 = event_time3.into_nanos().try_into().unwrap();
1370
1371        diagnostics_assertions::assert_data_tree!(fixtures.inspector, root: {
1372            test_node: {
1373                touch_injector_handler: {
1374                    events_received_count: 3u64,
1375                    events_handled_count: 3u64,
1376                    last_received_timestamp_ns: last_received_event_time,
1377                    "fuchsia.inspect.Health": {
1378                        status: "STARTING_UP",
1379                        // Timestamp value is unpredictable and not relevant in this context,
1380                        // so we only assert that the property is present.
1381                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
1382                    },
1383                }
1384            }
1385        });
1386    }
1387
1388    #[fuchsia::test]
1389    async fn clone_event_with_lease_duplicates_lease() {
1390        let (event_pair, _) = fidl::EventPair::create();
1391        let event = fidl_ui_input::TouchButtonsEvent {
1392            event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1393            device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1394            pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1395            wake_lease: Some(event_pair),
1396            ..Default::default()
1397        };
1398        let cloned_event = TouchInjectorHandler::clone_event(&event);
1399        assert_eq!(event.event_time, cloned_event.event_time);
1400        assert_eq!(event.device_info, cloned_event.device_info);
1401        assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1402        assert!(event.wake_lease.is_some());
1403        assert!(cloned_event.wake_lease.is_some());
1404        assert_ne!(
1405            event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
1406            cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
1407        );
1408    }
1409
1410    #[fuchsia::test]
1411    async fn clone_event_without_lease_has_no_lease() {
1412        let event = fidl_ui_input::TouchButtonsEvent {
1413            event_time: Some(zx::MonotonicInstant::from_nanos(1)),
1414            device_info: Some(fidl_ui_input::TouchDeviceInfo { id: Some(1), ..Default::default() }),
1415            pressed_buttons: Some(vec![fidl_ui_input::TouchButton::Palm]),
1416            wake_lease: None,
1417            ..Default::default()
1418        };
1419        let cloned_event = TouchInjectorHandler::clone_event(&event);
1420        assert_eq!(event.event_time, cloned_event.event_time);
1421        assert_eq!(event.device_info, cloned_event.device_info);
1422        assert_eq!(event.pressed_buttons, cloned_event.pressed_buttons);
1423        assert!(event.wake_lease.is_none());
1424        assert!(cloned_event.wake_lease.is_none());
1425    }
1426
1427    #[fuchsia::test]
1428    async fn handle_input_events_batches_events() {
1429        let mut fixtures = TestFixtures::new().await;
1430
1431        // Add an injector.
1432        let (injector_device_proxy, mut injector_device_request_stream) =
1433            fidl::endpoints::create_proxy_and_stream::<pointerinjector::DeviceMarker>();
1434        fixtures
1435            .touch_handler
1436            .mutable_state
1437            .borrow_mut()
1438            .injectors
1439            .insert(1, injector_device_proxy);
1440
1441        // Request a viewport update.
1442        let _watch_viewport_task =
1443            fasync::Task::local(fixtures.touch_handler.clone().watch_viewport());
1444
1445        // Send a viewport update.
1446        match fixtures.configuration_request_stream.next().await {
1447            Some(Ok(pointerinjector_config::SetupRequest::WatchViewport { responder, .. })) => {
1448                responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
1449            }
1450            other => panic!("Received unexpected value: {:?}", other),
1451        };
1452
1453        // Check that the injector received an updated viewport
1454        match injector_device_request_stream.next().await {
1455            Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1456                assert_eq!(events.len(), 1);
1457                assert!(events[0].data.is_some());
1458                assert_eq!(
1459                    events[0].data,
1460                    Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
1461                );
1462            }
1463            other => panic!("Received unexpected value: {:?}", other),
1464        }
1465
1466        // Create two touch events to be batched.
1467        let event_time1 = zx::MonotonicInstant::get();
1468        let contact1 = create_touch_contact(TOUCH_ID, Position { x: 20.0, y: 40.0 });
1469        let descriptor = get_touch_screen_device_descriptor();
1470        let input_event1 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1471            hashmap! {
1472                fidl_ui_input::PointerEventPhase::Add
1473                    => vec![contact1.clone()],
1474            },
1475            event_time1,
1476            &descriptor,
1477        ))
1478        .unwrap();
1479
1480        let event_time2 = event_time1 + zx::MonotonicDuration::from_millis(10);
1481        let contact2 = create_touch_contact(TOUCH_ID, Position { x: 25.0, y: 45.0 });
1482        let input_event2 = input_device::UnhandledInputEvent::try_from(create_touch_screen_event(
1483            hashmap! {
1484                fidl_ui_input::PointerEventPhase::Move
1485                    => vec![contact2.clone()],
1486            },
1487            event_time2,
1488            &descriptor,
1489        ))
1490        .unwrap();
1491
1492        // Handle events.
1493        let handle_event_fut = fixtures
1494            .touch_handler
1495            .clone()
1496            .handle_input_events(vec![input_event1.into(), input_event2.into()]);
1497
1498        // Declare expected events.
1499        let expected_event1 = create_touch_pointer_sample_event(
1500            pointerinjector::EventPhase::Add,
1501            &contact1,
1502            Position { x: 20.0, y: 40.0 },
1503            event_time1,
1504        );
1505        let expected_event2 = create_touch_pointer_sample_event(
1506            pointerinjector::EventPhase::Change,
1507            &contact2,
1508            Position { x: 25.0, y: 45.0 },
1509            event_time2,
1510        );
1511
1512        let device_fut = async move {
1513            match injector_device_request_stream.next().await {
1514                Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
1515                    assert_eq!(events.len(), 2);
1516                    assert_eq!(events[0].timestamp, expected_event1.timestamp);
1517                    assert_eq!(events[0].data, expected_event1.data);
1518                    assert_eq!(events[1].timestamp, expected_event2.timestamp);
1519                    assert_eq!(events[1].data, expected_event2.data);
1520                }
1521                other => panic!("Received unexpected value: {:?}", other),
1522            }
1523        };
1524
1525        let (handle_result, _) = futures::future::join(handle_event_fut, device_fut).await;
1526
1527        // Verify events were marked handled.
1528        assert_matches!(
1529            handle_result.as_slice(),
1530            [
1531                input_device::InputEvent { handled: input_device::Handled::Yes, .. },
1532                input_device::InputEvent { handled: input_device::Handled::Yes, .. }
1533            ]
1534        );
1535    }
1536}