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