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::{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<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(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
255#[async_trait(?Send)]
256impl UnhandledInputHandler for DisplayOwnership {
257    async fn handle_unhandled_input_event(
258        self: Rc<Self>,
259        unhandled_input_event: UnhandledInputEvent,
260    ) -> Vec<input_device::InputEvent> {
261        fuchsia_trace::duration!("input", "display_ownership");
262        self.inspect_status.count_received_event(&unhandled_input_event.event_time);
263        match unhandled_input_event.device_event {
264            input_device::InputDeviceEvent::Keyboard(ref e) => {
265                self.key_state.borrow_mut().update(e.get_event_type(), e.get_key());
266            }
267            _ => {
268                // TODO: b/478249522 - add cobalt logging
269                log::warn!("Unhandled input event: {:?}", unhandled_input_event.get_event_type());
270            }
271        }
272        let is_display_ownership_lost = self.is_display_ownership_lost();
273        if is_display_ownership_lost {
274            self.inspect_status.count_handled_event();
275        }
276
277        #[cfg(test)]
278        {
279            if let Some(loop_done) = self.loop_done.borrow().as_ref() {
280                loop_done.unbounded_send(()).unwrap();
281            }
282        }
283
284        vec![
285            input_device::InputEvent::from(unhandled_input_event)
286                .into_handled_if(is_display_ownership_lost),
287        ]
288    }
289
290    fn set_handler_healthy(self: std::rc::Rc<Self>) {
291        self.inspect_status.health_node.borrow_mut().set_ok();
292    }
293
294    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
295        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
296    }
297
298    fn get_name(&self) -> &'static str {
299        "DisplayOwnership"
300    }
301
302    fn interest(&self) -> Vec<input_device::InputEventType> {
303        vec![input_device::InputEventType::Keyboard]
304    }
305}
306
307fn empty_keyboard_device_descriptor() -> input_device::InputDeviceDescriptor {
308    input_device::InputDeviceDescriptor::Keyboard(
309        // Should descriptor be something sensible?
310        KeyboardDeviceDescriptor {
311            keys: vec![],
312            device_information: fidl_fuchsia_input_report::DeviceInformation {
313                vendor_id: Some(0),
314                product_id: Some(0),
315                version: Some(0),
316                polling_rate: Some(0),
317                ..Default::default()
318            },
319            device_id: 0,
320        },
321    )
322}
323
324fn into_input_event(
325    keyboard_event: KeyboardEvent,
326    event_time: MonotonicInstant,
327) -> input_device::InputEvent {
328    input_device::InputEvent {
329        device_event: input_device::InputDeviceEvent::Keyboard(keyboard_event),
330        device_descriptor: empty_keyboard_device_descriptor(),
331        event_time,
332        handled: input_device::Handled::No,
333        trace_id: None,
334    }
335}
336
337#[cfg(test)]
338mod tests {
339    use super::*;
340    use crate::testing_utilities::{create_fake_input_event, create_input_event};
341    use fidl_fuchsia_input::Key;
342    use fuchsia_async as fasync;
343    use pretty_assertions::assert_eq;
344    use std::convert::TryFrom as _;
345    use zx::{EventPair, Peered};
346
347    // Manages losing and regaining display, since manual management is error-prone:
348    // if signal_peer does not change the signal state, the waiting process will block
349    // forever, which makes tests run longer than needed.
350    struct DisplayWrangler {
351        event: EventPair,
352        last: Signals,
353    }
354
355    impl DisplayWrangler {
356        fn new(event: EventPair) -> Self {
357            let mut instance = DisplayWrangler { event, last: *DISPLAY_OWNED };
358            // Signal needs to be initialized before the handlers attempts to read it.
359            // This is normally always the case in production.
360            // Else, the `new_for_test` below will panic with a TIMEOUT error.
361            instance.set_unowned();
362            instance
363        }
364
365        fn set_unowned(&mut self) {
366            assert!(self.last != *DISPLAY_UNOWNED, "display is already unowned");
367            self.event.signal_peer(*DISPLAY_OWNED, *DISPLAY_UNOWNED).unwrap();
368            self.last = *DISPLAY_UNOWNED;
369        }
370
371        fn set_owned(&mut self) {
372            assert!(self.last != *DISPLAY_OWNED, "display is already owned");
373            self.event.signal_peer(*DISPLAY_UNOWNED, *DISPLAY_OWNED).unwrap();
374            self.last = *DISPLAY_OWNED;
375        }
376    }
377
378    #[fuchsia::test]
379    async fn display_ownership_change() {
380        // handler_event is the event that the unit under test will examine for
381        // display ownership changes.  test_event is used to set the appropriate
382        // signals.
383        let (test_event, handler_event) = EventPair::create();
384
385        // test_sender is used to pipe input events into the handler.
386        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
387
388        // test_receiver is used to pipe input events out of the handler.
389        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
390
391        // The unit under test adds a () each time it completes one pass through
392        // its event loop.  Use to ensure synchronization.
393        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
394
395        // We use a wrapper to signal test_event correctly, since doing it wrong
396        // by hand causes tests to hang, which isn't the best dev experience.
397        let mut wrangler = DisplayWrangler::new(test_event);
398        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
399
400        let handler_clone = handler.clone();
401        let handler_sender_clone = handler_sender.clone();
402        let _task = fasync::Task::local(async move {
403            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
404        });
405
406        let handler_clone_2 = handler.clone();
407        let _input_task = fasync::Task::local(async move {
408            let mut receiver = handler_receiver;
409            while let Some(event) = receiver.next().await {
410                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
411                let out_events =
412                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
413                for out_event in out_events {
414                    handler_sender.unbounded_send(out_event).unwrap();
415                }
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> =
448            test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
449
450        assert_eq!(
451            actual,
452            vec![
453                // Event received while we owned the display.
454                create_fake_input_event(fake_time),
455                // Event received when we lost the display.
456                create_fake_input_event(fake_time).into_handled(),
457                // Display ownership regained.
458                create_fake_input_event(fake_time),
459                // Display ownership lost.
460                create_fake_input_event(fake_time).into_handled(),
461            ]
462        );
463    }
464
465    fn new_keyboard_input_event(key: Key, event_type: KeyEventType) -> InputEvent {
466        let fake_time = MonotonicInstant::from_nanos(42);
467        create_input_event(
468            KeyboardEvent::new(key, event_type),
469            &input_device::InputDeviceDescriptor::Fake,
470            fake_time,
471            input_device::Handled::No,
472        )
473    }
474
475    #[fuchsia::test]
476    async fn basic_key_state_handling() {
477        let (test_event, handler_event) = EventPair::create();
478        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
479        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
480        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
481        let mut wrangler = DisplayWrangler::new(test_event);
482        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
483
484        let handler_clone = handler.clone();
485        let handler_sender_clone = handler_sender.clone();
486        let _task = fasync::Task::local(async move {
487            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
488        });
489
490        let handler_clone_2 = handler.clone();
491        let _input_task = fasync::Task::local(async move {
492            let mut receiver = handler_receiver;
493            while let Some(event) = receiver.next().await {
494                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
495                let out_events =
496                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
497                for out_event in out_events {
498                    handler_sender.unbounded_send(out_event).unwrap();
499                }
500            }
501        });
502
503        let fake_time = MonotonicInstant::from_nanos(42);
504
505        // Gain the display, and press a key.
506        wrangler.set_owned();
507        loop_done.next().await;
508        test_sender
509            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
510            .unwrap();
511        loop_done.next().await;
512
513        // Lose display.
514        wrangler.set_unowned();
515        loop_done.next().await;
516
517        // Regain display
518        wrangler.set_owned();
519        loop_done.next().await;
520
521        // Key event after regaining.
522        test_sender
523            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
524            .unwrap();
525        loop_done.next().await;
526
527        let actual: Vec<InputEvent> =
528            test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
529
530        assert_eq!(
531            actual,
532            vec![
533                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
534                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
535                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
536                new_keyboard_input_event(Key::A, KeyEventType::Sync)
537                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
538                new_keyboard_input_event(Key::A, KeyEventType::Released),
539            ]
540        );
541    }
542
543    #[fuchsia::test]
544    async fn more_key_state_handling() {
545        let (test_event, handler_event) = EventPair::create();
546        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
547        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
548        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
549        let mut wrangler = DisplayWrangler::new(test_event);
550        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
551
552        let handler_clone = handler.clone();
553        let handler_sender_clone = handler_sender.clone();
554        let _task = fasync::Task::local(async move {
555            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
556        });
557
558        let handler_clone_2 = handler.clone();
559        let _input_task = fasync::Task::local(async move {
560            let mut receiver = handler_receiver;
561            while let Some(event) = receiver.next().await {
562                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
563                let out_events =
564                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
565                for out_event in out_events {
566                    handler_sender.unbounded_send(out_event).unwrap();
567                }
568            }
569        });
570
571        let fake_time = MonotonicInstant::from_nanos(42);
572
573        wrangler.set_owned();
574        loop_done.next().await;
575        test_sender
576            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
577            .unwrap();
578        loop_done.next().await;
579        test_sender
580            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
581            .unwrap();
582        loop_done.next().await;
583
584        // Lose display, release a key, press a key.
585        wrangler.set_unowned();
586        loop_done.next().await;
587        test_sender
588            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Released))
589            .unwrap();
590        loop_done.next().await;
591        test_sender
592            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Pressed))
593            .unwrap();
594        loop_done.next().await;
595
596        // Regain display
597        wrangler.set_owned();
598        loop_done.next().await;
599
600        // Key event after regaining.
601        test_sender
602            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
603            .unwrap();
604        loop_done.next().await;
605        test_sender
606            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Released))
607            .unwrap();
608        loop_done.next().await;
609
610        let actual: Vec<InputEvent> =
611            test_receiver.take(10).map(|e| e.into_with_event_time(fake_time)).collect().await;
612
613        assert_eq!(
614            actual,
615            vec![
616                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
617                new_keyboard_input_event(Key::B, KeyEventType::Pressed),
618                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
619                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
620                new_keyboard_input_event(Key::B, KeyEventType::Cancel)
621                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
622                new_keyboard_input_event(Key::B, KeyEventType::Released).into_handled(),
623                new_keyboard_input_event(Key::C, KeyEventType::Pressed).into_handled(),
624                // The CANCEL and SYNC events are emitted in the sort ordering of the
625                // `Key` enum values. Perhaps they should be emitted instead in the order
626                // they have been received for SYNC, and in reverse order for CANCEL.
627                new_keyboard_input_event(Key::A, KeyEventType::Sync)
628                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
629                new_keyboard_input_event(Key::C, KeyEventType::Sync)
630                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
631                new_keyboard_input_event(Key::A, KeyEventType::Released),
632                new_keyboard_input_event(Key::C, KeyEventType::Released),
633            ]
634        );
635    }
636
637    #[fuchsia::test]
638    async fn display_ownership_initialized_with_inspect_node() {
639        let (test_event, handler_event) = EventPair::create();
640        let (loop_done_sender, _) = mpsc::unbounded::<()>();
641        let inspector = fuchsia_inspect::Inspector::default();
642        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
643        // Signal needs to be initialized first so DisplayOwnership::new doesn't panic with a TIMEOUT error
644        let _ = DisplayWrangler::new(test_event);
645        let _handler = DisplayOwnership::new_internal(
646            handler_event,
647            Some(loop_done_sender),
648            &fake_handlers_node,
649        );
650        diagnostics_assertions::assert_data_tree!(inspector, root: {
651            input_handlers_node: {
652                display_ownership: {
653                    events_received_count: 0u64,
654                    events_handled_count: 0u64,
655                    last_received_timestamp_ns: 0u64,
656                    "fuchsia.inspect.Health": {
657                        status: "STARTING_UP",
658                        // Timestamp value is unpredictable and not relevant in this context,
659                        // so we only assert that the property is present.
660                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
661                    },
662                }
663            }
664        });
665    }
666
667    #[fuchsia::test]
668    async fn display_ownership_inspect_counts_events() {
669        let (test_event, handler_event) = EventPair::create();
670        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
671        let (handler_sender, _test_receiver) = mpsc::unbounded::<InputEvent>();
672        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
673        let mut wrangler = DisplayWrangler::new(test_event);
674        let inspector = fuchsia_inspect::Inspector::default();
675        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
676        let handler = DisplayOwnership::new_internal(
677            handler_event,
678            Some(loop_done_sender),
679            &fake_handlers_node,
680        );
681        let handler_clone = handler.clone();
682        let handler_sender_clone = handler_sender.clone();
683        let _task = fasync::Task::local(async move {
684            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
685        });
686
687        let handler_clone_2 = handler.clone();
688        let _input_task = fasync::Task::local(async move {
689            let mut receiver = handler_receiver;
690            while let Some(event) = receiver.next().await {
691                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
692                let out_events =
693                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
694                for out_event in out_events {
695                    handler_sender.unbounded_send(out_event).unwrap();
696                }
697            }
698        });
699
700        // Gain the display, and press a key.
701        wrangler.set_owned();
702        loop_done.next().await;
703        test_sender
704            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
705            .unwrap();
706        loop_done.next().await;
707
708        // Lose display
709        // Input event is marked `Handled` if received after display ownership is lost
710        wrangler.set_unowned();
711        loop_done.next().await;
712        test_sender
713            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
714            .unwrap();
715        loop_done.next().await;
716
717        // Regain display
718        wrangler.set_owned();
719        loop_done.next().await;
720
721        // Key event after regaining.
722        test_sender
723            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
724            .unwrap();
725        loop_done.next().await;
726
727        diagnostics_assertions::assert_data_tree!(inspector, root: {
728            input_handlers_node: {
729                display_ownership: {
730                    events_received_count: 3u64,
731                    events_handled_count: 1u64,
732                    last_received_timestamp_ns: 42u64,
733                    "fuchsia.inspect.Health": {
734                        status: "STARTING_UP",
735                        // Timestamp value is unpredictable and not relevant in this context,
736                        // so we only assert that the property is present.
737                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
738                    },
739                }
740            }
741        });
742    }
743}