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