Skip to main content

input_pipeline/
mouse_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)]
6
7use crate::input_handler::{Handler, InputHandler, InputHandlerStatus};
8use crate::utils::{self, CursorMessage, Position, Size};
9use crate::{
10    Dispatcher, Incoming, MonotonicInstant, Transport, input_device, metrics, mouse_binding,
11};
12use anyhow::{Context, Error, Result, anyhow};
13use async_trait::async_trait;
14use async_utils::hanging_get::client::HangingGetStream;
15use fidl_fuchsia_input_report::Range;
16use fidl_fuchsia_ui_pointerinjector_configuration as pointerinjector_config;
17use fidl_next_fuchsia_ui_pointerinjector as pointerinjector;
18use fuchsia_inspect::health::Reporter;
19use futures::SinkExt;
20use futures::channel::mpsc::Sender;
21use futures::stream::StreamExt;
22use metrics_registry::*;
23use std::cell::{Ref, RefCell, RefMut};
24use std::collections::HashMap;
25use std::rc::Rc;
26
27/// Each mm of physical movement by the mouse translates to the cursor moving
28/// on the display by 10 logical pixels.
29/// Because pointer_display_scale_handler scaled for device pixel ratio, here
30/// only need to apply mm * logical pixel scale factor to get physical pixel.
31/// TODO(https://fxbug.dev/42066909): need to revisit this
32/// 1. allow users to adjust how fast the mouse move.
33/// 2. allow different value per monitor model.
34const MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL: f32 = 10.0;
35
36/// A [`MouseInjectorHandler`] parses mouse events and forwards them to Scenic through the
37/// fidl_fuchsia_pointerinjector protocols.
38pub struct MouseInjectorHandler {
39    /// The mutable fields of this handler.
40    mutable_state: RefCell<MutableState>,
41
42    /// The scope and coordinate system of injection.
43    /// See [`fidl_fuchsia_pointerinjector::Context`] for more details.
44    context_view_ref: fidl_fuchsia_ui_views::ViewRef,
45
46    /// The region where dispatch is attempted for injected events.
47    /// See [`fidl_fuchsia_pointerinjector::Target`] for more details.
48    target_view_ref: fidl_fuchsia_ui_views::ViewRef,
49
50    /// The maximum position sent to clients, used to bound relative movements
51    /// and scale absolute positions from device coordinates.
52    max_position: Position,
53
54    /// The FIDL proxy to register new injectors.
55    injector_registry_proxy: fidl_next::Client<pointerinjector::Registry, Transport>,
56
57    /// The FIDL proxy used to get configuration details for pointer injection.
58    configuration_proxy: pointerinjector_config::SetupProxy,
59
60    /// The inventory of this handler's Inspect status.
61    pub inspect_status: InputHandlerStatus,
62
63    metrics_logger: metrics::MetricsLogger,
64}
65
66struct MutableState {
67    /// A rectangular region that directs injected events into a target.
68    /// See fidl_fuchsia_pointerinjector::Viewport for more details.
69    viewport: Option<pointerinjector::Viewport>,
70
71    /// The injectors registered with Scenic, indexed by their device ids.
72    injectors: HashMap<u32, fidl_next::Client<pointerinjector::Device, Transport>>,
73
74    /// The current position.
75    current_position: Position,
76
77    /// A [`Sender`] used to communicate the current cursor state.
78    cursor_message_sender: Sender<CursorMessage>,
79}
80
81impl Handler for MouseInjectorHandler {
82    fn set_handler_healthy(self: std::rc::Rc<Self>) {
83        self.inspect_status.health_node.borrow_mut().set_ok();
84    }
85
86    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
87        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
88    }
89
90    fn get_name(&self) -> &'static str {
91        "MouseInjectorHandler"
92    }
93
94    fn interest(&self) -> Vec<input_device::InputEventType> {
95        vec![input_device::InputEventType::Mouse]
96    }
97}
98
99#[async_trait(?Send)]
100impl InputHandler for MouseInjectorHandler {
101    async fn handle_input_event(
102        self: Rc<Self>,
103        mut input_event: input_device::InputEvent,
104    ) -> Vec<input_device::InputEvent> {
105        fuchsia_trace::duration!("input", "mouse_injector_handler");
106        match input_event {
107            input_device::InputEvent {
108                device_event: input_device::InputDeviceEvent::Mouse(ref mouse_event),
109                device_descriptor:
110                    input_device::InputDeviceDescriptor::Mouse(ref mouse_device_descriptor),
111                event_time,
112                handled: input_device::Handled::No,
113                trace_id,
114            } => {
115                fuchsia_trace::duration!("input", "mouse_injector_handler[processing]");
116                let trace_id = match trace_id {
117                    Some(id) => {
118                        fuchsia_trace::flow_step!("input", "event_in_input_pipeline", id.into());
119                        id
120                    }
121                    None => fuchsia_trace::Id::random(),
122                };
123
124                self.inspect_status.count_received_event(&event_time);
125                // TODO(https://fxbug.dev/42171756): Investigate latency introduced by waiting for update_cursor_renderer
126                if let Err(e) =
127                    self.update_cursor_renderer(mouse_event, &mouse_device_descriptor).await
128                {
129                    self.metrics_logger.log_error(
130                        InputPipelineErrorMetricDimensionEvent::MouseInjectorUpdateCursorRendererFailed,
131                        std::format!("update_cursor_renderer failed: {}", e));
132                }
133
134                // Create a new injector if this is the first time seeing device_id.
135                if let Err(e) = self
136                    .ensure_injector_registered(&mouse_event, &mouse_device_descriptor, event_time)
137                    .await
138                {
139                    self.metrics_logger.log_error(
140                        InputPipelineErrorMetricDimensionEvent::MouseInjectorEnsureInjectorRegisteredFailed,
141                        std::format!("ensure_injector_registered failed: {}", e));
142                }
143
144                // Handle the event.
145                if let Err(e) = self
146                    .send_event_to_scenic(
147                        &mouse_event,
148                        &mouse_device_descriptor,
149                        event_time,
150                        trace_id.into(),
151                    )
152                    .await
153                {
154                    self.metrics_logger.log_error(
155                        InputPipelineErrorMetricDimensionEvent::MouseInjectorSendEventToScenicFailed,
156                        std::format!("send_event_to_scenic failed: {}", e));
157                }
158
159                // Consume the input event.
160                input_event.handled = input_device::Handled::Yes;
161                self.inspect_status.count_handled_event();
162            }
163            _ => {
164                self.metrics_logger.log_error(
165                    InputPipelineErrorMetricDimensionEvent::HandlerReceivedUninterestedEvent,
166                    std::format!(
167                        "{} uninterested input event: {:?}",
168                        self.get_name(),
169                        input_event.get_event_type()
170                    ),
171                );
172            }
173        }
174        vec![input_event]
175    }
176}
177
178impl MouseInjectorHandler {
179    /// Creates a new mouse handler that holds mouse pointer injectors.
180    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
181    /// Example:
182    /// let handler = MouseInjectorHandler::new(display_size).await?;
183    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
184    ///
185    /// # Parameters
186    /// - `display_size`: The size of the associated display.
187    /// - `cursor_message_sender`: A [`Sender`] used to communicate the current cursor state.
188    ///
189    /// # Errors
190    /// If unable to connect to pointerinjector protocols.
191    pub async fn new(
192        incoming: &Incoming,
193        display_size: Size,
194        cursor_message_sender: Sender<CursorMessage>,
195        input_handlers_node: &fuchsia_inspect::Node,
196        metrics_logger: metrics::MetricsLogger,
197    ) -> Result<Rc<Self>, Error> {
198        let configuration_proxy =
199            incoming.connect_protocol::<pointerinjector_config::SetupProxy>()?;
200        let injector_registry_proxy =
201            incoming.connect_protocol_next::<pointerinjector::Registry>()?.spawn();
202
203        Self::new_handler(
204            configuration_proxy,
205            injector_registry_proxy,
206            display_size,
207            cursor_message_sender,
208            input_handlers_node,
209            metrics_logger,
210        )
211        .await
212    }
213
214    /// Creates a new mouse handler that holds mouse pointer injectors.
215    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
216    /// Example:
217    /// let handler = MouseInjectorHandler::new_with_config_proxy(config_proxy, 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    /// - `display_size`: The size of the associated display.
224    /// - `cursor_message_sender`: A [`Sender`] used to communicate the current cursor state.
225    ///
226    /// # Errors
227    /// If unable to get injection view refs from `configuration_proxy`.
228    /// If unable to connect to pointerinjector Registry protocol.
229    pub async fn new_with_config_proxy(
230        incoming: &Incoming,
231        configuration_proxy: pointerinjector_config::SetupProxy,
232        display_size: Size,
233        cursor_message_sender: Sender<CursorMessage>,
234        input_handlers_node: &fuchsia_inspect::Node,
235        metrics_logger: metrics::MetricsLogger,
236    ) -> Result<Rc<Self>, Error> {
237        let injector_registry_proxy =
238            incoming.connect_protocol_next::<pointerinjector::Registry>()?.spawn();
239        Self::new_handler(
240            configuration_proxy,
241            injector_registry_proxy,
242            display_size,
243            cursor_message_sender,
244            input_handlers_node,
245            metrics_logger,
246        )
247        .await
248    }
249
250    fn inner(&self) -> Ref<'_, MutableState> {
251        self.mutable_state.borrow()
252    }
253
254    fn inner_mut(&self) -> RefMut<'_, MutableState> {
255        self.mutable_state.borrow_mut()
256    }
257
258    /// Creates a new mouse handler that holds mouse pointer injectors.
259    /// The caller is expected to spawn a task to continually watch for updates to the viewport.
260    /// Example:
261    /// let handler = MouseInjectorHandler::new_handler(None, None, display_size).await?;
262    /// fasync::Task::local(handler.clone().watch_viewport()).detach();
263    ///
264    /// # Parameters
265    /// - `configuration_proxy`: A proxy used to get configuration details for pointer
266    ///    injection.
267    /// - `injector_registry_proxy`: A proxy used to register new pointer injectors.
268    /// - `display_size`: The size of the associated display.
269    /// - `cursor_message_sender`: A [`Sender`] used to communicate the current cursor state.
270    ///
271    /// # Errors
272    /// If unable to get injection view refs from `configuration_proxy`.
273    async fn new_handler(
274        configuration_proxy: pointerinjector_config::SetupProxy,
275        injector_registry_proxy: fidl_next::Client<pointerinjector::Registry, Transport>,
276        display_size: Size,
277        cursor_message_sender: Sender<CursorMessage>,
278        input_handlers_node: &fuchsia_inspect::Node,
279        metrics_logger: metrics::MetricsLogger,
280    ) -> Result<Rc<Self>, Error> {
281        // Get the context and target views to inject into.
282        let (context_view_ref, target_view_ref) = configuration_proxy.get_view_refs().await?;
283        let inspect_status = InputHandlerStatus::new(
284            input_handlers_node,
285            "mouse_injector_handler",
286            /* generates_events */ false,
287        );
288        let handler = Rc::new(Self {
289            mutable_state: RefCell::new(MutableState {
290                viewport: None,
291                injectors: HashMap::new(),
292                // Initially centered.
293                current_position: Position {
294                    x: display_size.width / 2.0,
295                    y: display_size.height / 2.0,
296                },
297                cursor_message_sender,
298            }),
299            context_view_ref,
300            target_view_ref,
301            max_position: Position { x: display_size.width, y: display_size.height },
302            injector_registry_proxy,
303            configuration_proxy,
304            inspect_status,
305            metrics_logger,
306        });
307
308        Ok(handler)
309    }
310
311    /// Adds a new pointer injector and tracks it in `self.injectors` if one doesn't exist at
312    /// `mouse_descriptor.device_id`.
313    ///
314    /// # Parameters
315    /// - `mouse_event`: The mouse event to send to Scenic.
316    /// - `mouse_descriptor`: The descriptor for the device that sent the mouse event.
317    /// - `event_time`: The time in nanoseconds when the event was first recorded.
318    async fn ensure_injector_registered(
319        self: &Rc<Self>,
320        mouse_event: &mouse_binding::MouseEvent,
321        mouse_descriptor: &mouse_binding::MouseDeviceDescriptor,
322        event_time: zx::MonotonicInstant,
323    ) -> Result<(), anyhow::Error> {
324        if self.inner().injectors.contains_key(&mouse_descriptor.device_id) {
325            return Ok(());
326        }
327
328        // Create a new injector.
329        let (device_proxy, device_server) =
330            fidl_next::fuchsia::create_channel::<pointerinjector::Device>();
331        let device_proxy = Dispatcher::client_from_zx_channel(device_proxy).spawn();
332        let context = fuchsia_scenic::duplicate_view_ref(&self.context_view_ref)
333            .context("Failed to duplicate context view ref.")?;
334        let context = fidl_next_fuchsia_ui_views::ViewRef { reference: context.reference };
335        let target = fuchsia_scenic::duplicate_view_ref(&self.target_view_ref)
336            .context("Failed to duplicate target view ref.")?;
337        let target = fidl_next_fuchsia_ui_views::ViewRef { reference: target.reference };
338
339        let viewport = self.inner().viewport.clone();
340        let config = pointerinjector::Config {
341            device_id: Some(mouse_descriptor.device_id),
342            device_type: Some(pointerinjector::DeviceType::Mouse),
343            context: Some(pointerinjector::Context::View(context)),
344            target: Some(pointerinjector::Target::View(target)),
345            viewport,
346            dispatch_policy: Some(pointerinjector::DispatchPolicy::MouseHoverAndLatchInTarget),
347            scroll_v_range: utils::axis_to_next(mouse_descriptor.wheel_v_range.as_ref()),
348            scroll_h_range: utils::axis_to_next(mouse_descriptor.wheel_h_range.as_ref()),
349            buttons: mouse_descriptor.buttons.clone(),
350            ..Default::default()
351        };
352
353        // Register the new injector.
354        self.injector_registry_proxy
355            .register(config, device_server)
356            .await
357            .context("Failed to register injector.")?;
358        log::info!("Registered injector with device id {:?}", mouse_descriptor.device_id);
359
360        // Keep track of the injector.
361        self.inner_mut().injectors.insert(mouse_descriptor.device_id, device_proxy.clone());
362
363        // Inject ADD event the first time a MouseDevice is seen.
364        let events_to_send = vec![self.create_pointer_sample_event(
365            mouse_event,
366            event_time,
367            pointerinjector::EventPhase::Add,
368            self.inner().current_position,
369            None,
370            None,
371        )];
372        device_proxy
373            .inject_events(events_to_send)
374            .send_immediately()
375            .context("Failed to ADD new MouseDevice.")?;
376
377        Ok(())
378    }
379
380    /// Updates the current cursor position according to the received mouse event.
381    ///
382    /// The updated cursor state is sent via `self.inner.cursor_message_sender` to a client
383    /// that renders the cursor on-screen.
384    ///
385    /// If there is no movement, the location is not sent.
386    ///
387    /// # Parameters
388    /// - `mouse_event`: The mouse event to use to update the cursor location.
389    /// - `mouse_descriptor`: The descriptor for the input device generating the input reports.
390    async fn update_cursor_renderer(
391        &self,
392        mouse_event: &mouse_binding::MouseEvent,
393        mouse_descriptor: &mouse_binding::MouseDeviceDescriptor,
394    ) -> Result<(), anyhow::Error> {
395        let mut new_position = match (mouse_event.location, mouse_descriptor) {
396            (
397                mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
398                    millimeters,
399                }),
400                _,
401            ) => {
402                self.inner().current_position
403                    + self.relative_movement_mm_to_phyical_pixel(millimeters)
404            }
405            (
406                mouse_binding::MouseLocation::Absolute(position),
407                mouse_binding::MouseDeviceDescriptor {
408                    absolute_x_range: Some(x_range),
409                    absolute_y_range: Some(y_range),
410                    ..
411                },
412            ) => self.scale_absolute_position(&position, &x_range, &y_range),
413            (mouse_binding::MouseLocation::Absolute(_), _) => {
414                return Err(anyhow!(
415                    "Received an Absolute mouse location without absolute device ranges."
416                ));
417            }
418        };
419        Position::clamp(&mut new_position, Position::zero(), self.max_position);
420        self.inner_mut().current_position = new_position;
421
422        let mut cursor_message_sender = self.inner().cursor_message_sender.clone();
423        cursor_message_sender
424            .send(CursorMessage::SetPosition(new_position))
425            .await
426            .context("Failed to send current mouse position to cursor renderer")?;
427
428        Ok(())
429    }
430
431    /// Returns an absolute cursor position scaled from device coordinates to the handler's
432    /// max position.
433    ///
434    /// # Parameters
435    /// - `position`: Absolute cursor position in device coordinates.
436    /// - `x_range`: The range of possible x values of absolute mouse positions.
437    /// - `y_range`: The range of possible y values of absolute mouse positions.
438    fn scale_absolute_position(
439        &self,
440        position: &Position,
441        x_range: &Range,
442        y_range: &Range,
443    ) -> Position {
444        let range_min = Position { x: x_range.min as f32, y: y_range.min as f32 };
445        let range_max = Position { x: x_range.max as f32, y: y_range.max as f32 };
446        self.max_position * ((*position - range_min) / (range_max - range_min))
447    }
448
449    /// Sends the given event to Scenic.
450    ///
451    /// # Parameters
452    /// - `mouse_event`: The mouse event to send to Scenic.
453    /// - `mouse_descriptor`: The descriptor for the device that sent the mouse event.
454    /// - `event_time`: The time in nanoseconds when the event was first recorded.
455    async fn send_event_to_scenic(
456        &self,
457        mouse_event: &mouse_binding::MouseEvent,
458        mouse_descriptor: &mouse_binding::MouseDeviceDescriptor,
459        event_time: zx::MonotonicInstant,
460        tracing_id: u64,
461    ) -> Result<(), anyhow::Error> {
462        let injector = self.inner().injectors.get(&mouse_descriptor.device_id).cloned();
463        if let Some(injector) = injector {
464            let relative_motion = match mouse_event.location {
465                mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
466                    millimeters: offset_mm,
467                }) if mouse_event.phase == mouse_binding::MousePhase::Move => {
468                    let offset = self.relative_movement_mm_to_phyical_pixel(offset_mm);
469                    Some([offset.x, offset.y])
470                }
471                _ => None,
472            };
473            let events_to_send = vec![self.create_pointer_sample_event(
474                mouse_event,
475                event_time,
476                pointerinjector::EventPhase::Change,
477                self.inner().current_position,
478                relative_motion,
479                Some(tracing_id),
480            )];
481
482            fuchsia_trace::flow_begin!("input", "dispatch_event_to_scenic", tracing_id.into());
483
484            _ = injector.inject_events(events_to_send).send_immediately();
485
486            Ok(())
487        } else {
488            Err(anyhow::format_err!(
489                "No injector found for mouse device {}.",
490                mouse_descriptor.device_id
491            ))
492        }
493    }
494
495    /// Creates a [`fidl_fuchsia_ui_pointerinjector::Event`] representing the given MouseEvent.
496    ///
497    /// # Parameters
498    /// - `mouse_event`: The mouse event to send to Scenic.
499    /// - `event_time`: The time in nanoseconds when the event was first recorded.
500    /// - `phase`: The EventPhase to send to Scenic.
501    /// - `current_position`: The current cursor position.
502    /// - `relative_motion`: The relative motion to send to Scenic.
503    fn create_pointer_sample_event(
504        &self,
505        mouse_event: &mouse_binding::MouseEvent,
506        event_time: zx::MonotonicInstant,
507        phase: pointerinjector::EventPhase,
508        current_position: Position,
509        relative_motion: Option<[f32; 2]>,
510        trace_id: Option<u64>,
511    ) -> pointerinjector::Event {
512        let pointer_sample = pointerinjector::PointerSample {
513            pointer_id: Some(0),
514            phase: Some(phase),
515            position_in_viewport: Some([current_position.x, current_position.y]),
516            scroll_v: match mouse_event.wheel_delta_v {
517                Some(mouse_binding::WheelDelta {
518                    raw_data: mouse_binding::RawWheelDelta::Ticks(tick),
519                    ..
520                }) => Some(tick),
521                _ => None,
522            },
523            scroll_h: match mouse_event.wheel_delta_h {
524                Some(mouse_binding::WheelDelta {
525                    raw_data: mouse_binding::RawWheelDelta::Ticks(tick),
526                    ..
527                }) => Some(tick),
528                _ => None,
529            },
530            scroll_v_physical_pixel: match mouse_event.wheel_delta_v {
531                Some(mouse_binding::WheelDelta { physical_pixel: Some(pixel), .. }) => {
532                    Some(pixel.into())
533                }
534                _ => None,
535            },
536            scroll_h_physical_pixel: match mouse_event.wheel_delta_h {
537                Some(mouse_binding::WheelDelta { physical_pixel: Some(pixel), .. }) => {
538                    Some(pixel.into())
539                }
540                _ => None,
541            },
542            is_precision_scroll: match mouse_event.phase {
543                mouse_binding::MousePhase::Wheel => match mouse_event.is_precision_scroll {
544                    Some(mouse_binding::PrecisionScroll::Yes) => Some(true),
545                    Some(mouse_binding::PrecisionScroll::No) => Some(false),
546                    None => {
547                        self.metrics_logger.log_error(
548                            InputPipelineErrorMetricDimensionEvent::MouseInjectorMissingIsPrecisionScroll,
549                            "mouse wheel event does not have value in is_precision_scroll.");
550                        None
551                    }
552                },
553                _ => None,
554            },
555            pressed_buttons: Some(Vec::from_iter(mouse_event.pressed_buttons.iter().cloned())),
556            relative_motion,
557            ..Default::default()
558        };
559        pointerinjector::Event {
560            timestamp: Some(event_time.into_nanos()),
561            data: Some(pointerinjector::Data::PointerSample(pointer_sample)),
562            trace_flow_id: trace_id,
563            wake_lease: mouse_event.wake_lease.lock().take(),
564            ..Default::default()
565        }
566    }
567
568    /// Watches for viewport updates from the scene manager.
569    pub async fn watch_viewport(self: Rc<Self>) {
570        let configuration_proxy = self.configuration_proxy.clone();
571        let mut viewport_stream = HangingGetStream::new(
572            configuration_proxy,
573            pointerinjector_config::SetupProxy::watch_viewport,
574        );
575        loop {
576            match viewport_stream.next().await {
577                Some(Ok(new_viewport)) => {
578                    // Update the viewport tracked by this handler.
579                    self.inner_mut().viewport = Some(utils::viewport_to_next(&new_viewport));
580
581                    // Update Scenic with the latest viewport.
582                    let injectors = self.inner().injectors.values().cloned().collect::<Vec<_>>();
583                    for injector in injectors {
584                        let events = vec![pointerinjector::Event {
585                            timestamp: Some(MonotonicInstant::now().into_nanos()),
586                            data: Some(pointerinjector::Data::Viewport(utils::viewport_to_next(
587                                &new_viewport,
588                            ))),
589                            trace_flow_id: Some(fuchsia_trace::Id::random().into()),
590                            ..Default::default()
591                        }];
592                        injector
593                            .inject_events(events)
594                            .await
595                            .expect("Failed to inject updated viewport.");
596                    }
597                }
598                Some(Err(e)) => {
599                    self.metrics_logger.log_error(
600                        InputPipelineErrorMetricDimensionEvent::MouseInjectorErrorWhileReadingViewportUpdate,
601                        std::format!("Error while reading viewport update: {}", e));
602                    return;
603                }
604                None => {
605                    self.metrics_logger.log_error(
606                        InputPipelineErrorMetricDimensionEvent::MouseInjectorViewportUpdateStreamTerminatedUnexpectedly,
607                        "Viewport update stream terminated unexpectedly");
608                    return;
609                }
610            }
611        }
612    }
613
614    /// Converts a relative movement given in millimeters to movement in phyical pixel.
615    /// Because pointer_display_scale_handler scaled for device pixel ratio, this method
616    /// only need to apply phyical distance to logical pixel scale factor.
617    fn relative_movement_mm_to_phyical_pixel(&self, movement_mm: Position) -> Position {
618        Position {
619            x: movement_mm.x * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
620            y: movement_mm.y * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
621        }
622    }
623}
624
625#[cfg(test)]
626mod tests {
627    use super::*;
628    use crate::testing_utilities::{
629        assert_handler_ignores_input_event_sequence, create_mouse_event,
630        create_mouse_event_with_handled, create_mouse_pointer_sample_event,
631        create_mouse_pointer_sample_event_phase_add,
632        create_mouse_pointer_sample_event_with_wheel_physical_pixel, next_client_old_stream,
633    };
634    use assert_matches::assert_matches;
635    use fidl_fuchsia_input_report as fidl_input_report;
636    use fidl_fuchsia_ui_pointerinjector as pointerinjector;
637    use fidl_next_fuchsia_ui_pointerinjector as pointerinjector_next;
638    use fuchsia_async as fasync;
639    use futures::channel::mpsc;
640    use pretty_assertions::assert_eq;
641    use std::collections::HashSet;
642    use std::ops::Add;
643    use test_case::test_case;
644
645    const DISPLAY_WIDTH_IN_PHYSICAL_PX: f32 = 100.0;
646    const DISPLAY_HEIGHT_IN_PHYSICAL_PX: f32 = 100.0;
647    const COUNTS_PER_MM: u32 = 12;
648
649    /// Returns an |input_device::InputDeviceDescriptor::MouseDescriptor|.
650    const DESCRIPTOR: input_device::InputDeviceDescriptor =
651        input_device::InputDeviceDescriptor::Mouse(mouse_binding::MouseDeviceDescriptor {
652            device_id: 1,
653            absolute_x_range: Some(fidl_input_report::Range { min: 0, max: 100 }),
654            absolute_y_range: Some(fidl_input_report::Range { min: 0, max: 100 }),
655            wheel_v_range: Some(fidl_input_report::Axis {
656                range: fidl_input_report::Range { min: -1, max: 1 },
657                unit: fidl_input_report::Unit {
658                    type_: fidl_input_report::UnitType::Other,
659                    exponent: 0,
660                },
661            }),
662            wheel_h_range: Some(fidl_input_report::Axis {
663                range: fidl_input_report::Range { min: -1, max: 1 },
664                unit: fidl_input_report::Unit {
665                    type_: fidl_input_report::UnitType::Other,
666                    exponent: 0,
667                },
668            }),
669            buttons: None,
670            counts_per_mm: COUNTS_PER_MM,
671        });
672
673    /// Handles |fidl_fuchsia_pointerinjector_configuration::SetupRequest::GetViewRefs|.
674    async fn handle_configuration_request_stream(
675        stream: &mut pointerinjector_config::SetupRequestStream,
676    ) {
677        if let Some(Ok(request)) = stream.next().await {
678            match request {
679                pointerinjector_config::SetupRequest::GetViewRefs { responder, .. } => {
680                    let context = fuchsia_scenic::ViewRefPair::new()
681                        .expect("Failed to create viewrefpair.")
682                        .view_ref;
683                    let target = fuchsia_scenic::ViewRefPair::new()
684                        .expect("Failed to create viewrefpair.")
685                        .view_ref;
686                    let _ = responder.send(context, target);
687                }
688                _ => {}
689            };
690        }
691    }
692
693    /// Handles |fidl_fuchsia_pointerinjector::RegistryRequest|s by forwarding the registered device
694    /// over `injector_sender` to be handled by handle_device_request_stream().
695    async fn handle_registry_request_stream(
696        mut stream: pointerinjector::RegistryRequestStream,
697        injector_sender: futures::channel::oneshot::Sender<pointerinjector::DeviceRequestStream>,
698    ) {
699        if let Some(request) = stream.next().await {
700            match request {
701                Ok(pointerinjector::RegistryRequest::Register {
702                    config: _,
703                    injector,
704                    responder,
705                    ..
706                }) => {
707                    let injector_stream = injector.into_stream();
708                    let _ = injector_sender.send(injector_stream);
709                    responder.send().expect("failed to respond");
710                }
711                _ => {}
712            };
713        } else {
714            panic!("RegistryRequestStream failed.");
715        }
716    }
717
718    // Handles |fidl_fuchsia_pointerinjector::RegistryRequest|s
719    async fn handle_registry_request_stream2(
720        mut stream: pointerinjector::RegistryRequestStream,
721        injector_sender: mpsc::UnboundedSender<Vec<pointerinjector::Event>>,
722    ) {
723        let (injector, responder) = match stream.next().await {
724            Some(Ok(pointerinjector::RegistryRequest::Register {
725                config: _,
726                injector,
727                responder,
728                ..
729            })) => (injector, responder),
730            other => panic!("expected register request, but got {:?}", other),
731        };
732        let injector_stream: pointerinjector::DeviceRequestStream = injector.into_stream();
733        responder.send().expect("failed to respond");
734        injector_stream
735            .for_each(|request| {
736                futures::future::ready({
737                    match request {
738                        Ok(pointerinjector::DeviceRequest::Inject { .. }) => {
739                            panic!("DeviceRequest::Inject is deprecated.");
740                        }
741                        Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. }) => {
742                            let _ = injector_sender.unbounded_send(events);
743                        }
744                        Err(e) => panic!("FIDL error {}", e),
745                    }
746                })
747            })
748            .await;
749    }
750
751    /// Handles |fidl_fuchsia_pointerinjector::DeviceRequest|s by asserting the injector stream
752    /// received on `injector_stream_receiver` gets `expected_events`.
753    async fn handle_device_request_stream(
754        injector_stream_receiver: futures::channel::oneshot::Receiver<
755            pointerinjector::DeviceRequestStream,
756        >,
757        expected_events: Vec<pointerinjector::Event>,
758    ) {
759        let mut injector_stream =
760            injector_stream_receiver.await.expect("Failed to get DeviceRequestStream.");
761        for expected_event in expected_events {
762            match injector_stream.next().await {
763                Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
764                    panic!("DeviceRequest::Inject is deprecated.");
765                }
766                Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
767                    assert_eq!(events, vec![expected_event]);
768                }
769                Some(Err(e)) => panic!("FIDL error {}", e),
770                None => panic!("Expected another event."),
771            }
772        }
773    }
774
775    // Creates a |pointerinjector::Viewport|.
776    fn create_viewport(min: f32, max: f32) -> pointerinjector::Viewport {
777        pointerinjector::Viewport {
778            extents: Some([[min, min], [max, max]]),
779            viewport_to_context_transform: None,
780            ..Default::default()
781        }
782    }
783
784    fn create_viewport_next(min: f32, max: f32) -> pointerinjector_next::Viewport {
785        pointerinjector_next::Viewport {
786            extents: Some([[min, min], [max, max]]),
787            viewport_to_context_transform: None,
788            ..Default::default()
789        }
790    }
791
792    // Tests that MouseInjectorHandler::receives_viewport_updates() tracks viewport updates
793    // and notifies injectors about said updates.
794    #[fuchsia::test]
795    fn receives_viewport_updates() {
796        let mut exec = fasync::TestExecutor::new();
797
798        // Set up fidl streams.
799        let (configuration_proxy, mut configuration_request_stream) =
800            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
801        let (injector_registry_proxy, _) =
802            fidl_next::fuchsia::create_channel::<pointerinjector_next::Registry>();
803        let injector_registry_proxy =
804            Dispatcher::client_from_zx_channel(injector_registry_proxy).spawn();
805        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(0);
806
807        let inspector = fuchsia_inspect::Inspector::default();
808        let test_node = inspector.root().create_child("test_node");
809
810        // Create mouse handler.
811        let mouse_handler_fut = MouseInjectorHandler::new_handler(
812            configuration_proxy,
813            injector_registry_proxy,
814            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
815            sender,
816            &test_node,
817            metrics::MetricsLogger::default(),
818        );
819        let config_request_stream_fut =
820            handle_configuration_request_stream(&mut configuration_request_stream);
821        let (mouse_handler_res, _) = exec.run_singlethreaded(futures::future::join(
822            mouse_handler_fut,
823            config_request_stream_fut,
824        ));
825        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
826
827        // Add an injector.
828        let (injector_device_proxy, mut injector_device_request_stream) =
829            next_client_old_stream::<pointerinjector::DeviceMarker, pointerinjector_next::Device>();
830        mouse_handler.inner_mut().injectors.insert(1, injector_device_proxy);
831
832        // This nested block is used to bound the lifetime of `watch_viewport_fut`.
833        {
834            // Request a viewport update.
835            let watch_viewport_fut = mouse_handler.clone().watch_viewport();
836            futures::pin_mut!(watch_viewport_fut);
837            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
838
839            // Send a viewport update.
840            match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
841                Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
842                    responder, ..
843                })) => {
844                    responder.send(&create_viewport(0.0, 100.0)).expect("Failed to send viewport.");
845                }
846                other => panic!("Received unexpected value: {:?}", other),
847            };
848            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
849
850            // Check that the injector received an updated viewport
851            exec.run_singlethreaded(async {
852                match injector_device_request_stream.next().await {
853                    Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
854                        panic!("DeviceRequest::Inject is deprecated.");
855                    }
856                    Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
857                        assert_eq!(events.len(), 1);
858                        assert!(events[0].data.is_some());
859                        assert_eq!(
860                            events[0].data,
861                            Some(pointerinjector::Data::Viewport(create_viewport(0.0, 100.0)))
862                        );
863                    }
864                    other => panic!("Received unexpected value: {:?}", other),
865                }
866            });
867
868            // Request viewport update.
869            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
870
871            // Send viewport update.
872            match exec.run_singlethreaded(&mut configuration_request_stream.next()) {
873                Some(Ok(pointerinjector_config::SetupRequest::WatchViewport {
874                    responder, ..
875                })) => {
876                    responder
877                        .send(&create_viewport(100.0, 200.0))
878                        .expect("Failed to send viewport.");
879                }
880                other => panic!("Received unexpected value: {:?}", other),
881            };
882
883            // Process viewport update.
884            assert!(exec.run_until_stalled(&mut watch_viewport_fut).is_pending());
885        }
886
887        // Check that the injector received an updated viewport
888        exec.run_singlethreaded(async {
889            match injector_device_request_stream.next().await {
890                Some(Ok(pointerinjector::DeviceRequest::Inject { .. })) => {
891                    panic!("DeviceRequest::Inject is deprecated.");
892                }
893                Some(Ok(pointerinjector::DeviceRequest::InjectEvents { events, .. })) => {
894                    assert_eq!(events.len(), 1);
895                    assert!(events[0].data.is_some());
896                    assert_eq!(
897                        events[0].data,
898                        Some(pointerinjector::Data::Viewport(create_viewport(100.0, 200.0)))
899                    );
900                }
901                other => panic!("Received unexpected value: {:?}", other),
902            }
903        });
904
905        // Check the viewport on the handler is accurate.
906        let expected_viewport = create_viewport_next(100.0, 200.0);
907        assert_eq!(mouse_handler.inner().viewport, Some(expected_viewport));
908    }
909
910    fn wheel_delta_ticks(
911        ticks: i64,
912        physical_pixel: Option<f32>,
913    ) -> Option<mouse_binding::WheelDelta> {
914        Some(mouse_binding::WheelDelta {
915            raw_data: mouse_binding::RawWheelDelta::Ticks(ticks),
916            physical_pixel,
917        })
918    }
919
920    fn wheel_delta_mm(mm: f32, physical_pixel: Option<f32>) -> Option<mouse_binding::WheelDelta> {
921        Some(mouse_binding::WheelDelta {
922            raw_data: mouse_binding::RawWheelDelta::Millimeters(mm),
923            physical_pixel,
924        })
925    }
926
927    // Tests that a mouse move event both sends an update to scenic and sends the current cursor
928    // location via the cursor location sender.
929    #[test_case(
930        mouse_binding::MouseLocation::Relative(
931            mouse_binding::RelativeLocation {
932                millimeters: Position { x: 1.0, y: 2.0 }
933            }),
934        Position {
935            x: DISPLAY_WIDTH_IN_PHYSICAL_PX / 2.0
936                + 1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
937            y: DISPLAY_HEIGHT_IN_PHYSICAL_PX / 2.0
938                + 2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
939        },
940        [
941            1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
942            2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
943        ]; "Valid move event."
944    )]
945    #[test_case(
946        mouse_binding::MouseLocation::Relative(
947            mouse_binding::RelativeLocation {
948                millimeters: Position {
949                    x: DISPLAY_WIDTH_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 2.0,
950                    y: DISPLAY_HEIGHT_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 1.0,
951                }}),
952        Position {
953          x: DISPLAY_WIDTH_IN_PHYSICAL_PX,
954          y: DISPLAY_HEIGHT_IN_PHYSICAL_PX,
955        },
956        [
957            DISPLAY_WIDTH_IN_PHYSICAL_PX + 2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
958            DISPLAY_HEIGHT_IN_PHYSICAL_PX + 1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
959        ]; "Move event exceeds max bounds."
960    )]
961    #[test_case(
962        mouse_binding::MouseLocation::Relative(
963            mouse_binding::RelativeLocation {
964                millimeters: Position {
965                    x: -(DISPLAY_WIDTH_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 2.0),
966                    y: -(DISPLAY_HEIGHT_IN_PHYSICAL_PX / MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL + 1.0),
967                }}),
968        Position { x: 0.0, y: 0.0 },
969        [
970            -(DISPLAY_WIDTH_IN_PHYSICAL_PX + 2.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL),
971            -(DISPLAY_HEIGHT_IN_PHYSICAL_PX + 1.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL),
972        ]; "Move event exceeds min bounds."
973    )]
974    #[fuchsia::test(allow_stalls = false)]
975    async fn move_event(
976        move_location: mouse_binding::MouseLocation,
977        expected_position: Position,
978        expected_relative_motion: [f32; 2],
979    ) {
980        // Set up fidl streams.
981        let (configuration_proxy, mut configuration_request_stream) =
982            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
983        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
984            pointerinjector::RegistryMarker,
985            pointerinjector_next::Registry,
986        >();
987        let config_request_stream_fut =
988            handle_configuration_request_stream(&mut configuration_request_stream);
989
990        // Create MouseInjectorHandler.
991        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
992        let inspector = fuchsia_inspect::Inspector::default();
993        let test_node = inspector.root().create_child("test_node");
994        let mouse_handler_fut = MouseInjectorHandler::new_handler(
995            configuration_proxy,
996            injector_registry_proxy,
997            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
998            sender,
999            &test_node,
1000            metrics::MetricsLogger::default(),
1001        );
1002        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1003        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1004
1005        let event_time = zx::MonotonicInstant::get();
1006        let input_event = create_mouse_event(
1007            move_location,
1008            None, /* wheel_delta_v */
1009            None, /* wheel_delta_h */
1010            None, /* is_precision_scroll */
1011            mouse_binding::MousePhase::Move,
1012            HashSet::new(),
1013            HashSet::new(),
1014            event_time,
1015            &DESCRIPTOR,
1016        );
1017
1018        // Handle event.
1019        let handle_event_fut = mouse_handler.handle_input_event(input_event);
1020        let expected_events = vec![
1021            create_mouse_pointer_sample_event_phase_add(vec![], expected_position, event_time),
1022            create_mouse_pointer_sample_event(
1023                pointerinjector::EventPhase::Change,
1024                vec![],
1025                expected_position,
1026                Some(expected_relative_motion),
1027                None, /*wheel_delta_v*/
1028                None, /*wheel_delta_h*/
1029                None, /*is_precision_scroll*/
1030                event_time,
1031            ),
1032        ];
1033
1034        // Create a channel for the the registered device's handle to be forwarded to the
1035        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1036        // handle_input_event() to continue.
1037        let (injector_stream_sender, injector_stream_receiver) =
1038            futures::channel::oneshot::channel::<pointerinjector::DeviceRequestStream>();
1039        let registry_fut = handle_registry_request_stream(
1040            injector_registry_request_stream,
1041            injector_stream_sender,
1042        );
1043        let device_fut = handle_device_request_stream(injector_stream_receiver, expected_events);
1044
1045        // Await all futures concurrently. If this completes, then the mouse event was handled and
1046        // matches `expected_events`.
1047        let (handle_result, _, _) = futures::join!(handle_event_fut, registry_fut, device_fut);
1048        match receiver.next().await {
1049            Some(CursorMessage::SetPosition(position)) => {
1050                pretty_assertions::assert_eq!(position, expected_position);
1051            }
1052            Some(CursorMessage::SetVisibility(_)) => {
1053                panic!("Received unexpected cursor visibility update.")
1054            }
1055            None => panic!("Did not receive cursor update."),
1056        }
1057
1058        // No unhandled events.
1059        assert_matches!(
1060            handle_result.as_slice(),
1061            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1062        );
1063    }
1064
1065    // Tests that an absolute mouse move event scales the location from device coordinates to
1066    // between {0, 0} and the handler's maximum position.
1067    #[fuchsia::test(allow_stalls = false)]
1068    async fn move_absolute_event() {
1069        const DEVICE_ID: u32 = 1;
1070
1071        // Set up fidl streams.
1072        let (configuration_proxy, mut configuration_request_stream) =
1073            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1074        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
1075            pointerinjector::RegistryMarker,
1076            pointerinjector_next::Registry,
1077        >();
1078        let config_request_stream_fut =
1079            handle_configuration_request_stream(&mut configuration_request_stream);
1080
1081        // Create MouseInjectorHandler.
1082        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
1083        let inspector = fuchsia_inspect::Inspector::default();
1084        let test_node = inspector.root().create_child("test_node");
1085        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1086            configuration_proxy,
1087            injector_registry_proxy,
1088            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1089            sender,
1090            &test_node,
1091            metrics::MetricsLogger::default(),
1092        );
1093        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1094        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1095
1096        // The location is rescaled from the device coordinate system defined
1097        // by `absolute_x_range` and `absolute_y_range`, to the display coordinate
1098        // system defined by `max_position`.
1099        //
1100        //          -50 y              0 +------------------ w
1101        //            |                  |         .
1102        //            |                  |         .
1103        //            |                  |         .
1104        // -50 x -----o----- 50   ->     | . . . . . . . . .
1105        //            |                  |         .
1106        //         * { x: -25, y: 25 }   |    * { x: w * 0.25, y: h * 0.75 }
1107        //            |                  |         .
1108        //           50                h |         .
1109        //
1110        // Where w = DISPLAY_WIDTH, h = DISPLAY_HEIGHT
1111        let cursor_location =
1112            mouse_binding::MouseLocation::Absolute(Position { x: -25.0, y: 25.0 });
1113        let event_time = zx::MonotonicInstant::get();
1114        let descriptor =
1115            input_device::InputDeviceDescriptor::Mouse(mouse_binding::MouseDeviceDescriptor {
1116                device_id: DEVICE_ID,
1117                absolute_x_range: Some(fidl_input_report::Range { min: -50, max: 50 }),
1118                absolute_y_range: Some(fidl_input_report::Range { min: -50, max: 50 }),
1119                wheel_v_range: None,
1120                wheel_h_range: None,
1121                buttons: None,
1122                counts_per_mm: COUNTS_PER_MM,
1123            });
1124        let input_event = create_mouse_event(
1125            cursor_location,
1126            None, /* wheel_delta_v */
1127            None, /* wheel_delta_h */
1128            None, /* is_precision_scroll */
1129            mouse_binding::MousePhase::Move,
1130            HashSet::new(),
1131            HashSet::new(),
1132            event_time,
1133            &descriptor,
1134        );
1135
1136        // Handle event.
1137        let handle_event_fut = mouse_handler.handle_input_event(input_event);
1138        let expected_position = Position {
1139            x: DISPLAY_WIDTH_IN_PHYSICAL_PX * 0.25,
1140            y: DISPLAY_WIDTH_IN_PHYSICAL_PX * 0.75,
1141        };
1142        let expected_events = vec![
1143            create_mouse_pointer_sample_event_phase_add(vec![], expected_position, event_time),
1144            create_mouse_pointer_sample_event(
1145                pointerinjector::EventPhase::Change,
1146                vec![],
1147                expected_position,
1148                None, /*relative_motion*/
1149                None, /*wheel_delta_v*/
1150                None, /*wheel_delta_h*/
1151                None, /*is_precision_scroll*/
1152                event_time,
1153            ),
1154        ];
1155
1156        // Create a channel for the the registered device's handle to be forwarded to the
1157        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1158        // handle_input_event() to continue.
1159        let (injector_stream_sender, injector_stream_receiver) =
1160            futures::channel::oneshot::channel::<pointerinjector::DeviceRequestStream>();
1161        let registry_fut = handle_registry_request_stream(
1162            injector_registry_request_stream,
1163            injector_stream_sender,
1164        );
1165        let device_fut = handle_device_request_stream(injector_stream_receiver, expected_events);
1166
1167        // Await all futures concurrently. If this completes, then the mouse event was handled and
1168        // matches `expected_events`.
1169        let (handle_result, _, _) = futures::join!(handle_event_fut, registry_fut, device_fut);
1170        match receiver.next().await {
1171            Some(CursorMessage::SetPosition(position)) => {
1172                assert_eq!(position, expected_position);
1173            }
1174            Some(CursorMessage::SetVisibility(_)) => {
1175                panic!("Received unexpected cursor visibility update.")
1176            }
1177            None => panic!("Did not receive cursor update."),
1178        }
1179
1180        // No unhandled events.
1181        assert_matches!(
1182            handle_result.as_slice(),
1183            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1184        );
1185    }
1186
1187    // Tests that mouse down and up events inject button press state.
1188    #[test_case(
1189      mouse_binding::MousePhase::Down,
1190      vec![1], vec![1]; "Down event injects button press state."
1191    )]
1192    #[test_case(
1193      mouse_binding::MousePhase::Up,
1194      vec![1], vec![]; "Up event injects button press state."
1195    )]
1196    #[fuchsia::test(allow_stalls = false)]
1197    async fn button_state_event(
1198        phase: mouse_binding::MousePhase,
1199        affected_buttons: Vec<mouse_binding::MouseButton>,
1200        pressed_buttons: Vec<mouse_binding::MouseButton>,
1201    ) {
1202        // Set up fidl streams.
1203        let (configuration_proxy, mut configuration_request_stream) =
1204            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1205        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
1206            pointerinjector::RegistryMarker,
1207            pointerinjector_next::Registry,
1208        >();
1209        let config_request_stream_fut =
1210            handle_configuration_request_stream(&mut configuration_request_stream);
1211
1212        // Create MouseInjectorHandler.
1213        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
1214        let inspector = fuchsia_inspect::Inspector::default();
1215        let test_node = inspector.root().create_child("test_node");
1216        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1217            configuration_proxy,
1218            injector_registry_proxy,
1219            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1220            sender,
1221            &test_node,
1222            metrics::MetricsLogger::default(),
1223        );
1224        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1225        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1226
1227        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
1228        let event_time = zx::MonotonicInstant::get();
1229
1230        let input_event = create_mouse_event(
1231            cursor_location,
1232            None, /* wheel_delta_v */
1233            None, /* wheel_delta_h */
1234            None, /* is_precision_scroll */
1235            phase,
1236            HashSet::from_iter(affected_buttons.clone()),
1237            HashSet::from_iter(pressed_buttons.clone()),
1238            event_time,
1239            &DESCRIPTOR,
1240        );
1241
1242        // Handle event.
1243        let handle_event_fut = mouse_handler.handle_input_event(input_event);
1244        let expected_position = Position { x: 0.0, y: 0.0 };
1245        let expected_events = vec![
1246            create_mouse_pointer_sample_event_phase_add(
1247                pressed_buttons.clone(),
1248                expected_position,
1249                event_time,
1250            ),
1251            create_mouse_pointer_sample_event(
1252                pointerinjector::EventPhase::Change,
1253                pressed_buttons.clone(),
1254                expected_position,
1255                None, /*relative_motion*/
1256                None, /*wheel_delta_v*/
1257                None, /*wheel_delta_h*/
1258                None, /*is_precision_scroll*/
1259                event_time,
1260            ),
1261        ];
1262
1263        // Create a channel for the the registered device's handle to be forwarded to the
1264        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1265        // handle_input_event() to continue.
1266        let (injector_stream_sender, injector_stream_receiver) =
1267            futures::channel::oneshot::channel::<pointerinjector::DeviceRequestStream>();
1268        let registry_fut = handle_registry_request_stream(
1269            injector_registry_request_stream,
1270            injector_stream_sender,
1271        );
1272        let device_fut = handle_device_request_stream(injector_stream_receiver, expected_events);
1273
1274        // Await all futures concurrently. If this completes, then the mouse event was handled and
1275        // matches `expected_events`.
1276        let (handle_result, _, _) = futures::join!(handle_event_fut, registry_fut, device_fut);
1277        match receiver.next().await {
1278            Some(CursorMessage::SetPosition(position)) => {
1279                pretty_assertions::assert_eq!(position, expected_position);
1280            }
1281            Some(CursorMessage::SetVisibility(_)) => {
1282                panic!("Received unexpected cursor visibility update.")
1283            }
1284            None => panic!("Did not receive cursor update."),
1285        }
1286
1287        // No unhandled events.
1288        assert_matches!(
1289            handle_result.as_slice(),
1290            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
1291        );
1292    }
1293
1294    // Tests that mouse down followed by mouse up events inject button press state.
1295    #[fuchsia::test(allow_stalls = false)]
1296    async fn down_up_event() {
1297        // Set up fidl streams.
1298        let (configuration_proxy, mut configuration_request_stream) =
1299            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1300        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
1301            pointerinjector::RegistryMarker,
1302            pointerinjector_next::Registry,
1303        >();
1304        let config_request_stream_fut =
1305            handle_configuration_request_stream(&mut configuration_request_stream);
1306
1307        // Create MouseInjectorHandler.
1308        // Note: The size of the CursorMessage channel's buffer is 2 to allow for one cursor
1309        // update for every input event being sent.
1310        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(2);
1311        let inspector = fuchsia_inspect::Inspector::default();
1312        let test_node = inspector.root().create_child("test_node");
1313        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1314            configuration_proxy,
1315            injector_registry_proxy,
1316            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1317            sender,
1318            &test_node,
1319            metrics::MetricsLogger::default(),
1320        );
1321        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1322        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1323
1324        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
1325        let event_time1 = zx::MonotonicInstant::get();
1326        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1327
1328        let event1 = create_mouse_event(
1329            cursor_location,
1330            None, /* wheel_delta_v */
1331            None, /* wheel_delta_h */
1332            None, /* is_precision_scroll */
1333            mouse_binding::MousePhase::Down,
1334            HashSet::from_iter(vec![1]),
1335            HashSet::from_iter(vec![1]),
1336            event_time1,
1337            &DESCRIPTOR,
1338        );
1339
1340        let event2 = create_mouse_event(
1341            cursor_location,
1342            None, /* wheel_delta_v */
1343            None, /* wheel_delta_h */
1344            None, /* is_precision_scroll */
1345            mouse_binding::MousePhase::Up,
1346            HashSet::from_iter(vec![1]),
1347            HashSet::new(),
1348            event_time2,
1349            &DESCRIPTOR,
1350        );
1351
1352        let expected_position = Position { x: 0.0, y: 0.0 };
1353
1354        // Create a channel for the the registered device's handle to be forwarded to the
1355        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1356        // handle_input_event() to continue.
1357        let (injector_stream_sender, injector_stream_receiver) =
1358            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1359        // Up to 2 events per handle_input_event() call.
1360        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1361        let registry_fut = handle_registry_request_stream2(
1362            injector_registry_request_stream,
1363            injector_stream_sender,
1364        );
1365
1366        // Run future until the handler future completes.
1367        let _registry_task = fasync::Task::local(registry_fut);
1368
1369        mouse_handler.clone().handle_input_event(event1).await;
1370        assert_eq!(
1371            injector_stream_receiver
1372                .next()
1373                .await
1374                .map(|events| events.into_iter().flatten().collect()),
1375            Some(vec![
1376                create_mouse_pointer_sample_event_phase_add(
1377                    vec![1],
1378                    expected_position,
1379                    event_time1,
1380                ),
1381                create_mouse_pointer_sample_event(
1382                    pointerinjector::EventPhase::Change,
1383                    vec![1],
1384                    expected_position,
1385                    None, /*relative_motion*/
1386                    None, /*wheel_delta_v*/
1387                    None, /*wheel_delta_h*/
1388                    None, /*is_precision_scroll*/
1389                    event_time1,
1390                )
1391            ])
1392        );
1393
1394        // Send another input event.
1395        mouse_handler.clone().handle_input_event(event2).await;
1396        assert_eq!(
1397            injector_stream_receiver
1398                .next()
1399                .await
1400                .map(|events| events.into_iter().flatten().collect()),
1401            Some(vec![create_mouse_pointer_sample_event(
1402                pointerinjector::EventPhase::Change,
1403                vec![],
1404                expected_position,
1405                None, /*relative_motion*/
1406                None, /*wheel_delta_v*/
1407                None, /*wheel_delta_h*/
1408                None, /*is_precision_scroll*/
1409                event_time2,
1410            )])
1411        );
1412
1413        // Wait until validation is complete.
1414        match receiver.next().await {
1415            Some(CursorMessage::SetPosition(position)) => {
1416                assert_eq!(position, expected_position);
1417            }
1418            Some(CursorMessage::SetVisibility(_)) => {
1419                panic!("Received unexpected cursor visibility update.")
1420            }
1421            None => panic!("Did not receive cursor update."),
1422        }
1423    }
1424
1425    /// Tests that two staggered button presses followed by stagged releases generate four mouse
1426    /// events with distinct `affected_button` and `pressed_button`.
1427    /// Specifically, we test and expect the following in order:
1428    /// | Action           | MousePhase | Injected Phase | `pressed_buttons` |
1429    /// | ---------------- | ---------- | -------------- | ----------------- |
1430    /// | Press button 1   | Down       | Change         | [1]               |
1431    /// | Press button 2   | Down       | Change         | [1, 2]            |
1432    /// | Release button 1 | Up         | Change         | [2]               |
1433    /// | Release button 2 | Up         | Change         | []                |
1434    #[fuchsia::test(allow_stalls = false)]
1435    async fn down_down_up_up_event() {
1436        // Set up fidl streams.
1437        let (configuration_proxy, mut configuration_request_stream) =
1438            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1439        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
1440            pointerinjector::RegistryMarker,
1441            pointerinjector_next::Registry,
1442        >();
1443        let config_request_stream_fut =
1444            handle_configuration_request_stream(&mut configuration_request_stream);
1445
1446        // Create MouseInjectorHandler.
1447        // Note: The size of the CursorMessage channel's buffer is 4 to allow for one cursor
1448        // update for every input event being sent.
1449        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(4);
1450        let inspector = fuchsia_inspect::Inspector::default();
1451        let test_node = inspector.root().create_child("test_node");
1452        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1453            configuration_proxy,
1454            injector_registry_proxy,
1455            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1456            sender,
1457            &test_node,
1458            metrics::MetricsLogger::default(),
1459        );
1460        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1461        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1462
1463        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
1464        let event_time1 = zx::MonotonicInstant::get();
1465        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1466        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1467        let event_time4 = event_time3.add(zx::MonotonicDuration::from_micros(1));
1468
1469        let event1 = create_mouse_event(
1470            cursor_location,
1471            None, /* wheel_delta_v */
1472            None, /* wheel_delta_h */
1473            None, /* is_precision_scroll */
1474            mouse_binding::MousePhase::Down,
1475            HashSet::from_iter(vec![1]),
1476            HashSet::from_iter(vec![1]),
1477            event_time1,
1478            &DESCRIPTOR,
1479        );
1480        let event2 = create_mouse_event(
1481            cursor_location,
1482            None, /* wheel_delta_v */
1483            None, /* wheel_delta_h */
1484            None, /* is_precision_scroll */
1485            mouse_binding::MousePhase::Down,
1486            HashSet::from_iter(vec![2]),
1487            HashSet::from_iter(vec![1, 2]),
1488            event_time2,
1489            &DESCRIPTOR,
1490        );
1491        let event3 = create_mouse_event(
1492            cursor_location,
1493            None, /* wheel_delta_v */
1494            None, /* wheel_delta_h */
1495            None, /* is_precision_scroll */
1496            mouse_binding::MousePhase::Up,
1497            HashSet::from_iter(vec![1]),
1498            HashSet::from_iter(vec![2]),
1499            event_time3,
1500            &DESCRIPTOR,
1501        );
1502        let event4 = create_mouse_event(
1503            cursor_location,
1504            None, /* wheel_delta_v */
1505            None, /* wheel_delta_h */
1506            None, /* is_precision_scroll */
1507            mouse_binding::MousePhase::Up,
1508            HashSet::from_iter(vec![2]),
1509            HashSet::new(),
1510            event_time4,
1511            &DESCRIPTOR,
1512        );
1513
1514        let expected_position = Position { x: 0.0, y: 0.0 };
1515
1516        // Create a channel for the the registered device's handle to be forwarded to the
1517        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1518        // handle_input_event() to continue.
1519        let (injector_stream_sender, injector_stream_receiver) =
1520            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1521        // Up to 2 events per handle_input_event() call.
1522        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1523        let registry_fut = handle_registry_request_stream2(
1524            injector_registry_request_stream,
1525            injector_stream_sender,
1526        );
1527
1528        // Run future until the handler future completes.
1529        let _registry_task = fasync::Task::local(registry_fut);
1530        mouse_handler.clone().handle_input_event(event1).await;
1531        assert_eq!(
1532            injector_stream_receiver
1533                .next()
1534                .await
1535                .map(|events| events.into_iter().flatten().collect()),
1536            Some(vec![
1537                create_mouse_pointer_sample_event_phase_add(
1538                    vec![1],
1539                    expected_position,
1540                    event_time1,
1541                ),
1542                create_mouse_pointer_sample_event(
1543                    pointerinjector::EventPhase::Change,
1544                    vec![1],
1545                    expected_position,
1546                    None, /*relative_motion*/
1547                    None, /*wheel_delta_v*/
1548                    None, /*wheel_delta_h*/
1549                    None, /*is_precision_scroll*/
1550                    event_time1,
1551                )
1552            ])
1553        );
1554
1555        // Send another down event.
1556        mouse_handler.clone().handle_input_event(event2).await;
1557        let pointer_sample_event2: Vec<_> = injector_stream_receiver
1558            .next()
1559            .await
1560            .map(|events| events.into_iter().flatten().collect())
1561            .expect("Failed to receive pointer sample event.");
1562        let expected_event_time: i64 = event_time2.into_nanos();
1563        assert_eq!(pointer_sample_event2.len(), 1);
1564
1565        // We must break this event result apart for assertions since the
1566        // `pressed_buttons` can be given with elements in any order.
1567        match &pointer_sample_event2[0] {
1568            pointerinjector::Event {
1569                timestamp: Some(actual_event_time),
1570                data:
1571                    Some(pointerinjector::Data::PointerSample(pointerinjector::PointerSample {
1572                        pointer_id: Some(0),
1573                        phase: Some(pointerinjector::EventPhase::Change),
1574                        position_in_viewport: Some(actual_position),
1575                        scroll_v: None,
1576                        scroll_h: None,
1577                        pressed_buttons: Some(actual_buttons),
1578                        relative_motion: None,
1579                        ..
1580                    })),
1581                ..
1582            } => {
1583                assert_eq!(*actual_event_time, expected_event_time);
1584                assert_eq!(actual_position[0], expected_position.x);
1585                assert_eq!(actual_position[1], expected_position.y);
1586                assert_eq!(
1587                    HashSet::<mouse_binding::MouseButton>::from_iter(actual_buttons.clone()),
1588                    HashSet::from_iter(vec![1, 2])
1589                );
1590            }
1591            _ => panic!("Unexpected pointer sample event: {:?}", pointer_sample_event2[0]),
1592        }
1593
1594        // Send another up event.
1595        mouse_handler.clone().handle_input_event(event3).await;
1596        assert_eq!(
1597            injector_stream_receiver
1598                .next()
1599                .await
1600                .map(|events| events.into_iter().flatten().collect()),
1601            Some(vec![create_mouse_pointer_sample_event(
1602                pointerinjector::EventPhase::Change,
1603                vec![2],
1604                expected_position,
1605                None, /*relative_motion*/
1606                None, /*wheel_delta_v*/
1607                None, /*wheel_delta_h*/
1608                None, /*is_precision_scroll*/
1609                event_time3,
1610            )])
1611        );
1612
1613        // Send another up event.
1614        mouse_handler.clone().handle_input_event(event4).await;
1615        assert_eq!(
1616            injector_stream_receiver
1617                .next()
1618                .await
1619                .map(|events| events.into_iter().flatten().collect()),
1620            Some(vec![create_mouse_pointer_sample_event(
1621                pointerinjector::EventPhase::Change,
1622                vec![],
1623                expected_position,
1624                None, /*relative_motion*/
1625                None, /*wheel_delta_v*/
1626                None, /*wheel_delta_h*/
1627                None, /*is_precision_scroll*/
1628                event_time4,
1629            )])
1630        );
1631
1632        // Wait until validation is complete.
1633        match receiver.next().await {
1634            Some(CursorMessage::SetPosition(position)) => {
1635                assert_eq!(position, expected_position);
1636            }
1637            Some(CursorMessage::SetVisibility(_)) => {
1638                panic!("Received unexpected cursor visibility update.")
1639            }
1640            None => panic!("Did not receive cursor update."),
1641        }
1642    }
1643
1644    /// Tests that button press, mouse move, and button release inject changes accordingly.
1645    #[fuchsia::test(allow_stalls = false)]
1646    async fn down_move_up_event() {
1647        // Set up fidl streams.
1648        let (configuration_proxy, mut configuration_request_stream) =
1649            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1650        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
1651            pointerinjector::RegistryMarker,
1652            pointerinjector_next::Registry,
1653        >();
1654        let config_request_stream_fut =
1655            handle_configuration_request_stream(&mut configuration_request_stream);
1656
1657        // Create MouseInjectorHandler.
1658        // Note: The size of the CursorMessage channel's buffer is 3 to allow for one cursor
1659        // update for every input event being sent.
1660        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(3);
1661        let inspector = fuchsia_inspect::Inspector::default();
1662        let test_node = inspector.root().create_child("test_node");
1663        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1664            configuration_proxy,
1665            injector_registry_proxy,
1666            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1667            sender,
1668            &test_node,
1669            metrics::MetricsLogger::default(),
1670        );
1671        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1672        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1673
1674        let event_time1 = zx::MonotonicInstant::get();
1675        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
1676        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
1677        let zero_position = Position { x: 0.0, y: 0.0 };
1678        let expected_position = Position {
1679            x: 10.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1680            y: 5.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1681        };
1682        let expected_relative_motion = [
1683            10.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1684            5.0 * MOUSE_DISTANCE_IN_MM_TO_DISPLAY_LOGICAL_PIXEL,
1685        ];
1686        let event1 = create_mouse_event(
1687            mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 }),
1688            None, /* wheel_delta_v */
1689            None, /* wheel_delta_h */
1690            None, /* is_precision_scroll */
1691            mouse_binding::MousePhase::Down,
1692            HashSet::from_iter(vec![1]),
1693            HashSet::from_iter(vec![1]),
1694            event_time1,
1695            &DESCRIPTOR,
1696        );
1697        let event2 = create_mouse_event(
1698            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1699                millimeters: Position { x: 10.0, y: 5.0 },
1700            }),
1701            None, /* wheel_delta_v */
1702            None, /* wheel_delta_h */
1703            None, /* is_precision_scroll */
1704            mouse_binding::MousePhase::Move,
1705            HashSet::from_iter(vec![1]),
1706            HashSet::from_iter(vec![1]),
1707            event_time2,
1708            &DESCRIPTOR,
1709        );
1710        let event3 = create_mouse_event(
1711            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1712                millimeters: Position { x: 0.0, y: 0.0 },
1713            }),
1714            None, /* wheel_delta_v */
1715            None, /* wheel_delta_h */
1716            None, /* is_precision_scroll */
1717            mouse_binding::MousePhase::Up,
1718            HashSet::from_iter(vec![1]),
1719            HashSet::from_iter(vec![]),
1720            event_time3,
1721            &DESCRIPTOR,
1722        );
1723
1724        // Create a channel for the the registered device's handle to be forwarded to the
1725        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
1726        // handle_input_event() to continue.
1727        let (injector_stream_sender, injector_stream_receiver) =
1728            mpsc::unbounded::<Vec<pointerinjector::Event>>();
1729        // Up to 2 events per handle_input_event() call.
1730        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
1731        let registry_fut = handle_registry_request_stream2(
1732            injector_registry_request_stream,
1733            injector_stream_sender,
1734        );
1735
1736        // Run future until the handler future completes.
1737        let _registry_task = fasync::Task::local(registry_fut);
1738        mouse_handler.clone().handle_input_event(event1).await;
1739        assert_eq!(
1740            injector_stream_receiver
1741                .next()
1742                .await
1743                .map(|events| events.into_iter().flatten().collect()),
1744            Some(vec![
1745                create_mouse_pointer_sample_event_phase_add(vec![1], zero_position, event_time1,),
1746                create_mouse_pointer_sample_event(
1747                    pointerinjector::EventPhase::Change,
1748                    vec![1],
1749                    zero_position,
1750                    None, /*relative_motion*/
1751                    None, /*wheel_delta_v*/
1752                    None, /*wheel_delta_h*/
1753                    None, /*is_precision_scroll*/
1754                    event_time1,
1755                )
1756            ])
1757        );
1758
1759        // Wait until cursor position validation is complete.
1760        match receiver.next().await {
1761            Some(CursorMessage::SetPosition(position)) => {
1762                assert_eq!(position, zero_position);
1763            }
1764            Some(CursorMessage::SetVisibility(_)) => {
1765                panic!("Received unexpected cursor visibility update.")
1766            }
1767            None => panic!("Did not receive cursor update."),
1768        }
1769
1770        // Send a move event.
1771        mouse_handler.clone().handle_input_event(event2).await;
1772        assert_eq!(
1773            injector_stream_receiver
1774                .next()
1775                .await
1776                .map(|events| events.into_iter().flatten().collect()),
1777            Some(vec![create_mouse_pointer_sample_event(
1778                pointerinjector::EventPhase::Change,
1779                vec![1],
1780                expected_position,
1781                Some(expected_relative_motion),
1782                None, /*wheel_delta_v*/
1783                None, /*wheel_delta_h*/
1784                None, /*is_precision_scroll*/
1785                event_time2,
1786            )])
1787        );
1788
1789        // Wait until cursor position validation is complete.
1790        match receiver.next().await {
1791            Some(CursorMessage::SetPosition(position)) => {
1792                assert_eq!(position, expected_position);
1793            }
1794            Some(CursorMessage::SetVisibility(_)) => {
1795                panic!("Received unexpected cursor visibility update.")
1796            }
1797            None => panic!("Did not receive cursor update."),
1798        }
1799
1800        // Send an up event.
1801        mouse_handler.clone().handle_input_event(event3).await;
1802        assert_eq!(
1803            injector_stream_receiver
1804                .next()
1805                .await
1806                .map(|events| events.into_iter().flatten().collect()),
1807            Some(vec![create_mouse_pointer_sample_event(
1808                pointerinjector::EventPhase::Change,
1809                vec![],
1810                expected_position,
1811                None, /*relative_motion*/
1812                None, /*wheel_delta_v*/
1813                None, /*wheel_delta_h*/
1814                None, /*is_precision_scroll*/
1815                event_time3,
1816            )])
1817        );
1818
1819        // Wait until cursor position validation is complete.
1820        match receiver.next().await {
1821            Some(CursorMessage::SetPosition(position)) => {
1822                assert_eq!(position, expected_position);
1823            }
1824            Some(CursorMessage::SetVisibility(_)) => {
1825                panic!("Received unexpected cursor visibility update.")
1826            }
1827            None => panic!("Did not receive cursor update."),
1828        }
1829    }
1830
1831    // Tests that a mouse move event that has already been handled is not forwarded to scenic.
1832    #[fuchsia::test(allow_stalls = false)]
1833    async fn handler_ignores_handled_events() {
1834        // Set up fidl streams.
1835        let (configuration_proxy, mut configuration_request_stream) =
1836            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
1837        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
1838            pointerinjector::RegistryMarker,
1839            pointerinjector_next::Registry,
1840        >();
1841        let config_request_stream_fut =
1842            handle_configuration_request_stream(&mut configuration_request_stream);
1843
1844        // Create MouseInjectorHandler.
1845        let (sender, mut receiver) = futures::channel::mpsc::channel::<CursorMessage>(1);
1846        let inspector = fuchsia_inspect::Inspector::default();
1847        let test_node = inspector.root().create_child("test_node");
1848        let mouse_handler_fut = MouseInjectorHandler::new_handler(
1849            configuration_proxy,
1850            injector_registry_proxy,
1851            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
1852            sender,
1853            &test_node,
1854            metrics::MetricsLogger::default(),
1855        );
1856        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
1857        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
1858
1859        let cursor_relative_position = Position { x: 50.0, y: 75.0 };
1860        let cursor_location =
1861            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1862                millimeters: Position {
1863                    x: cursor_relative_position.x / COUNTS_PER_MM as f32,
1864                    y: cursor_relative_position.y / COUNTS_PER_MM as f32,
1865                },
1866            });
1867        let event_time = zx::MonotonicInstant::get();
1868        let input_events = vec![create_mouse_event_with_handled(
1869            cursor_location,
1870            None, /* wheel_delta_v */
1871            None, /* wheel_delta_h */
1872            None, /* is_precision_scroll */
1873            mouse_binding::MousePhase::Move,
1874            HashSet::new(),
1875            HashSet::new(),
1876            event_time,
1877            &DESCRIPTOR,
1878            input_device::Handled::Yes,
1879        )];
1880
1881        assert_handler_ignores_input_event_sequence(
1882            mouse_handler,
1883            input_events,
1884            injector_registry_request_stream,
1885        )
1886        .await;
1887
1888        // The cursor location stream should not receive any position.
1889        assert!(receiver.next().await.is_none());
1890    }
1891
1892    fn zero_relative_location() -> mouse_binding::MouseLocation {
1893        mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
1894            millimeters: Position { x: 0.0, y: 0.0 },
1895        })
1896    }
1897
1898    #[test_case(
1899        create_mouse_event(
1900            zero_relative_location(),
1901            wheel_delta_ticks(1, None),               /*wheel_delta_v*/
1902            None,                                     /*wheel_delta_h*/
1903            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1904            mouse_binding::MousePhase::Wheel,
1905            HashSet::new(),
1906            HashSet::new(),
1907            zx::MonotonicInstant::ZERO,
1908            &DESCRIPTOR,
1909        ),
1910        create_mouse_pointer_sample_event(
1911            pointerinjector::EventPhase::Change,
1912            vec![],
1913            Position { x: 50.0, y: 50.0 },
1914            None,    /*relative_motion*/
1915            Some(1), /*wheel_delta_v*/
1916            None,    /*wheel_delta_h*/
1917            Some(false), /*is_precision_scroll*/
1918            zx::MonotonicInstant::ZERO,
1919        ); "v tick scroll"
1920    )]
1921    #[test_case(
1922        create_mouse_event(
1923            zero_relative_location(),
1924            None,                                     /*wheel_delta_v*/
1925            wheel_delta_ticks(1, None),               /*wheel_delta_h*/
1926            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1927            mouse_binding::MousePhase::Wheel,
1928            HashSet::new(),
1929            HashSet::new(),
1930            zx::MonotonicInstant::ZERO,
1931            &DESCRIPTOR,
1932        ),
1933        create_mouse_pointer_sample_event(
1934            pointerinjector::EventPhase::Change,
1935            vec![],
1936            Position { x: 50.0, y: 50.0 },
1937            None,    /*relative_motion*/
1938            None,    /*wheel_delta_v*/
1939            Some(1), /*wheel_delta_h*/
1940            Some(false), /*is_precision_scroll*/
1941            zx::MonotonicInstant::ZERO,
1942        ); "h tick scroll"
1943    )]
1944    #[test_case(
1945        create_mouse_event(
1946            zero_relative_location(),
1947            wheel_delta_ticks(1, Some(120.0)),        /*wheel_delta_v*/
1948            None,                                     /*wheel_delta_h*/
1949            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1950            mouse_binding::MousePhase::Wheel,
1951            HashSet::new(),
1952            HashSet::new(),
1953            zx::MonotonicInstant::ZERO,
1954            &DESCRIPTOR,
1955        ),
1956        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1957            pointerinjector::EventPhase::Change,
1958            vec![],
1959            Position { x: 50.0, y: 50.0 },
1960            None,        /*relative_motion*/
1961            Some(1),     /*wheel_delta_v*/
1962            None,        /*wheel_delta_h*/
1963            Some(120.0), /*wheel_delta_v_physical_pixel*/
1964            None,        /*wheel_delta_h_physical_pixel*/
1965            Some(false), /*is_precision_scroll*/
1966            zx::MonotonicInstant::ZERO,
1967        ); "v tick scroll with physical pixel"
1968    )]
1969    #[test_case(
1970        create_mouse_event(
1971            zero_relative_location(),
1972            None,                                     /*wheel_delta_v*/
1973            wheel_delta_ticks(1, Some(120.0)),        /*wheel_delta_h*/
1974            Some(mouse_binding::PrecisionScroll::No), /*is_precision_scroll*/
1975            mouse_binding::MousePhase::Wheel,
1976            HashSet::new(),
1977            HashSet::new(),
1978            zx::MonotonicInstant::ZERO,
1979            &DESCRIPTOR,
1980        ),
1981        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
1982            pointerinjector::EventPhase::Change,
1983            vec![],
1984            Position { x: 50.0, y: 50.0 },
1985            None,        /*relative_motion*/
1986            None,        /*wheel_delta_v*/
1987            Some(1),     /*wheel_delta_h*/
1988            None,        /*wheel_delta_v_physical_pixel*/
1989            Some(120.0), /*wheel_delta_h_physical_pixel*/
1990            Some(false), /*is_precision_scroll*/
1991            zx::MonotonicInstant::ZERO,
1992        ); "h tick scroll with physical pixel"
1993    )]
1994    #[test_case(
1995        create_mouse_event(
1996            zero_relative_location(),
1997            wheel_delta_mm(1.0, Some(120.0)),          /*wheel_delta_v*/
1998            None,                                      /*wheel_delta_h*/
1999            Some(mouse_binding::PrecisionScroll::Yes), /*is_precision_scroll*/
2000            mouse_binding::MousePhase::Wheel,
2001            HashSet::new(),
2002            HashSet::new(),
2003            zx::MonotonicInstant::ZERO,
2004            &DESCRIPTOR,
2005        ),
2006        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
2007            pointerinjector::EventPhase::Change,
2008            vec![],
2009            Position { x: 50.0, y: 50.0 },
2010            None,        /*relative_motion*/
2011            None,        /*wheel_delta_v*/
2012            None,        /*wheel_delta_h*/
2013            Some(120.0), /*wheel_delta_v_physical_pixel*/
2014            None,        /*wheel_delta_h_physical_pixel*/
2015            Some(true),  /*is_precision_scroll*/
2016            zx::MonotonicInstant::ZERO,
2017        ); "v mm scroll with physical pixel"
2018    )]
2019    #[test_case(
2020        create_mouse_event(
2021            zero_relative_location(),
2022            None,                                      /*wheel_delta_v*/
2023            wheel_delta_mm(1.0, Some(120.0)),          /*wheel_delta_h*/
2024            Some(mouse_binding::PrecisionScroll::Yes), /*is_precision_scroll*/
2025            mouse_binding::MousePhase::Wheel,
2026            HashSet::new(),
2027            HashSet::new(),
2028            zx::MonotonicInstant::ZERO,
2029            &DESCRIPTOR,
2030        ),
2031        create_mouse_pointer_sample_event_with_wheel_physical_pixel(
2032            pointerinjector::EventPhase::Change,
2033            vec![],
2034            Position { x: 50.0, y: 50.0 },
2035            None,        /*relative_motion*/
2036            None,        /*wheel_delta_v*/
2037            None,        /*wheel_delta_h*/
2038            None,        /*wheel_delta_v_physical_pixel*/
2039            Some(120.0), /*wheel_delta_h_physical_pixel*/
2040            Some(true),  /*is_precision_scroll*/
2041            zx::MonotonicInstant::ZERO,
2042        ); "h mm scroll with physical pixel"
2043    )]
2044    /// Test simple scroll in vertical and horizontal.
2045    #[fuchsia::test(allow_stalls = false)]
2046    async fn scroll(event: input_device::InputEvent, want_event: pointerinjector::Event) {
2047        // Set up fidl streams.
2048        let (configuration_proxy, mut configuration_request_stream) =
2049            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2050        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
2051            pointerinjector::RegistryMarker,
2052            pointerinjector_next::Registry,
2053        >();
2054        let config_request_stream_fut =
2055            handle_configuration_request_stream(&mut configuration_request_stream);
2056
2057        // Create MouseInjectorHandler.
2058        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2059        let inspector = fuchsia_inspect::Inspector::default();
2060        let test_node = inspector.root().create_child("test_node");
2061        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2062            configuration_proxy,
2063            injector_registry_proxy,
2064            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2065            sender,
2066            &test_node,
2067            metrics::MetricsLogger::default(),
2068        );
2069        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2070        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2071
2072        // Create a channel for the the registered device's handle to be forwarded to the
2073        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2074        // handle_input_event() to continue.
2075        let (injector_stream_sender, injector_stream_receiver) =
2076            mpsc::unbounded::<Vec<pointerinjector::Event>>();
2077        // Up to 2 events per handle_input_event() call.
2078        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
2079        let registry_fut = handle_registry_request_stream2(
2080            injector_registry_request_stream,
2081            injector_stream_sender,
2082        );
2083
2084        let event_time = zx::MonotonicInstant::get();
2085
2086        let event = input_device::InputEvent { event_time, ..event };
2087
2088        let want_event =
2089            pointerinjector::Event { timestamp: Some(event_time.into_nanos()), ..want_event };
2090
2091        // Run future until the handler future completes.
2092        let _registry_task = fasync::Task::local(registry_fut);
2093
2094        mouse_handler.clone().handle_input_event(event).await;
2095        let got_events: Vec<_> = injector_stream_receiver
2096            .next()
2097            .await
2098            .map(|events| events.into_iter().flatten().collect())
2099            .unwrap();
2100        pretty_assertions::assert_eq!(got_events.len(), 2);
2101        assert_matches!(
2102            got_events[0],
2103            pointerinjector::Event {
2104                data: Some(pointerinjector::Data::PointerSample(pointerinjector::PointerSample {
2105                    phase: Some(pointerinjector::EventPhase::Add),
2106                    ..
2107                })),
2108                ..
2109            }
2110        );
2111
2112        pretty_assertions::assert_eq!(got_events[1], want_event);
2113    }
2114
2115    /// Test button down -> scroll -> button up -> continue scroll.
2116    #[fuchsia::test(allow_stalls = false)]
2117    async fn down_scroll_up_scroll() {
2118        // Set up fidl streams.
2119        let (configuration_proxy, mut configuration_request_stream) =
2120            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2121        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
2122            pointerinjector::RegistryMarker,
2123            pointerinjector_next::Registry,
2124        >();
2125        let config_request_stream_fut =
2126            handle_configuration_request_stream(&mut configuration_request_stream);
2127
2128        // Create MouseInjectorHandler.
2129        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2130        let inspector = fuchsia_inspect::Inspector::default();
2131        let test_node = inspector.root().create_child("test_node");
2132        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2133            configuration_proxy,
2134            injector_registry_proxy,
2135            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2136            sender,
2137            &test_node,
2138            metrics::MetricsLogger::default(),
2139        );
2140        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2141        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2142
2143        // Create a channel for the the registered device's handle to be forwarded to the
2144        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2145        // handle_input_event() to continue.
2146        let (injector_stream_sender, injector_stream_receiver) =
2147            mpsc::unbounded::<Vec<pointerinjector::Event>>();
2148        // Up to 2 events per handle_input_event() call.
2149        let mut injector_stream_receiver = injector_stream_receiver.ready_chunks(2);
2150        let registry_fut = handle_registry_request_stream2(
2151            injector_registry_request_stream,
2152            injector_stream_sender,
2153        );
2154
2155        let event_time1 = zx::MonotonicInstant::get();
2156        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
2157        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
2158        let event_time4 = event_time3.add(zx::MonotonicDuration::from_micros(1));
2159
2160        // Run future until the handler future completes.
2161        let _registry_task = fasync::Task::local(registry_fut);
2162
2163        let zero_location =
2164            mouse_binding::MouseLocation::Relative(mouse_binding::RelativeLocation {
2165                millimeters: Position { x: 0.0, y: 0.0 },
2166            });
2167        let expected_position = Position { x: 50.0, y: 50.0 };
2168
2169        let down_event = create_mouse_event(
2170            zero_location,
2171            None, /* wheel_delta_v */
2172            None, /* wheel_delta_h */
2173            None, /* is_precision_scroll */
2174            mouse_binding::MousePhase::Down,
2175            HashSet::from_iter(vec![1]),
2176            HashSet::from_iter(vec![1]),
2177            event_time1,
2178            &DESCRIPTOR,
2179        );
2180
2181        let wheel_event = create_mouse_event(
2182            zero_location,
2183            wheel_delta_ticks(1, None),               /* wheel_delta_v */
2184            None,                                     /* wheel_delta_h */
2185            Some(mouse_binding::PrecisionScroll::No), /* is_precision_scroll */
2186            mouse_binding::MousePhase::Wheel,
2187            HashSet::from_iter(vec![1]),
2188            HashSet::from_iter(vec![1]),
2189            event_time2,
2190            &DESCRIPTOR,
2191        );
2192
2193        let up_event = create_mouse_event(
2194            zero_location,
2195            None,
2196            None,
2197            None, /* is_precision_scroll */
2198            mouse_binding::MousePhase::Up,
2199            HashSet::from_iter(vec![1]),
2200            HashSet::new(),
2201            event_time3,
2202            &DESCRIPTOR,
2203        );
2204
2205        let continue_wheel_event = create_mouse_event(
2206            zero_location,
2207            wheel_delta_ticks(1, None),               /* wheel_delta_v */
2208            None,                                     /* wheel_delta_h */
2209            Some(mouse_binding::PrecisionScroll::No), /* is_precision_scroll */
2210            mouse_binding::MousePhase::Wheel,
2211            HashSet::new(),
2212            HashSet::new(),
2213            event_time4,
2214            &DESCRIPTOR,
2215        );
2216
2217        // Handle button down event.
2218        mouse_handler.clone().handle_input_event(down_event).await;
2219        assert_eq!(
2220            injector_stream_receiver
2221                .next()
2222                .await
2223                .map(|events| events.into_iter().flatten().collect()),
2224            Some(vec![
2225                create_mouse_pointer_sample_event_phase_add(
2226                    vec![1],
2227                    expected_position,
2228                    event_time1,
2229                ),
2230                create_mouse_pointer_sample_event(
2231                    pointerinjector::EventPhase::Change,
2232                    vec![1],
2233                    expected_position,
2234                    None, /*relative_motion*/
2235                    None, /*wheel_delta_v*/
2236                    None, /*wheel_delta_h*/
2237                    None, /*is_precision_scroll*/
2238                    event_time1,
2239                ),
2240            ])
2241        );
2242
2243        // Handle wheel event with button pressing.
2244        mouse_handler.clone().handle_input_event(wheel_event).await;
2245        assert_eq!(
2246            injector_stream_receiver
2247                .next()
2248                .await
2249                .map(|events| events.into_iter().flatten().collect()),
2250            Some(vec![create_mouse_pointer_sample_event(
2251                pointerinjector::EventPhase::Change,
2252                vec![1],
2253                expected_position,
2254                None,        /*relative_motion*/
2255                Some(1),     /*wheel_delta_v*/
2256                None,        /*wheel_delta_h*/
2257                Some(false), /*is_precision_scroll*/
2258                event_time2,
2259            )])
2260        );
2261
2262        // Handle button up event.
2263        mouse_handler.clone().handle_input_event(up_event).await;
2264        assert_eq!(
2265            injector_stream_receiver
2266                .next()
2267                .await
2268                .map(|events| events.into_iter().flatten().collect()),
2269            Some(vec![create_mouse_pointer_sample_event(
2270                pointerinjector::EventPhase::Change,
2271                vec![],
2272                expected_position,
2273                None, /*relative_motion*/
2274                None, /*wheel_delta_v*/
2275                None, /*wheel_delta_h*/
2276                None, /*is_precision_scroll*/
2277                event_time3,
2278            )])
2279        );
2280
2281        // Handle wheel event after button released.
2282        mouse_handler.clone().handle_input_event(continue_wheel_event).await;
2283        assert_eq!(
2284            injector_stream_receiver
2285                .next()
2286                .await
2287                .map(|events| events.into_iter().flatten().collect()),
2288            Some(vec![create_mouse_pointer_sample_event(
2289                pointerinjector::EventPhase::Change,
2290                vec![],
2291                expected_position,
2292                None,        /*relative_motion*/
2293                Some(1),     /*wheel_delta_v*/
2294                None,        /*wheel_delta_h*/
2295                Some(false), /*is_precision_scroll*/
2296                event_time4,
2297            )])
2298        );
2299    }
2300
2301    #[fuchsia::test(allow_stalls = false)]
2302    async fn mouse_injector_handler_initialized_with_inspect_node() {
2303        let (configuration_proxy, mut configuration_request_stream) =
2304            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2305        let config_request_stream_fut =
2306            handle_configuration_request_stream(&mut configuration_request_stream);
2307        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2308        let inspector = fuchsia_inspect::Inspector::default();
2309        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
2310        let incoming = Incoming::new();
2311        let mouse_handler_fut = MouseInjectorHandler::new_with_config_proxy(
2312            &incoming,
2313            configuration_proxy,
2314            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2315            sender,
2316            &fake_handlers_node,
2317            metrics::MetricsLogger::default(),
2318        );
2319        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2320        let _handler = mouse_handler_res.expect("Failed to create mouse handler");
2321
2322        diagnostics_assertions::assert_data_tree!(inspector, root: {
2323            input_handlers_node: {
2324                mouse_injector_handler: {
2325                    events_received_count: 0u64,
2326                    events_handled_count: 0u64,
2327                    last_received_timestamp_ns: 0u64,
2328                    "fuchsia.inspect.Health": {
2329                        status: "STARTING_UP",
2330                        // Timestamp value is unpredictable and not relevant in this context,
2331                        // so we only assert that the property is present.
2332                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
2333                    },
2334                }
2335            }
2336        });
2337    }
2338
2339    #[fuchsia::test(allow_stalls = false)]
2340    async fn mouse_injector_handler_inspect_counts_events() {
2341        // Set up fidl streams.
2342        let (configuration_proxy, mut configuration_request_stream) =
2343            fidl::endpoints::create_proxy_and_stream::<pointerinjector_config::SetupMarker>();
2344        let (injector_registry_proxy, injector_registry_request_stream) = next_client_old_stream::<
2345            pointerinjector::RegistryMarker,
2346            pointerinjector_next::Registry,
2347        >();
2348        let (sender, _) = futures::channel::mpsc::channel::<CursorMessage>(1);
2349
2350        let inspector = fuchsia_inspect::Inspector::default();
2351        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
2352
2353        // Create mouse handler.
2354        let mouse_handler_fut = MouseInjectorHandler::new_handler(
2355            configuration_proxy,
2356            injector_registry_proxy,
2357            Size { width: DISPLAY_WIDTH_IN_PHYSICAL_PX, height: DISPLAY_HEIGHT_IN_PHYSICAL_PX },
2358            sender,
2359            &fake_handlers_node,
2360            metrics::MetricsLogger::default(),
2361        );
2362        let config_request_stream_fut =
2363            handle_configuration_request_stream(&mut configuration_request_stream);
2364
2365        let (mouse_handler_res, _) = futures::join!(mouse_handler_fut, config_request_stream_fut);
2366        let mouse_handler = mouse_handler_res.expect("Failed to create mouse handler");
2367
2368        let cursor_location = mouse_binding::MouseLocation::Absolute(Position { x: 0.0, y: 0.0 });
2369        let event_time1 = zx::MonotonicInstant::get();
2370        let event_time2 = event_time1.add(zx::MonotonicDuration::from_micros(1));
2371        let event_time3 = event_time2.add(zx::MonotonicDuration::from_micros(1));
2372
2373        let input_events = vec![
2374            create_mouse_event(
2375                cursor_location,
2376                None, /* wheel_delta_v */
2377                None, /* wheel_delta_h */
2378                None, /* is_precision_scroll */
2379                mouse_binding::MousePhase::Down,
2380                HashSet::from_iter(vec![1]),
2381                HashSet::from_iter(vec![1]),
2382                event_time1,
2383                &DESCRIPTOR,
2384            ),
2385            create_mouse_event(
2386                cursor_location,
2387                None, /* wheel_delta_v */
2388                None, /* wheel_delta_h */
2389                None, /* is_precision_scroll */
2390                mouse_binding::MousePhase::Up,
2391                HashSet::from_iter(vec![1]),
2392                HashSet::new(),
2393                event_time2,
2394                &DESCRIPTOR,
2395            ),
2396            create_mouse_event_with_handled(
2397                cursor_location,
2398                None, /* wheel_delta_v */
2399                None, /* wheel_delta_h */
2400                None, /* is_precision_scroll */
2401                mouse_binding::MousePhase::Down,
2402                HashSet::from_iter(vec![1]),
2403                HashSet::from_iter(vec![1]),
2404                event_time3,
2405                &DESCRIPTOR,
2406                input_device::Handled::Yes,
2407            ),
2408        ];
2409
2410        // Create a channel for the the registered device's handle to be forwarded to the
2411        // DeviceRequestStream handler. This allows the registry_fut to complete and allows
2412        // handle_input_event() to continue.
2413        let (injector_stream_sender, _) = mpsc::unbounded::<Vec<pointerinjector::Event>>();
2414        let registry_fut = handle_registry_request_stream2(
2415            injector_registry_request_stream,
2416            injector_stream_sender,
2417        );
2418
2419        // Run future until the handler future completes.
2420        let _registry_task = fasync::Task::local(registry_fut);
2421        for input_event in input_events {
2422            mouse_handler.clone().handle_input_event(input_event).await;
2423        }
2424
2425        let last_received_event_time: u64 = event_time2.into_nanos().try_into().unwrap();
2426
2427        diagnostics_assertions::assert_data_tree!(inspector, root: {
2428            input_handlers_node: {
2429                mouse_injector_handler: {
2430                    events_received_count: 2u64,
2431                    events_handled_count: 2u64,
2432                    last_received_timestamp_ns: last_received_event_time,
2433                    "fuchsia.inspect.Health": {
2434                        status: "STARTING_UP",
2435                        // Timestamp value is unpredictable and not relevant in this context,
2436                        // so we only assert that the property is present.
2437                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
2438                    },
2439                }
2440            }
2441        });
2442    }
2443}