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