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