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<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
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::<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                for out_event in out_events {
416                    handler_sender.unbounded_send(out_event).unwrap();
417                }
418            }
419        });
420
421        let fake_time = MonotonicInstant::from_nanos(42);
422
423        // Go two full circles of signaling.
424
425        // 1
426        wrangler.set_owned();
427        loop_done.next().await;
428        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
429        loop_done.next().await;
430
431        // 2
432        wrangler.set_unowned();
433        loop_done.next().await;
434        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
435        loop_done.next().await;
436
437        // 3
438        wrangler.set_owned();
439        loop_done.next().await;
440        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
441        loop_done.next().await;
442
443        // 4
444        wrangler.set_unowned();
445        loop_done.next().await;
446        test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
447        loop_done.next().await;
448
449        let actual: Vec<InputEvent> =
450            test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
451
452        assert_eq!(
453            actual,
454            vec![
455                // Event received while we owned the display.
456                create_fake_input_event(fake_time),
457                // Event received when we lost the display.
458                create_fake_input_event(fake_time).into_handled(),
459                // Display ownership regained.
460                create_fake_input_event(fake_time),
461                // Display ownership lost.
462                create_fake_input_event(fake_time).into_handled(),
463            ]
464        );
465    }
466
467    fn new_keyboard_input_event(key: Key, event_type: KeyEventType) -> InputEvent {
468        let fake_time = MonotonicInstant::from_nanos(42);
469        create_input_event(
470            KeyboardEvent::new(key, event_type),
471            &input_device::InputDeviceDescriptor::Fake,
472            fake_time,
473            input_device::Handled::No,
474        )
475    }
476
477    #[fuchsia::test]
478    async fn basic_key_state_handling() {
479        let (test_event, handler_event) = EventPair::create();
480        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
481        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
482        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
483        let mut wrangler = DisplayWrangler::new(test_event);
484        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
485
486        let handler_clone = handler.clone();
487        let handler_sender_clone = handler_sender.clone();
488        let _task = fasync::Task::local(async move {
489            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
490        });
491
492        let handler_clone_2 = handler.clone();
493        let _input_task = fasync::Task::local(async move {
494            let mut receiver = handler_receiver;
495            while let Some(event) = receiver.next().await {
496                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
497                let out_events =
498                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
499                for out_event in out_events {
500                    handler_sender.unbounded_send(out_event).unwrap();
501                }
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> =
530            test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
531
532        assert_eq!(
533            actual,
534            vec![
535                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
536                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
537                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
538                new_keyboard_input_event(Key::A, KeyEventType::Sync)
539                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
540                new_keyboard_input_event(Key::A, KeyEventType::Released),
541            ]
542        );
543    }
544
545    #[fuchsia::test]
546    async fn more_key_state_handling() {
547        let (test_event, handler_event) = EventPair::create();
548        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
549        let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
550        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
551        let mut wrangler = DisplayWrangler::new(test_event);
552        let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
553
554        let handler_clone = handler.clone();
555        let handler_sender_clone = handler_sender.clone();
556        let _task = fasync::Task::local(async move {
557            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
558        });
559
560        let handler_clone_2 = handler.clone();
561        let _input_task = fasync::Task::local(async move {
562            let mut receiver = handler_receiver;
563            while let Some(event) = receiver.next().await {
564                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
565                let out_events =
566                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
567                for out_event in out_events {
568                    handler_sender.unbounded_send(out_event).unwrap();
569                }
570            }
571        });
572
573        let fake_time = MonotonicInstant::from_nanos(42);
574
575        wrangler.set_owned();
576        loop_done.next().await;
577        test_sender
578            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
579            .unwrap();
580        loop_done.next().await;
581        test_sender
582            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
583            .unwrap();
584        loop_done.next().await;
585
586        // Lose display, release a key, press a key.
587        wrangler.set_unowned();
588        loop_done.next().await;
589        test_sender
590            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Released))
591            .unwrap();
592        loop_done.next().await;
593        test_sender
594            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Pressed))
595            .unwrap();
596        loop_done.next().await;
597
598        // Regain display
599        wrangler.set_owned();
600        loop_done.next().await;
601
602        // Key event after regaining.
603        test_sender
604            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
605            .unwrap();
606        loop_done.next().await;
607        test_sender
608            .unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Released))
609            .unwrap();
610        loop_done.next().await;
611
612        let actual: Vec<InputEvent> =
613            test_receiver.take(10).map(|e| e.into_with_event_time(fake_time)).collect().await;
614
615        assert_eq!(
616            actual,
617            vec![
618                new_keyboard_input_event(Key::A, KeyEventType::Pressed),
619                new_keyboard_input_event(Key::B, KeyEventType::Pressed),
620                new_keyboard_input_event(Key::A, KeyEventType::Cancel)
621                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
622                new_keyboard_input_event(Key::B, KeyEventType::Cancel)
623                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
624                new_keyboard_input_event(Key::B, KeyEventType::Released).into_handled(),
625                new_keyboard_input_event(Key::C, KeyEventType::Pressed).into_handled(),
626                // The CANCEL and SYNC events are emitted in the sort ordering of the
627                // `Key` enum values. Perhaps they should be emitted instead in the order
628                // they have been received for SYNC, and in reverse order for CANCEL.
629                new_keyboard_input_event(Key::A, KeyEventType::Sync)
630                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
631                new_keyboard_input_event(Key::C, KeyEventType::Sync)
632                    .into_with_device_descriptor(empty_keyboard_device_descriptor()),
633                new_keyboard_input_event(Key::A, KeyEventType::Released),
634                new_keyboard_input_event(Key::C, KeyEventType::Released),
635            ]
636        );
637    }
638
639    #[fuchsia::test]
640    async fn display_ownership_initialized_with_inspect_node() {
641        let (test_event, handler_event) = EventPair::create();
642        let (loop_done_sender, _) = mpsc::unbounded::<()>();
643        let inspector = fuchsia_inspect::Inspector::default();
644        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
645        // Signal needs to be initialized first so DisplayOwnership::new doesn't panic with a TIMEOUT error
646        let _ = DisplayWrangler::new(test_event);
647        let _handler = DisplayOwnership::new_internal(
648            handler_event,
649            Some(loop_done_sender),
650            &fake_handlers_node,
651        );
652        diagnostics_assertions::assert_data_tree!(inspector, root: {
653            input_handlers_node: {
654                display_ownership: {
655                    events_received_count: 0u64,
656                    events_handled_count: 0u64,
657                    last_received_timestamp_ns: 0u64,
658                    "fuchsia.inspect.Health": {
659                        status: "STARTING_UP",
660                        // Timestamp value is unpredictable and not relevant in this context,
661                        // so we only assert that the property is present.
662                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
663                    },
664                }
665            }
666        });
667    }
668
669    #[fuchsia::test]
670    async fn display_ownership_inspect_counts_events() {
671        let (test_event, handler_event) = EventPair::create();
672        let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
673        let (handler_sender, _test_receiver) = mpsc::unbounded::<InputEvent>();
674        let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
675        let mut wrangler = DisplayWrangler::new(test_event);
676        let inspector = fuchsia_inspect::Inspector::default();
677        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
678        let handler = DisplayOwnership::new_internal(
679            handler_event,
680            Some(loop_done_sender),
681            &fake_handlers_node,
682        );
683        let handler_clone = handler.clone();
684        let handler_sender_clone = handler_sender.clone();
685        let _task = fasync::Task::local(async move {
686            handler_clone.handle_ownership_change(handler_sender_clone).await.unwrap();
687        });
688
689        let handler_clone_2 = handler.clone();
690        let _input_task = fasync::Task::local(async move {
691            let mut receiver = handler_receiver;
692            while let Some(event) = receiver.next().await {
693                let unhandled_event = UnhandledInputEvent::try_from(event).unwrap();
694                let out_events =
695                    handler_clone_2.clone().handle_unhandled_input_event(unhandled_event).await;
696                for out_event in out_events {
697                    handler_sender.unbounded_send(out_event).unwrap();
698                }
699            }
700        });
701
702        // Gain the display, and press a key.
703        wrangler.set_owned();
704        loop_done.next().await;
705        test_sender
706            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
707            .unwrap();
708        loop_done.next().await;
709
710        // Lose display
711        // Input event is marked `Handled` if received after display ownership is lost
712        wrangler.set_unowned();
713        loop_done.next().await;
714        test_sender
715            .unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
716            .unwrap();
717        loop_done.next().await;
718
719        // Regain display
720        wrangler.set_owned();
721        loop_done.next().await;
722
723        // Key event after regaining.
724        test_sender
725            .unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
726            .unwrap();
727        loop_done.next().await;
728
729        diagnostics_assertions::assert_data_tree!(inspector, root: {
730            input_handlers_node: {
731                display_ownership: {
732                    events_received_count: 3u64,
733                    events_handled_count: 1u64,
734                    last_received_timestamp_ns: 42u64,
735                    "fuchsia.inspect.Health": {
736                        status: "STARTING_UP",
737                        // Timestamp value is unpredictable and not relevant in this context,
738                        // so we only assert that the property is present.
739                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
740                    },
741                }
742            }
743        });
744    }
745}