Skip to main content

input_pipeline/
media_buttons_handler.rs

1// Copyright 2021 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::input_handler::{Handler, InputHandlerStatus, UnhandledInputHandler};
6use crate::{consumer_controls_binding, input_device, metrics};
7use async_trait::async_trait;
8use fidl::HandleBased;
9use fidl::endpoints::Proxy;
10use fuchsia_inspect::health::Reporter;
11use futures::StreamExt;
12use futures::channel::mpsc;
13use metrics_registry::*;
14use std::cell::RefCell;
15use std::collections::HashMap;
16use std::rc::Rc;
17use zx::AsHandleRef;
18use {
19    fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
20    fidl_fuchsia_ui_policy as fidl_ui_policy, fuchsia_async as fasync,
21};
22
23/// A [`MediaButtonsHandler`] tracks MediaButtonListeners and sends media button events to them.
24pub struct MediaButtonsHandler {
25    /// The mutable fields of this handler.
26    inner: RefCell<MediaButtonsHandlerInner>,
27
28    /// The inventory of this handler's Inspect status.
29    pub inspect_status: InputHandlerStatus,
30
31    metrics_logger: metrics::MetricsLogger,
32}
33
34#[derive(Debug)]
35struct MediaButtonsHandlerInner {
36    /// The media button listeners, key referenced by proxy channel's raw handle.
37    pub listeners: HashMap<u32, fidl_ui_policy::MediaButtonsListenerProxy>,
38
39    /// The last MediaButtonsEvent sent to all listeners.
40    /// This is used to send new listeners the state of the media buttons.
41    pub last_event: Option<fidl_ui_input::MediaButtonsEvent>,
42
43    pub send_event_task_tracker: LocalTaskTracker,
44}
45
46impl Handler for MediaButtonsHandler {
47    fn set_handler_healthy(self: std::rc::Rc<Self>) {
48        self.inspect_status.health_node.borrow_mut().set_ok();
49    }
50
51    fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
52        self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
53    }
54
55    fn get_name(&self) -> &'static str {
56        "MediaButtonsHandler"
57    }
58
59    fn interest(&self) -> Vec<input_device::InputEventType> {
60        vec![input_device::InputEventType::ConsumerControls]
61    }
62}
63
64#[async_trait(?Send)]
65impl UnhandledInputHandler for MediaButtonsHandler {
66    async fn handle_unhandled_input_event(
67        self: Rc<Self>,
68        mut unhandled_input_event: input_device::UnhandledInputEvent,
69    ) -> Vec<input_device::InputEvent> {
70        fuchsia_trace::duration!("input", "media_buttons_handler");
71        match unhandled_input_event {
72            input_device::UnhandledInputEvent {
73                device_event:
74                    input_device::InputDeviceEvent::ConsumerControls(ref mut consumer_controls_event),
75                device_descriptor:
76                    input_device::InputDeviceDescriptor::ConsumerControls(ref device_descriptor),
77                event_time,
78                trace_id,
79            } => {
80                fuchsia_trace::duration!("input", "media_buttons_handler[processing]");
81                if let Some(trace_id) = trace_id {
82                    fuchsia_trace::flow_step!("input", "event_in_input_pipeline", trace_id.into());
83                }
84
85                self.inspect_status.count_received_event(&event_time);
86                let mut media_buttons_event = Self::create_media_buttons_event(
87                    consumer_controls_event,
88                    device_descriptor.device_id,
89                );
90
91                // Send the event if the media buttons are supported.
92                self.send_event_to_listeners(&media_buttons_event).await;
93
94                // Store the sent event without any wake leases.
95                std::mem::drop(media_buttons_event.wake_lease.take());
96                self.inner.borrow_mut().last_event = Some(media_buttons_event);
97
98                // Consume the input event.
99                self.inspect_status.count_handled_event();
100                vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
101            }
102            _ => {
103                self.metrics_logger.log_error(
104                    InputPipelineErrorMetricDimensionEvent::HandlerReceivedUninterestedEvent,
105                    std::format!(
106                        "uninterested input event: {:?}",
107                        unhandled_input_event.get_event_type()
108                    ),
109                );
110                vec![input_device::InputEvent::from(unhandled_input_event)]
111            }
112        }
113    }
114}
115
116impl MediaButtonsHandler {
117    /// Creates a new [`MediaButtonsHandler`] that sends media button events to listeners.
118    pub fn new(
119        input_handlers_node: &fuchsia_inspect::Node,
120        metrics_logger: metrics::MetricsLogger,
121    ) -> Rc<Self> {
122        let inspect_status =
123            InputHandlerStatus::new(input_handlers_node, "media_buttons_handler", false);
124        Self::new_internal(inspect_status, metrics_logger)
125    }
126
127    fn clone_event(event: &fidl_ui_input::MediaButtonsEvent) -> fidl_ui_input::MediaButtonsEvent {
128        fidl_ui_input::MediaButtonsEvent {
129            volume: event.volume,
130            mic_mute: event.mic_mute,
131            pause: event.pause,
132            camera_disable: event.camera_disable,
133            power: event.power,
134            function: event.function,
135            device_id: event.device_id,
136            wake_lease: event.wake_lease.as_ref().map(|lease| {
137                lease
138                    .duplicate_handle(zx::Rights::SAME_RIGHTS)
139                    .expect("failed to duplicate event pair")
140            }),
141            ..Default::default()
142        }
143    }
144
145    fn new_internal(
146        inspect_status: InputHandlerStatus,
147        metrics_logger: metrics::MetricsLogger,
148    ) -> Rc<Self> {
149        let media_buttons_handler = Self {
150            inner: RefCell::new(MediaButtonsHandlerInner {
151                listeners: HashMap::new(),
152                last_event: None,
153                send_event_task_tracker: LocalTaskTracker::new(),
154            }),
155            inspect_status,
156            metrics_logger,
157        };
158        Rc::new(media_buttons_handler)
159    }
160
161    /// Creates a fidl_ui_input::MediaButtonsEvent from a media_buttons::MediaButtonEvent.
162    ///
163    /// # Parameters
164    /// -  `event`: The MediaButtonEvent to create a MediaButtonsEvent from.
165    fn create_media_buttons_event(
166        event: &mut consumer_controls_binding::ConsumerControlsEvent,
167        device_id: u32,
168    ) -> fidl_ui_input::MediaButtonsEvent {
169        let mut new_event = fidl_ui_input::MediaButtonsEvent {
170            volume: Some(0),
171            mic_mute: Some(false),
172            pause: Some(false),
173            camera_disable: Some(false),
174            power: Some(false),
175            function: Some(false),
176            device_id: Some(device_id),
177            wake_lease: event.wake_lease.take(),
178            ..Default::default()
179        };
180        for button in &event.pressed_buttons {
181            match button {
182                fidl_input_report::ConsumerControlButton::VolumeUp => {
183                    new_event.volume = Some(new_event.volume.unwrap().saturating_add(1));
184                }
185                fidl_input_report::ConsumerControlButton::VolumeDown => {
186                    new_event.volume = Some(new_event.volume.unwrap().saturating_sub(1));
187                }
188                fidl_input_report::ConsumerControlButton::MicMute => {
189                    new_event.mic_mute = Some(true);
190                }
191                fidl_input_report::ConsumerControlButton::Pause => {
192                    new_event.pause = Some(true);
193                }
194                fidl_input_report::ConsumerControlButton::CameraDisable => {
195                    new_event.camera_disable = Some(true);
196                }
197                fidl_input_report::ConsumerControlButton::Function => {
198                    new_event.function = Some(true);
199                }
200                fidl_input_report::ConsumerControlButton::Power => {
201                    new_event.power = Some(true);
202                }
203                _ => {}
204            }
205        }
206
207        new_event
208    }
209
210    /// Sends media button events to media button listeners.
211    ///
212    /// # Parameters
213    /// - `event`: The event to send to the listeners.
214    async fn send_event_to_listeners(self: &Rc<Self>, event: &fidl_ui_input::MediaButtonsEvent) {
215        let tracker = &self.inner.borrow().send_event_task_tracker;
216
217        for (handle, listener) in &self.inner.borrow().listeners {
218            let weak_handler = Rc::downgrade(&self);
219            let listener_clone = listener.clone();
220            let handle_clone = handle.clone();
221            let event_to_send = Self::clone_event(event);
222            let fut = async move {
223                match listener_clone.on_event(event_to_send).await {
224                    Ok(_) => {}
225                    Err(e) => {
226                        if let Some(handler) = weak_handler.upgrade() {
227                            handler.inner.borrow_mut().listeners.remove(&handle_clone);
228                            log::info!(
229                                "Unregistering listener; unable to send MediaButtonsEvent: {:?}",
230                                e
231                            )
232                        }
233                    }
234                }
235            };
236
237            let metrics_logger_clone = self.metrics_logger.clone();
238            tracker.track(metrics_logger_clone, fasync::Task::local(fut));
239        }
240    }
241
242    // Add the listener to the registry.
243    ///
244    /// # Parameters
245    /// - `proxy`: A new listener proxy to send events to.
246    pub async fn register_listener_proxy(
247        self: &Rc<Self>,
248        proxy: fidl_ui_policy::MediaButtonsListenerProxy,
249    ) {
250        self.inner
251            .borrow_mut()
252            .listeners
253            .insert(proxy.as_channel().as_handle_ref().as_handle_ref().raw_handle(), proxy.clone());
254
255        // Send the listener the last media button event.
256        if let Some(event) = &self.inner.borrow().last_event {
257            let event_to_send = Self::clone_event(event);
258            let fut = async move {
259                match proxy.on_event(event_to_send).await {
260                    Ok(_) => {}
261                    Err(e) => {
262                        log::info!("Failed to send media buttons event to listener {:?}", e)
263                    }
264                }
265            };
266            let metrics_logger_clone = self.metrics_logger.clone();
267            self.inner
268                .borrow()
269                .send_event_task_tracker
270                .track(metrics_logger_clone, fasync::Task::local(fut));
271        }
272    }
273}
274
275/// Maintains a collection of pending local [`Task`]s, allowing them to be dropped (and cancelled)
276/// en masse.
277#[derive(Debug)]
278pub struct LocalTaskTracker {
279    sender: mpsc::UnboundedSender<fasync::Task<()>>,
280    _receiver_task: fasync::Task<()>,
281}
282
283impl LocalTaskTracker {
284    pub fn new() -> Self {
285        let (sender, receiver) = mpsc::unbounded();
286        let receiver_task = fasync::Task::local(async move {
287            // Drop the tasks as they are completed.
288            receiver.for_each_concurrent(None, |task: fasync::Task<()>| task).await
289        });
290
291        Self { sender, _receiver_task: receiver_task }
292    }
293
294    /// Submits a new task to track.
295    pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: fasync::Task<()>) {
296        match self.sender.unbounded_send(task) {
297            Ok(_) => {}
298            // `Full` should never happen because this is unbounded.
299            // `Disconnected` might happen if the `Service` was dropped. However, it's not clear how
300            // to create such a race condition.
301            Err(e) => {
302                metrics_logger.log_error(
303                    InputPipelineErrorMetricDimensionEvent::MediaButtonErrorWhilePushingTask,
304                    std::format!("Unexpected {e:?} while pushing task"),
305                );
306            }
307        };
308    }
309}
310
311#[cfg(test)]
312mod tests {
313    use super::*;
314    use crate::input_handler::InputHandler;
315    use crate::testing_utilities;
316    use anyhow::Error;
317    use assert_matches::assert_matches;
318    use fidl::endpoints::create_proxy_and_stream;
319    use futures::TryStreamExt;
320    use futures::channel::oneshot;
321    use pretty_assertions::assert_eq;
322    use std::task::Poll;
323    use {fidl_fuchsia_input_report as fidl_input_report, fuchsia_async as fasync};
324
325    fn spawn_device_listener_registry_server(
326        handler: Rc<MediaButtonsHandler>,
327    ) -> fidl_ui_policy::DeviceListenerRegistryProxy {
328        let (device_listener_proxy, mut device_listener_stream) =
329            create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>();
330
331        fasync::Task::local(async move {
332            loop {
333                match device_listener_stream.try_next().await {
334                    Ok(Some(fidl_ui_policy::DeviceListenerRegistryRequest::RegisterListener {
335                        listener,
336                        responder,
337                    })) => {
338                        handler.register_listener_proxy(listener.into_proxy()).await;
339                        let _ = responder.send();
340                    }
341                    Ok(Some(_)) => {
342                        panic!("Unexpected registration");
343                    }
344                    Ok(None) => {
345                        break;
346                    }
347                    Err(e) => {
348                        panic!("Error handling device listener registry request stream: {}", e);
349                    }
350                }
351            }
352        })
353        .detach();
354
355        device_listener_proxy
356    }
357
358    fn create_ui_input_media_buttons_event(
359        volume: Option<i8>,
360        mic_mute: Option<bool>,
361        pause: Option<bool>,
362        camera_disable: Option<bool>,
363        power: Option<bool>,
364        function: Option<bool>,
365    ) -> fidl_ui_input::MediaButtonsEvent {
366        fidl_ui_input::MediaButtonsEvent {
367            volume,
368            mic_mute,
369            pause,
370            camera_disable,
371            power,
372            function,
373            device_id: Some(0),
374            ..Default::default()
375        }
376    }
377
378    /// Makes a `Task` that waits for a `oneshot`'s value to be set, and then forwards that value to
379    /// a reference-counted container that can be observed outside the task.
380    fn make_signalable_task<T: Default + 'static>()
381    -> (oneshot::Sender<T>, fasync::Task<()>, Rc<RefCell<T>>) {
382        let (sender, receiver) = oneshot::channel();
383        let task_completed = Rc::new(RefCell::new(<T as Default>::default()));
384        let task_completed_ = task_completed.clone();
385        let task = fasync::Task::local(async move {
386            if let Ok(value) = receiver.await {
387                *task_completed_.borrow_mut() = value;
388            }
389        });
390        (sender, task, task_completed)
391    }
392
393    /// Tests that a media button listener can be registered and is sent the latest event upon
394    /// registration.
395    #[fasync::run_singlethreaded(test)]
396    async fn register_media_buttons_listener() {
397        let inspector = fuchsia_inspect::Inspector::default();
398        let test_node = inspector.root().create_child("test_node");
399        let inspect_status = InputHandlerStatus::new(
400            &test_node,
401            "media_buttons_handler",
402            /* generates_events */ false,
403        );
404
405        let media_buttons_handler = Rc::new(MediaButtonsHandler {
406            inner: RefCell::new(MediaButtonsHandlerInner {
407                listeners: HashMap::new(),
408                last_event: Some(create_ui_input_media_buttons_event(
409                    Some(1),
410                    None,
411                    None,
412                    None,
413                    None,
414                    None,
415                )),
416                send_event_task_tracker: LocalTaskTracker::new(),
417            }),
418            inspect_status,
419            metrics_logger: metrics::MetricsLogger::default(),
420        });
421        let device_listener_proxy =
422            spawn_device_listener_registry_server(media_buttons_handler.clone());
423
424        // Register a listener.
425        let (listener, mut listener_stream) =
426            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
427        let register_listener_fut = async {
428            let res = device_listener_proxy.register_listener(listener).await;
429            assert!(res.is_ok());
430        };
431
432        // Assert listener was registered and received last event.
433        let expected_event =
434            create_ui_input_media_buttons_event(Some(1), None, None, None, None, None);
435        let assert_fut = async {
436            match listener_stream.next().await {
437                Some(Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
438                    event,
439                    responder,
440                })) => {
441                    assert_eq!(event, expected_event);
442                    responder.send().expect("responder failed.");
443                }
444                _ => assert!(false),
445            }
446        };
447        futures::join!(register_listener_fut, assert_fut);
448        assert_eq!(media_buttons_handler.inner.borrow().listeners.len(), 1);
449    }
450
451    /// Tests that all supported buttons are sent.
452    #[fasync::run_singlethreaded(test)]
453    async fn listener_receives_all_buttons() {
454        let event_time = zx::MonotonicInstant::get();
455        let inspector = fuchsia_inspect::Inspector::default();
456        let test_node = inspector.root().create_child("test_node");
457        let inspect_status = InputHandlerStatus::new(
458            &test_node,
459            "media_buttons_handler",
460            /* generates_events */ false,
461        );
462        let media_buttons_handler =
463            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
464        let device_listener_proxy =
465            spawn_device_listener_registry_server(media_buttons_handler.clone());
466
467        // Register a listener.
468        let (listener, listener_stream) =
469            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
470        let _ = device_listener_proxy.register_listener(listener).await;
471
472        // Setup events and expectations.
473        let descriptor = testing_utilities::consumer_controls_device_descriptor();
474        let input_events = vec![testing_utilities::create_consumer_controls_event(
475            vec![
476                fidl_input_report::ConsumerControlButton::VolumeUp,
477                fidl_input_report::ConsumerControlButton::VolumeDown,
478                fidl_input_report::ConsumerControlButton::Pause,
479                fidl_input_report::ConsumerControlButton::MicMute,
480                fidl_input_report::ConsumerControlButton::CameraDisable,
481                fidl_input_report::ConsumerControlButton::Function,
482                fidl_input_report::ConsumerControlButton::Power,
483            ],
484            event_time,
485            &descriptor,
486        )];
487        let expected_events = vec![create_ui_input_media_buttons_event(
488            Some(0),
489            Some(true),
490            Some(true),
491            Some(true),
492            Some(true),
493            Some(true),
494        )];
495
496        // Assert registered listener receives event.
497        use crate::input_handler::InputHandler as _; // Adapt UnhandledInputHandler to InputHandler
498        assert_input_event_sequence_generates_media_buttons_events!(
499            input_handler: media_buttons_handler,
500            input_events: input_events,
501            expected_events: expected_events,
502            media_buttons_listener_request_stream: vec![listener_stream],
503        );
504    }
505
506    /// Tests that multiple listeners are supported.
507    #[fasync::run_singlethreaded(test)]
508    async fn multiple_listeners_receive_event() {
509        let event_time = zx::MonotonicInstant::get();
510        let inspector = fuchsia_inspect::Inspector::default();
511        let test_node = inspector.root().create_child("test_node");
512        let inspect_status = InputHandlerStatus::new(
513            &test_node,
514            "media_buttons_handler",
515            /* generates_events */ false,
516        );
517        let media_buttons_handler =
518            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
519        let device_listener_proxy =
520            spawn_device_listener_registry_server(media_buttons_handler.clone());
521
522        // Register two listeners.
523        let (first_listener, first_listener_stream) =
524            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
525        let (second_listener, second_listener_stream) =
526            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
527        let _ = device_listener_proxy.register_listener(first_listener).await;
528        let _ = device_listener_proxy.register_listener(second_listener).await;
529
530        // Setup events and expectations.
531        let descriptor = testing_utilities::consumer_controls_device_descriptor();
532        let input_events = vec![testing_utilities::create_consumer_controls_event(
533            vec![fidl_input_report::ConsumerControlButton::VolumeUp],
534            event_time,
535            &descriptor,
536        )];
537        let expected_events = vec![create_ui_input_media_buttons_event(
538            Some(1),
539            Some(false),
540            Some(false),
541            Some(false),
542            Some(false),
543            Some(false),
544        )];
545
546        // Assert registered listeners receives event.
547        use crate::input_handler::InputHandler as _; // Adapt UnhandledInputHandler to InputHandler
548        assert_input_event_sequence_generates_media_buttons_events!(
549            input_handler: media_buttons_handler,
550            input_events: input_events,
551            expected_events: expected_events,
552            media_buttons_listener_request_stream:
553                vec![first_listener_stream, second_listener_stream],
554        );
555    }
556
557    /// Tests that listener is unregistered if channel is closed and we try to send input event to listener
558    #[fuchsia::test]
559    fn unregister_listener_if_channel_closed() {
560        let mut exec = fasync::TestExecutor::new();
561
562        let event_time = zx::MonotonicInstant::get();
563        let inspector = fuchsia_inspect::Inspector::default();
564        let test_node = inspector.root().create_child("test_node");
565        let inspect_status = InputHandlerStatus::new(
566            &test_node,
567            "media_buttons_handler",
568            /* generates_events */ false,
569        );
570        let media_buttons_handler =
571            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
572        let media_buttons_handler_clone = media_buttons_handler.clone();
573
574        let mut task = fasync::Task::local(async move {
575            let device_listener_proxy =
576                spawn_device_listener_registry_server(media_buttons_handler.clone());
577
578            // Register three listeners.
579            let (first_listener, mut first_listener_stream) =
580                fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>(
581                );
582            let (second_listener, mut second_listener_stream) =
583                fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>(
584                );
585            let (third_listener, third_listener_stream) = fidl::endpoints::create_request_stream::<
586                fidl_ui_policy::MediaButtonsListenerMarker,
587            >();
588            let _ = device_listener_proxy.register_listener(first_listener).await;
589            let _ = device_listener_proxy.register_listener(second_listener).await;
590            let _ = device_listener_proxy.register_listener(third_listener).await;
591            assert_eq!(media_buttons_handler.inner.borrow().listeners.len(), 3);
592
593            // Generate input event to be handled by MediaButtonsHandler.
594            let descriptor = testing_utilities::consumer_controls_device_descriptor();
595            let input_event = testing_utilities::create_consumer_controls_event(
596                vec![fidl_input_report::ConsumerControlButton::VolumeUp],
597                event_time,
598                &descriptor,
599            );
600
601            let expected_media_buttons_event = create_ui_input_media_buttons_event(
602                Some(1),
603                Some(false),
604                Some(false),
605                Some(false),
606                Some(false),
607                Some(false),
608            );
609
610            // Drop third registered listener.
611            std::mem::drop(third_listener_stream);
612
613            let _ = media_buttons_handler.clone().handle_input_event(input_event).await;
614            // First listener stalls, responder doesn't send response - subsequent listeners should still be able receive event.
615            if let Some(request) = first_listener_stream.next().await {
616                match request {
617                    Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
618                        event,
619                        responder: _,
620                    }) => {
621                        pretty_assertions::assert_eq!(event, expected_media_buttons_event);
622
623                        // No need to send response because we want to simulate reader getting stuck.
624                    }
625                    _ => assert!(false),
626                }
627            } else {
628                assert!(false);
629            }
630
631            // Send response from responder on second listener stream
632            if let Some(request) = second_listener_stream.next().await {
633                match request {
634                    Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
635                        event,
636                        responder,
637                    }) => {
638                        pretty_assertions::assert_eq!(event, expected_media_buttons_event);
639                        let _ = responder.send();
640                    }
641                    _ => assert!(false),
642                }
643            } else {
644                assert!(false);
645            }
646        });
647
648        // Must manually run tasks with executor to ensure all tasks in LocalTaskTracker complete/stall before we call final assertion.
649        let _ = exec.run_until_stalled(&mut task);
650
651        // Should only be two listeners still registered in 'inner' after we unregister the listener with closed channel.
652        let _ = exec.run_singlethreaded(async {
653            assert_eq!(media_buttons_handler_clone.inner.borrow().listeners.len(), 2);
654        });
655    }
656
657    /// Tests that handle_input_event returns even if reader gets stuck while sending event to listener
658    #[fasync::run_singlethreaded(test)]
659    async fn stuck_reader_wont_block_input_pipeline() {
660        let event_time = zx::MonotonicInstant::get();
661        let inspector = fuchsia_inspect::Inspector::default();
662        let test_node = inspector.root().create_child("test_node");
663        let inspect_status = InputHandlerStatus::new(
664            &test_node,
665            "media_buttons_handler",
666            /* generates_events */ false,
667        );
668        let media_buttons_handler =
669            MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
670        let device_listener_proxy =
671            spawn_device_listener_registry_server(media_buttons_handler.clone());
672
673        let (first_listener, mut first_listener_stream) =
674            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
675        let (second_listener, mut second_listener_stream) =
676            fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
677        let _ = device_listener_proxy.register_listener(first_listener).await;
678        let _ = device_listener_proxy.register_listener(second_listener).await;
679
680        // Setup events and expectations.
681        let descriptor = testing_utilities::consumer_controls_device_descriptor();
682        let first_unhandled_input_event = input_device::UnhandledInputEvent {
683            device_event: input_device::InputDeviceEvent::ConsumerControls(
684                consumer_controls_binding::ConsumerControlsEvent::new(
685                    vec![fidl_input_report::ConsumerControlButton::VolumeUp],
686                    None,
687                ),
688            ),
689            device_descriptor: descriptor.clone(),
690            event_time,
691            trace_id: None,
692        };
693        let first_expected_media_buttons_event = create_ui_input_media_buttons_event(
694            Some(1),
695            Some(false),
696            Some(false),
697            Some(false),
698            Some(false),
699            Some(false),
700        );
701
702        assert_matches!(
703            media_buttons_handler
704                .clone()
705                .handle_unhandled_input_event(first_unhandled_input_event)
706                .await
707                .as_slice(),
708            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
709        );
710
711        let mut save_responder = None;
712
713        // Ensure handle_input_event attempts to send event to first listener.
714        if let Some(request) = first_listener_stream.next().await {
715            match request {
716                Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
717                    pretty_assertions::assert_eq!(event, first_expected_media_buttons_event);
718
719                    // No need to send response because we want to simulate reader getting stuck.
720
721                    // Save responder to send response later
722                    save_responder = Some(responder);
723                }
724                _ => assert!(false),
725            }
726        } else {
727            assert!(false)
728        }
729
730        // Ensure handle_input_event still sends event to second listener when reader for first listener is stuck.
731        if let Some(request) = second_listener_stream.next().await {
732            match request {
733                Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
734                    pretty_assertions::assert_eq!(event, first_expected_media_buttons_event);
735                    let _ = responder.send();
736                }
737                _ => assert!(false),
738            }
739        } else {
740            assert!(false)
741        }
742
743        // Setup second event to handle
744        let second_unhandled_input_event = input_device::UnhandledInputEvent {
745            device_event: input_device::InputDeviceEvent::ConsumerControls(
746                consumer_controls_binding::ConsumerControlsEvent::new(
747                    vec![fidl_input_report::ConsumerControlButton::MicMute],
748                    None,
749                ),
750            ),
751            device_descriptor: descriptor.clone(),
752            event_time,
753            trace_id: None,
754        };
755        let second_expected_media_buttons_event = create_ui_input_media_buttons_event(
756            Some(0),
757            Some(true),
758            Some(false),
759            Some(false),
760            Some(false),
761            Some(false),
762        );
763
764        // Ensure we can handle a subsequent event if listener stalls on first event.
765        assert_matches!(
766            media_buttons_handler
767                .clone()
768                .handle_unhandled_input_event(second_unhandled_input_event)
769                .await
770                .as_slice(),
771            [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
772        );
773
774        // Ensure events are still sent to listeners if a listener stalls on a previous event.
775        if let Some(request) = second_listener_stream.next().await {
776            match request {
777                Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
778                    pretty_assertions::assert_eq!(event, second_expected_media_buttons_event);
779                    let _ = responder.send();
780                }
781                _ => assert!(false),
782            }
783        } else {
784            assert!(false)
785        }
786
787        match save_responder {
788            Some(save_responder) => {
789                // Simulate delayed response to first listener for first event
790                let _ = save_responder.send();
791                // First listener should now receive second event after delayed response for first event
792                if let Some(request) = first_listener_stream.next().await {
793                    match request {
794                        Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
795                            event,
796                            responder: _,
797                        }) => {
798                            pretty_assertions::assert_eq!(
799                                event,
800                                second_expected_media_buttons_event
801                            );
802
803                            // No need to send response
804                        }
805                        _ => assert!(false),
806                    }
807                } else {
808                    assert!(false)
809                }
810            }
811            None => {
812                assert!(false)
813            }
814        }
815    }
816
817    // Test for LocalTaskTracker
818    #[fuchsia::test]
819    fn local_task_tracker_test() -> Result<(), Error> {
820        let mut exec = fasync::TestExecutor::new();
821
822        let (mut sender_1, task_1, completed_1) = make_signalable_task::<bool>();
823        let (sender_2, task_2, completed_2) = make_signalable_task::<bool>();
824
825        let mut tracker = LocalTaskTracker::new();
826
827        tracker.track(metrics::MetricsLogger::default(), task_1);
828        tracker.track(metrics::MetricsLogger::default(), task_2);
829
830        assert_matches!(exec.run_until_stalled(&mut tracker._receiver_task), Poll::Pending);
831        assert_eq!(Rc::strong_count(&completed_1), 2);
832        assert_eq!(Rc::strong_count(&completed_2), 2);
833        assert!(!sender_1.is_canceled());
834        assert!(!sender_2.is_canceled());
835
836        assert!(sender_2.send(true).is_ok());
837        assert_matches!(exec.run_until_stalled(&mut tracker._receiver_task), Poll::Pending);
838
839        assert_eq!(Rc::strong_count(&completed_1), 2);
840        assert_eq!(Rc::strong_count(&completed_2), 1);
841        assert_eq!(*completed_1.borrow(), false);
842        assert_eq!(*completed_2.borrow(), true);
843        assert!(!sender_1.is_canceled());
844
845        drop(tracker);
846        let mut sender_1_cancellation = sender_1.cancellation();
847        assert_matches!(exec.run_until_stalled(&mut sender_1_cancellation), Poll::Ready(()));
848        assert_eq!(Rc::strong_count(&completed_1), 1);
849        assert!(sender_1.is_canceled());
850
851        Ok(())
852    }
853
854    #[fasync::run_singlethreaded(test)]
855    async fn media_buttons_handler_initialized_with_inspect_node() {
856        let inspector = fuchsia_inspect::Inspector::default();
857        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
858        let _handler =
859            MediaButtonsHandler::new(&fake_handlers_node, metrics::MetricsLogger::default());
860        diagnostics_assertions::assert_data_tree!(inspector, root: {
861            input_handlers_node: {
862                media_buttons_handler: {
863                    events_received_count: 0u64,
864                    events_handled_count: 0u64,
865                    last_received_timestamp_ns: 0u64,
866                    "fuchsia.inspect.Health": {
867                        status: "STARTING_UP",
868                        // Timestamp value is unpredictable and not relevant in this context,
869                        // so we only assert that the property is present.
870                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
871                    },
872                }
873            }
874        });
875    }
876
877    #[fasync::run_singlethreaded(test)]
878    async fn media_buttons_handler_inspect_counts_events() {
879        let inspector = fuchsia_inspect::Inspector::default();
880        let fake_handlers_node = inspector.root().create_child("input_handlers_node");
881        let media_buttons_handler =
882            MediaButtonsHandler::new(&fake_handlers_node, metrics::MetricsLogger::default());
883
884        // Unhandled input event should be counted by inspect.
885        let descriptor = testing_utilities::consumer_controls_device_descriptor();
886        let events = vec![
887            input_device::InputEvent {
888                device_event: input_device::InputDeviceEvent::ConsumerControls(
889                    consumer_controls_binding::ConsumerControlsEvent::new(
890                        vec![fidl_input_report::ConsumerControlButton::VolumeUp],
891                        None,
892                    ),
893                ),
894                device_descriptor: descriptor.clone(),
895                event_time: zx::MonotonicInstant::get(),
896                handled: input_device::Handled::No,
897                trace_id: None,
898            },
899            // Handled input event should be ignored.
900            input_device::InputEvent {
901                device_event: input_device::InputDeviceEvent::ConsumerControls(
902                    consumer_controls_binding::ConsumerControlsEvent::new(
903                        vec![fidl_input_report::ConsumerControlButton::VolumeUp],
904                        None,
905                    ),
906                ),
907                device_descriptor: descriptor.clone(),
908                event_time: zx::MonotonicInstant::get(),
909                handled: input_device::Handled::Yes,
910                trace_id: None,
911            },
912            input_device::InputEvent {
913                device_event: input_device::InputDeviceEvent::ConsumerControls(
914                    consumer_controls_binding::ConsumerControlsEvent::new(
915                        vec![fidl_input_report::ConsumerControlButton::VolumeDown],
916                        None,
917                    ),
918                ),
919                device_descriptor: descriptor.clone(),
920                event_time: zx::MonotonicInstant::get(),
921                handled: input_device::Handled::No,
922                trace_id: None,
923            },
924        ];
925
926        let last_event_timestamp: u64 =
927            events[2].clone().event_time.into_nanos().try_into().unwrap();
928
929        for event in events {
930            media_buttons_handler.clone().handle_input_event(event).await;
931        }
932
933        diagnostics_assertions::assert_data_tree!(inspector, root: {
934            input_handlers_node: {
935                media_buttons_handler: {
936                    events_received_count: 2u64,
937                    events_handled_count: 2u64,
938                    last_received_timestamp_ns: last_event_timestamp,
939                    "fuchsia.inspect.Health": {
940                        status: "STARTING_UP",
941                        // Timestamp value is unpredictable and not relevant in this context,
942                        // so we only assert that the property is present.
943                        start_timestamp_nanos: diagnostics_assertions::AnyProperty
944                    },
945                }
946            }
947        });
948    }
949
950    #[fasync::run_singlethreaded(test)]
951    async fn clone_event_with_lease_duplicates_lease() {
952        let (event_pair, _) = fidl::EventPair::create();
953        let event_with_lease = fidl_ui_input::MediaButtonsEvent {
954            volume: Some(1),
955            mic_mute: Some(true),
956            pause: Some(true),
957            camera_disable: Some(true),
958            power: Some(true),
959            function: Some(true),
960            device_id: Some(1),
961            wake_lease: Some(event_pair),
962            ..Default::default()
963        };
964
965        // Test cloning an event that has a wake lease.
966        // With wake lease argument should duplicate the handle.
967        let cloned_event = MediaButtonsHandler::clone_event(&event_with_lease);
968        assert_eq!(event_with_lease.volume, cloned_event.volume);
969        assert_eq!(event_with_lease.mic_mute, cloned_event.mic_mute);
970        assert_eq!(event_with_lease.pause, cloned_event.pause);
971        assert_eq!(event_with_lease.camera_disable, cloned_event.camera_disable);
972        assert_eq!(event_with_lease.power, cloned_event.power);
973        assert_eq!(event_with_lease.function, cloned_event.function);
974        assert_eq!(event_with_lease.device_id, cloned_event.device_id);
975        assert!(event_with_lease.wake_lease.is_some());
976        assert!(cloned_event.wake_lease.is_some());
977        assert_ne!(
978            event_with_lease.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
979            cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
980        );
981        assert_eq!(
982            event_with_lease.wake_lease.as_ref().unwrap().koid(),
983            cloned_event.wake_lease.as_ref().unwrap().koid()
984        );
985    }
986
987    #[fasync::run_singlethreaded(test)]
988    async fn clone_event_without_lease_has_no_lease() {
989        // Test cloning an event that does not have a wake lease.
990        let event_without_lease = fidl_ui_input::MediaButtonsEvent {
991            volume: Some(1),
992            mic_mute: Some(true),
993            pause: Some(true),
994            camera_disable: Some(true),
995            power: Some(true),
996            function: Some(true),
997            device_id: Some(1),
998            ..Default::default()
999        };
1000
1001        // With wake lease argument should result in no wake lease.
1002        let cloned_event = MediaButtonsHandler::clone_event(&event_without_lease);
1003        assert_eq!(event_without_lease.volume, cloned_event.volume);
1004        assert_eq!(event_without_lease.mic_mute, cloned_event.mic_mute);
1005        assert_eq!(event_without_lease.pause, cloned_event.pause);
1006        assert_eq!(event_without_lease.camera_disable, cloned_event.camera_disable);
1007        assert_eq!(event_without_lease.power, cloned_event.power);
1008        assert_eq!(event_without_lease.function, cloned_event.function);
1009        assert_eq!(event_without_lease.device_id, cloned_event.device_id);
1010        assert!(cloned_event.wake_lease.is_none());
1011    }
1012}