1use 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
23pub struct MediaButtonsHandler {
25 inner: RefCell<MediaButtonsHandlerInner>,
27
28 pub inspect_status: InputHandlerStatus,
30
31 metrics_logger: metrics::MetricsLogger,
32}
33
34#[derive(Debug)]
35struct MediaButtonsHandlerInner {
36 pub listeners: HashMap<u32, fidl_ui_policy::MediaButtonsListenerProxy>,
38
39 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 self.send_event_to_listeners(&media_buttons_event).await;
76
77 self.inner.borrow_mut().last_event = Some(media_buttons_event);
79
80 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 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 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 self.inner
148 .borrow_mut()
149 .listeners
150 .insert(proxy.as_channel().raw_handle(), proxy.clone());
151 let proxy_clone = proxy.clone();
152
153 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 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 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#[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 receiver.for_each_concurrent(None, |task: fasync::Task<()>| task).await
277 });
278
279 Self { sender, _receiver_task: receiver_task }
280 }
281
282 pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: fasync::Task<()>) {
284 match self.sender.unbounded_send(task) {
285 Ok(_) => {}
286 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 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 #[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 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 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 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 #[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 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 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 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 use crate::input_handler::InputHandler as _; 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 #[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 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 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 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 use crate::input_handler::InputHandler as _; 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 #[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 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 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 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 std::mem::drop(third_listener_stream);
582
583 let _ = media_buttons_handler.clone().handle_input_event(input_event).await;
584 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 }
595 _ => assert!(false),
596 }
597 } else {
598 assert!(false);
599 }
600
601 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 let _ = exec.run_until_stalled(&mut task);
620
621 let _ = exec.run_singlethreaded(async {
623 assert_eq!(media_buttons_handler_clone.inner.borrow().listeners.len(), 2);
624 });
625 }
626
627 #[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 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 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 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 save_responder = Some(responder);
692 }
693 _ => assert!(false),
694 }
695 } else {
696 assert!(false)
697 }
698
699 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 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 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 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 let _ = save_responder.send();
759 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 }
773 _ => assert!(false),
774 }
775 } else {
776 assert!(false)
777 }
778 }
779 None => {
780 assert!(false)
781 }
782 }
783 }
784
785 #[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 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 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 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 start_timestamp_nanos: diagnostics_assertions::AnyProperty
909 },
910 }
911 }
912 });
913 }
914}