Skip to main content

input_pipeline/
display_ownership.rs

1// Copyright 2022 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
5use crate::input_device::{self, InputEvent, UnhandledInputEvent};
6use crate::input_handler::{Handler, InputHandlerStatus, UnhandledInputHandler};
7use crate::keyboard_binding::{KeyboardDeviceDescriptor, KeyboardEvent};
8use crate::metrics;
9use anyhow::{Context, Result};
10use async_trait::async_trait;
11use fidl_fuchsia_ui_composition_internal as fcomp;
12use fidl_fuchsia_ui_input3::KeyEventType;
13use fuchsia_async::{OnSignals, Task};
14use fuchsia_inspect::health::Reporter;
15use futures::StreamExt;
16use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
17use keymaps::KeyState;
18use metrics_registry::InputPipelineErrorMetricDimensionEvent;
19use std::cell::RefCell;
20use std::rc::Rc;
21use std::sync::LazyLock;
22use zx::{AsHandleRef, MonotonicDuration, MonotonicInstant, Signals, Status};
23
24// The signal value corresponding to the `DISPLAY_OWNED_SIGNAL`.  Same as zircon's signal
25// USER_0.
26static DISPLAY_OWNED: LazyLock<Signals> = LazyLock::new(|| {
27    Signals::from_bits(fcomp::SIGNAL_DISPLAY_OWNED).expect("static init should not fail")
28});
29
30// The signal value corresponding to the `DISPLAY_NOT_OWNED_SIGNAL`.  Same as zircon's signal
31// USER_1.
32static DISPLAY_UNOWNED: LazyLock<Signals> = LazyLock::new(|| {
33    Signals::from_bits(fcomp::SIGNAL_DISPLAY_NOT_OWNED).expect("static init should not fail")
34});
35
36// Any display-related signal.
37static ANY_DISPLAY_EVENT: LazyLock<Signals> = LazyLock::new(|| *DISPLAY_OWNED | *DISPLAY_UNOWNED);
38
39// Stores the last received ownership signals.
40#[derive(Debug, Clone, PartialEq)]
41struct Ownership {
42    signals: Signals,
43}
44
45impl std::convert::From<Signals> for Ownership {
46    fn from(signals: Signals) -> Self {
47        Ownership { signals }
48    }
49}
50
51impl Ownership {
52    // Returns true if the display is currently indicated to be not owned by
53    // Scenic.
54    fn is_display_ownership_lost(&self) -> bool {
55        self.signals.contains(*DISPLAY_UNOWNED)
56    }
57
58    // Returns the mask of the next signal to watch.
59    //
60    // Since the ownership alternates, so does the next signal to wait on.
61    fn next_signal(&self) -> Signals {
62        match self.is_display_ownership_lost() {
63            true => *DISPLAY_OWNED,
64            false => *DISPLAY_UNOWNED,
65        }
66    }
67
68    /// Waits for the next signal change.
69    ///
70    /// If the display is owned, it will wait for display to become unowned.
71    /// If the display is unowned, it will wait for the display to become owned.
72    async fn wait_ownership_change<'a, T: AsHandleRef>(
73        &self,
74        event: &'a T,
75    ) -> Result<Signals, Status> {
76        OnSignals::new(event, self.next_signal()).await
77    }
78}
79
80/// A handler that turns the input pipeline off or on based on whether
81/// the Scenic owns the display.
82///
83/// This allows us to turn off keyboard processing when the user switches away
84/// from the product (e.g. terminal) into virtual console.
85///
86/// See the `README.md` file in this crate for details.
87///
88/// # Safety and Concurrency
89///
90/// This struct uses `RefCell` to manage internal state. While `DisplayOwnership`
91/// logic is split between multiple tasks (`handle_ownership_change` and
92/// `handle_unhandled_input_event`), safety is maintained because:
93/// 1. The pipeline runs on a single-threaded `LocalExecutor`.
94/// 2. Borrows of `RefCell`s (like `ownership` and `key_state`) are never held
95///    across `await` points.
96///
97/// If asynchronous calls are added to critical sections in the future,
98/// ensure that all borrows are dropped before the `await`.
99pub struct DisplayOwnership {
100    /// The current view of the display ownership.  It is mutated by the
101    /// display ownership task when appropriate signals arrive.
102    ownership: Rc<RefCell<Ownership>>,
103
104    /// The registry of currently pressed keys.
105    key_state: RefCell<KeyState>,
106
107    /// The source of ownership change events for the main loop.
108    display_ownership_change_receiver: RefCell<Option<UnboundedReceiver<Ownership>>>,
109
110    /// A background task that watches for display ownership changes.  We keep
111    /// it alive to ensure that it keeps running.
112    _display_ownership_task: Task<()>,
113
114    /// The metrics logger.
115    metrics_logger: metrics::MetricsLogger,
116
117    /// The inventory of this handler's Inspect status.
118    inspect_status: InputHandlerStatus,
119
120    /// The event processing loop will do an `unbounded_send(())` on this
121    /// channel once at the end of each loop pass, in test configurations only.
122    /// The test fixture uses this channel to execute test fixture in
123    /// lock-step with the event processing loop for test cases where the
124    /// precise event sequencing is relevant.
125    #[cfg(test)]
126    loop_done: RefCell<Option<UnboundedSender<()>>>,
127}
128
129impl DisplayOwnership {
130    /// Creates a new handler that watches `display_ownership_event` for events.
131    ///
132    /// The `display_ownership_event` is assumed to be an [Event] obtained from
133    /// `fuchsia.ui.composition.internal.DisplayOwnership/GetEvent`.  There
134    /// isn't really a way for this code to know here whether this is true or
135    /// not, so implementor beware.
136    pub fn new(
137        display_ownership_event: impl AsHandleRef + 'static,
138        input_handlers_node: &fuchsia_inspect::Node,
139        metrics_logger: metrics::MetricsLogger,
140    ) -> Rc<Self> {
141        DisplayOwnership::new_internal(
142            display_ownership_event,
143            None,
144            input_handlers_node,
145            metrics_logger,
146        )
147    }
148
149    #[cfg(test)]
150    pub fn new_for_test(
151        display_ownership_event: impl AsHandleRef + 'static,
152        loop_done: UnboundedSender<()>,
153        metrics_logger: metrics::MetricsLogger,
154    ) -> Rc<Self> {
155        let inspector = fuchsia_inspect::Inspector::default();
156        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
157        DisplayOwnership::new_internal(
158            display_ownership_event,
159            Some(loop_done),
160            &fake_handlers_node,
161            metrics_logger,
162        )
163    }
164
165    fn new_internal(
166        display_ownership_event: impl AsHandleRef + 'static,
167        _loop_done: Option<UnboundedSender<()>>,
168        input_handlers_node: &fuchsia_inspect::Node,
169        metrics_logger: metrics::MetricsLogger,
170    ) -> Rc<Self> {
171        let initial_state = display_ownership_event
172            // scenic guarantees that ANY_DISPLAY_EVENT is asserted. If it is
173            // not, this will fail with a timeout error.
174            .as_handle_ref()
175            .wait_one(*ANY_DISPLAY_EVENT, MonotonicInstant::INFINITE_PAST)
176            .expect("unable to set the initial display state");
177        log::debug!("setting initial display ownership to: {:?}", &initial_state);
178        let initial_ownership: Ownership = initial_state.into();
179        let ownership = Rc::new(RefCell::new(initial_ownership.clone()));
180
181        let mut ownership_clone = initial_ownership;
182        let (ownership_sender, ownership_receiver) = mpsc::unbounded();
183        let display_ownership_task = Task::local(async move {
184            loop {
185                let signals = ownership_clone.wait_ownership_change(&display_ownership_event).await;
186                match signals {
187                    Err(e) => {
188                        log::warn!("could not read display state: {:?}", e);
189                        break;
190                    }
191                    Ok(signals) => {
192                        log::debug!("setting display ownership to: {:?}", &signals);
193                        ownership_sender.unbounded_send(signals.into()).unwrap();
194                        ownership_clone = signals.into();
195                    }
196                }
197            }
198            log::warn!(
199                "display loop exiting and will no longer monitor display changes - this is not expected"
200            );
201        });
202        log::info!("Display ownership handler installed");
203        let inspect_status = InputHandlerStatus::new(
204            input_handlers_node,
205            "display_ownership",
206            /* generates_events */ false,
207        );
208        Rc::new(Self {
209            ownership,
210            key_state: RefCell::new(KeyState::new()),
211            display_ownership_change_receiver: RefCell::new(Some(ownership_receiver)),
212            _display_ownership_task: display_ownership_task,
213            metrics_logger,
214            inspect_status,
215            #[cfg(test)]
216            loop_done: RefCell::new(_loop_done),
217        })
218    }
219
220    /// Returns true if the display is currently *not* owned by Scenic.
221    fn is_display_ownership_lost(&self) -> bool {
222        self.ownership.borrow().is_display_ownership_lost()
223    }
224
225    /// Watches for display ownership changes and sends cancel/sync events.
226    ///
227    /// NOTE: RefCell safety relies on the single-threaded nature of the executor.
228    /// No borrows of `ownership` or `key_state` must be held across the `await`
229    /// below to avoid panics if `handle_unhandled_input_event` runs while this
230    /// task is suspended.
231    pub async fn handle_ownership_change(
232        self: &Rc<Self>,
233        output: UnboundedSender<Vec<InputEvent>>,
234    ) -> Result<()> {
235        let mut ownership_source = self
236            .display_ownership_change_receiver
237            .borrow_mut()
238            .take()
239            .context("display_ownership_change_receiver already taken")?;
240        while let Some(new_ownership) = ownership_source.next().await {
241            let is_display_ownership_lost = new_ownership.is_display_ownership_lost();
242            // When the ownership is modified, float a set of cancel or sync
243            // events to scoop up stale keyboard state, treating it the same
244            // as loss of focus.
245            let event_type = match is_display_ownership_lost {
246                true => KeyEventType::Cancel,
247                false => KeyEventType::Sync,
248            };
249            let keys = self.key_state.borrow().get_set();
250            let mut event_time = MonotonicInstant::get();
251            for key in keys.into_iter() {
252                let key_event = KeyboardEvent::new(key, event_type);
253                output
254                    .unbounded_send(vec![into_input_event(key_event, event_time)])
255                    .context("unable to send display updates")?;
256                event_time = event_time + MonotonicDuration::from_nanos(1);
257            }
258            *(self.ownership.borrow_mut()) = new_ownership;
259            #[cfg(test)]
260            {
261                if let Some(loop_done) = self.loop_done.borrow().as_ref() {
262                    loop_done.unbounded_send(()).unwrap();
263                }
264            }
265        }
266        Ok(())
267    }
268}
269
270impl Handler for DisplayOwnership {
271    fn set_handler_healthy(self: std::rc::Rc<Self>) {
272        self.inspect_status.health_node.borrow_mut().set_ok();
273    }
274
275    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
276        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
277    }
278
279    fn get_name(&self) -> &'static str {
280        "DisplayOwnership"
281    }
282
283    fn interest(&self) -> Vec<input_device::InputEventType> {
284        vec![input_device::InputEventType::Keyboard]
285    }
286}
287
288#[async_trait(?Send)]
289impl UnhandledInputHandler for DisplayOwnership {
290    async fn handle_unhandled_input_event(
291        self: Rc<Self>,
292        unhandled_input_event: UnhandledInputEvent,
293    ) -> Vec<input_device::InputEvent> {
294        fuchsia_trace::duration!("input", "display_ownership");
295        self.inspect_status.count_received_event(&unhandled_input_event.event_time);
296        match unhandled_input_event.device_event {
297            input_device::InputDeviceEvent::Keyboard(ref e) => {
298                self.key_state.borrow_mut().update(e.get_event_type(), e.get_key());
299            }
300            _ => {
301                self.metrics_logger.log_error(
302                    InputPipelineErrorMetricDimensionEvent::HandlerReceivedUninterestedEvent,
303                    std::format!(
304                        "uninterested input event: {:?}",
305                        unhandled_input_event.get_event_type()
306                    ),
307                );
308            }
309        }
310        let is_display_ownership_lost = self.is_display_ownership_lost();
311        if is_display_ownership_lost {
312            self.inspect_status.count_handled_event();
313        }
314
315        #[cfg(test)]
316        {
317            if let Some(loop_done) = self.loop_done.borrow().as_ref() {
318                loop_done.unbounded_send(()).unwrap();
319            }
320        }
321
322        vec![
323            input_device::InputEvent::from(unhandled_input_event)
324                .into_handled_if(is_display_ownership_lost),
325        ]
326    }
327}
328
329fn empty_keyboard_device_descriptor() -> input_device::InputDeviceDescriptor {
330    input_device::InputDeviceDescriptor::Keyboard(
331        // Should descriptor be something sensible?
332        KeyboardDeviceDescriptor {
333            keys: vec![],
334            device_information: fidl_fuchsia_input_report::DeviceInformation {
335                vendor_id: Some(0),
336                product_id: Some(0),
337                version: Some(0),
338                polling_rate: Some(0),
339                ..Default::default()
340            },
341            device_id: 0,
342        },
343    )
344}
345
346fn into_input_event(
347    keyboard_event: KeyboardEvent,
348    event_time: MonotonicInstant,
349) -> input_device::InputEvent {
350    input_device::InputEvent {
351        device_event: input_device::InputDeviceEvent::Keyboard(keyboard_event),
352        device_descriptor: empty_keyboard_device_descriptor(),
353        event_time,
354        handled: input_device::Handled::No,
355        trace_id: None,
356    }
357}
358
359#[cfg(test)]
360mod tests {
361    use super::*;
362    use crate::testing_utilities::{create_fake_input_event, create_input_event};
363    use fidl_fuchsia_input::Key;
364    use fuchsia_async as fasync;
365    use pretty_assertions::assert_eq;
366    use std::convert::TryFrom as _;
367    use zx::{EventPair, Peered};
368
369    // Manages losing and regaining display, since manual management is error-prone:
370    // if signal_peer does not change the signal state, the waiting process will block
371    // forever, which makes tests run longer than needed.
372    struct DisplayWrangler {
373        event: EventPair,
374        last: Signals,
375    }
376
377    impl DisplayWrangler {
378        fn new(event: EventPair) -> Self {
379            let mut instance = DisplayWrangler { event, last: *DISPLAY_OWNED };
380            // Signal needs to be initialized before the handlers attempts to read it.
381            // This is normally always the case in production.
382            // Else, the `new_for_test` below will panic with a TIMEOUT error.
383            instance.set_unowned();
384            instance
385        }
386
387        fn set_unowned(&mut self) {
388            assert!(self.last != *DISPLAY_UNOWNED, "display is already unowned");
389            self.event.signal_peer(*DISPLAY_OWNED, *DISPLAY_UNOWNED).unwrap();
390            self.last = *DISPLAY_UNOWNED;
391        }
392
393        fn set_owned(&mut self) {
394            assert!(self.last != *DISPLAY_OWNED, "display is already owned");
395            self.event.signal_peer(*DISPLAY_UNOWNED, *DISPLAY_OWNED).unwrap();
396            self.last = *DISPLAY_OWNED;
397        }
398    }
399
400    #[fuchsia::test]
401    async fn display_ownership_change() {
402        // handler_event is the event that the unit under test will examine for
403        // display ownership changes.  test_event is used to set the appropriate
404        // signals.
405        let (test_event, handler_event) = EventPair::create();
406
407        // test_sender is used to pipe input events into the handler.
408        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
409
410        // test_receiver is used to pipe input events out of the handler.
411        let (handler_sender, test_receiver) = mpsc::unbounded::<Vec<InputEvent>>();
412
413        // The unit under test adds a () each time it completes one pass through
414        // its event loop.  Use to ensure synchronization.
415        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
416
417        // We use a wrapper to signal test_event correctly, since doing it wrong
418        // by hand causes tests to hang, which isn't the best dev experience.
419        let mut wrangler = DisplayWrangler::new(test_event);
420        let handler = DisplayOwnership::new_for_test(
421            handler_event,
422            loop_done_sender,
423            metrics::MetricsLogger::default(),
424        );
425
426        let handler_clone = handler.clone();
427        let handler_sender_clone = handler_sender.clone();
428        let _task = fasync::Task::local(async move {
429            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
430        });
431
432        let handler_clone_2 = handler.clone();
433        let _input_task = fasync::Task::local(async move {
434            let mut receiver = handler_receiver;
435            while let Some(event) = receiver.next().await {
436                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
437                let out_events =
438                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
439                handler_sender.unbounded_send(out_events).unwrap();
440            }
441        });
442
443        let fake_time = MonotonicInstant::from_nanos(42);
444
445        // Go two full circles of signaling.
446
447        // 1
448        wrangler.set_owned();
449        loop_done.next().await;
450        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
451        loop_done.next().await;
452
453        // 2
454        wrangler.set_unowned();
455        loop_done.next().await;
456        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
457        loop_done.next().await;
458
459        // 3
460        wrangler.set_owned();
461        loop_done.next().await;
462        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
463        loop_done.next().await;
464
465        // 4
466        wrangler.set_unowned();
467        loop_done.next().await;
468        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
469        loop_done.next().await;
470
471        let actual: Vec<InputEvent> = test_receiver
472            .take(4)
473            .flat_map(|events| futures::stream::iter(events))
474            .map(|e| e.into_with_event_time(fake_time))
475            .collect()
476            .await;
477
478        assert_eq!(
479            actual,
480            vec![
481                // Event received while we owned the display.
482                create_fake_input_event(fake_time),
483                // Event received when we lost the display.
484                create_fake_input_event(fake_time).into_handled(),
485                // Display ownership regained.
486                create_fake_input_event(fake_time),
487                // Display ownership lost.
488                create_fake_input_event(fake_time).into_handled(),
489            ]
490        );
491    }
492
493    fn new_keyboard_input_event(key: Key, event_type: KeyEventType) -> InputEvent {
494        let fake_time = MonotonicInstant::from_nanos(42);
495        create_input_event(
496            KeyboardEvent::new(key, event_type),
497            &input_device::InputDeviceDescriptor::Fake,
498            fake_time,
499            input_device::Handled::No,
500        )
501    }
502
503    #[fuchsia::test]
504    async fn basic_key_state_handling() {
505        let (test_event, handler_event) = EventPair::create();
506        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
507        let (handler_sender, test_receiver) = mpsc::unbounded::<Vec<InputEvent>>();
508        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
509        let mut wrangler = DisplayWrangler::new(test_event);
510        let handler = DisplayOwnership::new_for_test(
511            handler_event,
512            loop_done_sender,
513            metrics::MetricsLogger::default(),
514        );
515
516        let handler_clone = handler.clone();
517        let handler_sender_clone = handler_sender.clone();
518        let _task = fasync::Task::local(async move {
519            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
520        });
521
522        let handler_clone_2 = handler.clone();
523        let _input_task = fasync::Task::local(async move {
524            let mut receiver = handler_receiver;
525            while let Some(event) = receiver.next().await {
526                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
527                let out_events =
528                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
529                handler_sender.unbounded_send(out_events).unwrap();
530            }
531        });
532
533        let fake_time = MonotonicInstant::from_nanos(42);
534
535        // Gain the display, and press a key.
536        wrangler.set_owned();
537        loop_done.next().await;
538        test_sender
539            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
540            .unwrap();
541        loop_done.next().await;
542
543        // Lose display.
544        wrangler.set_unowned();
545        loop_done.next().await;
546
547        // Regain display
548        wrangler.set_owned();
549        loop_done.next().await;
550
551        // Key event after regaining.
552        test_sender
553            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
554            .unwrap();
555        loop_done.next().await;
556
557        let actual: Vec<InputEvent> = test_receiver
558            .take(4)
559            .flat_map(|events| futures::stream::iter(events))
560            .map(|e| e.into_with_event_time(fake_time))
561            .collect()
562            .await;
563
564        assert_eq!(
565            actual,
566            vec![
567                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
568                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
569                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
570                new_keyboard_input_event(Key::A, KeyEventType::Sync)
571                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
572                new_keyboard_input_event(Key::A, KeyEventType::Released),
573            ]
574        );
575    }
576
577    #[fuchsia::test]
578    async fn more_key_state_handling() {
579        let (test_event, handler_event) = EventPair::create();
580        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
581        let (handler_sender, test_receiver) = mpsc::unbounded::<Vec<InputEvent>>();
582        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
583        let mut wrangler = DisplayWrangler::new(test_event);
584        let handler = DisplayOwnership::new_for_test(
585            handler_event,
586            loop_done_sender,
587            metrics::MetricsLogger::default(),
588        );
589
590        let handler_clone = handler.clone();
591        let handler_sender_clone = handler_sender.clone();
592        let _task = fasync::Task::local(async move {
593            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
594        });
595
596        let handler_clone_2 = handler.clone();
597        let _input_task = fasync::Task::local(async move {
598            let mut receiver = handler_receiver;
599            while let Some(event) = receiver.next().await {
600                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
601                let out_events =
602                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
603                handler_sender.unbounded_send(out_events).unwrap();
604            }
605        });
606
607        let fake_time = MonotonicInstant::from_nanos(42);
608
609        wrangler.set_owned();
610        loop_done.next().await;
611        test_sender
612            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
613            .unwrap();
614        loop_done.next().await;
615        test_sender
616            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
617            .unwrap();
618        loop_done.next().await;
619
620        // Lose display, release a key, press a key.
621        wrangler.set_unowned();
622        loop_done.next().await;
623        test_sender
624            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Released))
625            .unwrap();
626        loop_done.next().await;
627        test_sender
628            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Pressed))
629            .unwrap();
630        loop_done.next().await;
631
632        // Regain display
633        wrangler.set_owned();
634        loop_done.next().await;
635
636        // Key event after regaining.
637        test_sender
638            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
639            .unwrap();
640        loop_done.next().await;
641        test_sender
642            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Released))
643            .unwrap();
644        loop_done.next().await;
645
646        let actual: Vec<InputEvent> = test_receiver
647            .take(10) // 2 pressed, 2 cancelled, 1 released (handled), 1 pressed (handled), 2 synced, 2 released
648            .flat_map(|events| futures::stream::iter(events))
649            .map(|e| e.into_with_event_time(fake_time))
650            .collect()
651            .await;
652
653        assert_eq!(
654            actual,
655            vec![
656                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
657                new_keyboard_input_event(Key::B, KeyEventType::Pressed),
658                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
659                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
660                new_keyboard_input_event(Key::B, KeyEventType::Cancel)
661                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
662                new_keyboard_input_event(Key::B, KeyEventType::Released).into_handled(),
663                new_keyboard_input_event(Key::C, KeyEventType::Pressed).into_handled(),
664                // The CANCEL and SYNC events are emitted in the sort ordering of the
665                // `Key` enum values. Perhaps they should be emitted instead in the order
666                // they have been received for SYNC, and in reverse order for CANCEL.
667                new_keyboard_input_event(Key::A, KeyEventType::Sync)
668                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
669                new_keyboard_input_event(Key::C, KeyEventType::Sync)
670                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
671                new_keyboard_input_event(Key::A, KeyEventType::Released),
672                new_keyboard_input_event(Key::C, KeyEventType::Released),
673            ]
674        );
675    }
676
677    #[fuchsia::test]
678    async fn display_ownership_initialized_with_inspect_node() {
679        let (test_event, handler_event) = EventPair::create();
680        let (loop_done_sender, _) = mpsc::unbounded::<()>();
681        let inspector = fuchsia_inspect::Inspector::default();
682        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
683        // Signal needs to be initialized first so DisplayOwnership::new doesn't panic with a TIMEOUT error
684        let _ = DisplayWrangler::new(test_event);
685        let _handler = DisplayOwnership::new_internal(
686            handler_event,
687            Some(loop_done_sender),
688            &fake_handlers_node,
689            metrics::MetricsLogger::default(),
690        );
691        diagnostics_assertions::assert_data_tree!(inspector, root: {
692            input_handlers_node: {
693                display_ownership: {
694                    events_received_count: 0u64,
695                    events_handled_count: 0u64,
696                    last_received_timestamp_ns: 0u64,
697                    "fuchsia.inspect.Health": {
698                        status: "STARTING_UP",
699                        // Timestamp value is unpredictable and not relevant in this context,
700                        // so we only assert that the property is present.
701                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
702                    },
703                }
704            }
705        });
706    }
707
708    #[fuchsia::test]
709    async fn display_ownership_inspect_counts_events() {
710        let (test_event, handler_event) = EventPair::create();
711        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
712        let (handler_sender, _test_receiver) = mpsc::unbounded::<Vec<InputEvent>>();
713        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
714        let mut wrangler = DisplayWrangler::new(test_event);
715        let inspector = fuchsia_inspect::Inspector::default();
716        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
717        let handler = DisplayOwnership::new_internal(
718            handler_event,
719            Some(loop_done_sender),
720            &fake_handlers_node,
721            metrics::MetricsLogger::default(),
722        );
723        let handler_clone = handler.clone();
724        let handler_sender_clone = handler_sender.clone();
725        let _task = fasync::Task::local(async move {
726            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
727        });
728
729        let handler_clone_2 = handler.clone();
730        let _input_task = fasync::Task::local(async move {
731            let mut receiver = handler_receiver;
732            while let Some(event) = receiver.next().await {
733                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
734                let out_events =
735                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
736                handler_sender.unbounded_send(out_events).unwrap();
737            }
738        });
739
740        // Gain the display, and press a key.
741        wrangler.set_owned();
742        loop_done.next().await;
743        test_sender
744            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
745            .unwrap();
746        loop_done.next().await;
747
748        // Lose display
749        // Input event is marked `Handled` if received after display ownership is lost
750        wrangler.set_unowned();
751        loop_done.next().await;
752        test_sender
753            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
754            .unwrap();
755        loop_done.next().await;
756
757        // Regain display
758        wrangler.set_owned();
759        loop_done.next().await;
760
761        // Key event after regaining.
762        test_sender
763            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
764            .unwrap();
765        loop_done.next().await;
766
767        diagnostics_assertions::assert_data_tree!(inspector, root: {
768            input_handlers_node: {
769                display_ownership: {
770                    events_received_count: 3u64,
771                    events_handled_count: 1u64,
772                    last_received_timestamp_ns: 42u64,
773                    "fuchsia.inspect.Health": {
774                        status: "STARTING_UP",
775                        // Timestamp value is unpredictable and not relevant in this context,
776                        // so we only assert that the property is present.
777                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
778                    },
779                }
780            }
781        });
782    }
783}