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