1use crate::input_handler::{InputHandlerStatus, UnhandledInputHandler};
6use crate::{consumer_controls_binding, input_device, metrics};
7use async_trait::async_trait;
8use fidl::HandleBased;
9use fidl::endpoints::Proxy;
10use fuchsia_inspect::health::Reporter;
11use futures::StreamExt;
12use futures::channel::mpsc;
13use metrics_registry::*;
14use std::cell::RefCell;
15use std::collections::HashMap;
16use std::rc::Rc;
17use zx::AsHandleRef;
18use {
19 fidl_fuchsia_input_report as fidl_input_report, fidl_fuchsia_ui_input as fidl_ui_input,
20 fidl_fuchsia_ui_policy as fidl_ui_policy, fuchsia_async as fasync,
21};
22
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 mut 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 media_buttons_event.wake_lease = None;
79 self.inner.borrow_mut().last_event = Some(media_buttons_event);
80
81 self.inspect_status.count_handled_event();
83 vec![input_device::InputEvent::from(unhandled_input_event).into_handled()]
84 }
85 _ => vec![input_device::InputEvent::from(unhandled_input_event)],
86 }
87 }
88
89 fn set_handler_healthy(self: std::rc::Rc<Self>) {
90 self.inspect_status.health_node.borrow_mut().set_ok();
91 }
92
93 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
94 self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
95 }
96}
97
98impl MediaButtonsHandler {
99 pub fn new(
101 input_handlers_node: &fuchsia_inspect::Node,
102 metrics_logger: metrics::MetricsLogger,
103 ) -> Rc<Self> {
104 let inspect_status =
105 InputHandlerStatus::new(input_handlers_node, "media_buttons_handler", false);
106 Self::new_internal(inspect_status, metrics_logger)
107 }
108
109 fn clone_event(event: &fidl_ui_input::MediaButtonsEvent) -> fidl_ui_input::MediaButtonsEvent {
110 fidl_ui_input::MediaButtonsEvent {
111 volume: event.volume,
112 mic_mute: event.mic_mute,
113 pause: event.pause,
114 camera_disable: event.camera_disable,
115 power: event.power,
116 function: event.function,
117 device_id: event.device_id,
118 wake_lease: event.wake_lease.as_ref().map(|lease| {
119 lease
120 .duplicate_handle(zx::Rights::SAME_RIGHTS)
121 .expect("failed to duplicate event pair")
122 }),
123 ..Default::default()
124 }
125 }
126
127 fn new_internal(
128 inspect_status: InputHandlerStatus,
129 metrics_logger: metrics::MetricsLogger,
130 ) -> Rc<Self> {
131 let media_buttons_handler = Self {
132 inner: RefCell::new(MediaButtonsHandlerInner {
133 listeners: HashMap::new(),
134 last_event: None,
135 send_event_task_tracker: LocalTaskTracker::new(),
136 }),
137 inspect_status,
138 metrics_logger,
139 };
140 Rc::new(media_buttons_handler)
141 }
142
143 fn create_media_buttons_event(
148 event: &consumer_controls_binding::ConsumerControlsEvent,
149 device_id: u32,
150 ) -> fidl_ui_input::MediaButtonsEvent {
151 let mut new_event = fidl_ui_input::MediaButtonsEvent {
152 volume: Some(0),
153 mic_mute: Some(false),
154 pause: Some(false),
155 camera_disable: Some(false),
156 power: Some(false),
157 function: Some(false),
158 device_id: Some(device_id),
159 ..Default::default()
160 };
161 for button in &event.pressed_buttons {
162 match button {
163 fidl_input_report::ConsumerControlButton::VolumeUp => {
164 new_event.volume = Some(new_event.volume.unwrap().saturating_add(1));
165 }
166 fidl_input_report::ConsumerControlButton::VolumeDown => {
167 new_event.volume = Some(new_event.volume.unwrap().saturating_sub(1));
168 }
169 fidl_input_report::ConsumerControlButton::MicMute => {
170 new_event.mic_mute = Some(true);
171 }
172 fidl_input_report::ConsumerControlButton::Pause => {
173 new_event.pause = Some(true);
174 }
175 fidl_input_report::ConsumerControlButton::CameraDisable => {
176 new_event.camera_disable = Some(true);
177 }
178 fidl_input_report::ConsumerControlButton::Function => {
179 new_event.function = Some(true);
180 }
181 fidl_input_report::ConsumerControlButton::Power => {
182 new_event.power = Some(true);
183 }
184 _ => {}
185 }
186 }
187
188 new_event
189 }
190
191 async fn send_event_to_listeners(self: &Rc<Self>, event: &fidl_ui_input::MediaButtonsEvent) {
196 let tracker = &self.inner.borrow().send_event_task_tracker;
197
198 for (handle, listener) in &self.inner.borrow().listeners {
199 let weak_handler = Rc::downgrade(&self);
200 let listener_clone = listener.clone();
201 let handle_clone = handle.clone();
202 let event_to_send = Self::clone_event(event);
203 let fut = async move {
204 match listener_clone.on_event(event_to_send).await {
205 Ok(_) => {}
206 Err(e) => {
207 if let Some(handler) = weak_handler.upgrade() {
208 handler.inner.borrow_mut().listeners.remove(&handle_clone);
209 log::info!(
210 "Unregistering listener; unable to send MediaButtonsEvent: {:?}",
211 e
212 )
213 }
214 }
215 }
216 };
217
218 let metrics_logger_clone = self.metrics_logger.clone();
219 tracker.track(metrics_logger_clone, fasync::Task::local(fut));
220 }
221 }
222
223 pub async fn register_listener_proxy(
228 self: &Rc<Self>,
229 proxy: fidl_ui_policy::MediaButtonsListenerProxy,
230 ) {
231 self.inner.borrow_mut().listeners.insert(proxy.as_channel().raw_handle(), proxy.clone());
232
233 if let Some(event) = &self.inner.borrow().last_event {
235 let event_to_send = Self::clone_event(event);
236 let fut = async move {
237 match proxy.on_event(event_to_send).await {
238 Ok(_) => {}
239 Err(e) => {
240 log::info!("Failed to send media buttons event to listener {:?}", e)
241 }
242 }
243 };
244 let metrics_logger_clone = self.metrics_logger.clone();
245 self.inner
246 .borrow()
247 .send_event_task_tracker
248 .track(metrics_logger_clone, fasync::Task::local(fut));
249 }
250 }
251}
252
253#[derive(Debug)]
256pub struct LocalTaskTracker {
257 sender: mpsc::UnboundedSender<fasync::Task<()>>,
258 _receiver_task: fasync::Task<()>,
259}
260
261impl LocalTaskTracker {
262 pub fn new() -> Self {
263 let (sender, receiver) = mpsc::unbounded();
264 let receiver_task = fasync::Task::local(async move {
265 receiver.for_each_concurrent(None, |task: fasync::Task<()>| task).await
267 });
268
269 Self { sender, _receiver_task: receiver_task }
270 }
271
272 pub fn track(&self, metrics_logger: metrics::MetricsLogger, task: fasync::Task<()>) {
274 match self.sender.unbounded_send(task) {
275 Ok(_) => {}
276 Err(e) => {
280 metrics_logger.log_error(
281 InputPipelineErrorMetricDimensionEvent::MediaButtonErrorWhilePushingTask,
282 std::format!("Unexpected {e:?} while pushing task"),
283 );
284 }
285 };
286 }
287}
288
289#[cfg(test)]
290mod tests {
291 use super::*;
292 use crate::input_handler::InputHandler;
293 use crate::testing_utilities;
294 use anyhow::Error;
295 use assert_matches::assert_matches;
296 use fidl::endpoints::create_proxy_and_stream;
297 use futures::TryStreamExt;
298 use futures::channel::oneshot;
299 use pretty_assertions::assert_eq;
300 use std::task::Poll;
301 use {fidl_fuchsia_input_report as fidl_input_report, fuchsia_async as fasync};
302
303 fn spawn_device_listener_registry_server(
304 handler: Rc<MediaButtonsHandler>,
305 ) -> fidl_ui_policy::DeviceListenerRegistryProxy {
306 let (device_listener_proxy, mut device_listener_stream) =
307 create_proxy_and_stream::<fidl_ui_policy::DeviceListenerRegistryMarker>();
308
309 fasync::Task::local(async move {
310 loop {
311 match device_listener_stream.try_next().await {
312 Ok(Some(fidl_ui_policy::DeviceListenerRegistryRequest::RegisterListener {
313 listener,
314 responder,
315 })) => {
316 handler.register_listener_proxy(listener.into_proxy()).await;
317 let _ = responder.send();
318 }
319 Ok(Some(_)) => {
320 panic!("Unexpected registration");
321 }
322 Ok(None) => {
323 break;
324 }
325 Err(e) => {
326 panic!("Error handling device listener registry request stream: {}", e);
327 }
328 }
329 }
330 })
331 .detach();
332
333 device_listener_proxy
334 }
335
336 fn create_ui_input_media_buttons_event(
337 volume: Option<i8>,
338 mic_mute: Option<bool>,
339 pause: Option<bool>,
340 camera_disable: Option<bool>,
341 power: Option<bool>,
342 function: Option<bool>,
343 ) -> fidl_ui_input::MediaButtonsEvent {
344 fidl_ui_input::MediaButtonsEvent {
345 volume,
346 mic_mute,
347 pause,
348 camera_disable,
349 power,
350 function,
351 device_id: Some(0),
352 ..Default::default()
353 }
354 }
355
356 fn make_signalable_task<T: Default + 'static>()
359 -> (oneshot::Sender<T>, fasync::Task<()>, Rc<RefCell<T>>) {
360 let (sender, receiver) = oneshot::channel();
361 let task_completed = Rc::new(RefCell::new(<T as Default>::default()));
362 let task_completed_ = task_completed.clone();
363 let task = fasync::Task::local(async move {
364 if let Ok(value) = receiver.await {
365 *task_completed_.borrow_mut() = value;
366 }
367 });
368 (sender, task, task_completed)
369 }
370
371 #[fasync::run_singlethreaded(test)]
374 async fn register_media_buttons_listener() {
375 let inspector = fuchsia_inspect::Inspector::default();
376 let test_node = inspector.root().create_child("test_node");
377 let inspect_status = InputHandlerStatus::new(
378 &test_node,
379 "media_buttons_handler",
380 false,
381 );
382
383 let media_buttons_handler = Rc::new(MediaButtonsHandler {
384 inner: RefCell::new(MediaButtonsHandlerInner {
385 listeners: HashMap::new(),
386 last_event: Some(create_ui_input_media_buttons_event(
387 Some(1),
388 None,
389 None,
390 None,
391 None,
392 None,
393 )),
394 send_event_task_tracker: LocalTaskTracker::new(),
395 }),
396 inspect_status,
397 metrics_logger: metrics::MetricsLogger::default(),
398 });
399 let device_listener_proxy =
400 spawn_device_listener_registry_server(media_buttons_handler.clone());
401
402 let (listener, mut listener_stream) =
404 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
405 let register_listener_fut = async {
406 let res = device_listener_proxy.register_listener(listener).await;
407 assert!(res.is_ok());
408 };
409
410 let expected_event =
412 create_ui_input_media_buttons_event(Some(1), None, None, None, None, None);
413 let assert_fut = async {
414 match listener_stream.next().await {
415 Some(Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
416 event,
417 responder,
418 })) => {
419 assert_eq!(event, expected_event);
420 responder.send().expect("responder failed.");
421 }
422 _ => assert!(false),
423 }
424 };
425 futures::join!(register_listener_fut, assert_fut);
426 assert_eq!(media_buttons_handler.inner.borrow().listeners.len(), 1);
427 }
428
429 #[fasync::run_singlethreaded(test)]
431 async fn listener_receives_all_buttons() {
432 let event_time = zx::MonotonicInstant::get();
433 let inspector = fuchsia_inspect::Inspector::default();
434 let test_node = inspector.root().create_child("test_node");
435 let inspect_status = InputHandlerStatus::new(
436 &test_node,
437 "media_buttons_handler",
438 false,
439 );
440 let media_buttons_handler =
441 MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
442 let device_listener_proxy =
443 spawn_device_listener_registry_server(media_buttons_handler.clone());
444
445 let (listener, listener_stream) =
447 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
448 let _ = device_listener_proxy.register_listener(listener).await;
449
450 let descriptor = testing_utilities::consumer_controls_device_descriptor();
452 let input_events = vec![testing_utilities::create_consumer_controls_event(
453 vec![
454 fidl_input_report::ConsumerControlButton::VolumeUp,
455 fidl_input_report::ConsumerControlButton::VolumeDown,
456 fidl_input_report::ConsumerControlButton::Pause,
457 fidl_input_report::ConsumerControlButton::MicMute,
458 fidl_input_report::ConsumerControlButton::CameraDisable,
459 fidl_input_report::ConsumerControlButton::Function,
460 fidl_input_report::ConsumerControlButton::Power,
461 ],
462 event_time,
463 &descriptor,
464 )];
465 let expected_events = vec![create_ui_input_media_buttons_event(
466 Some(0),
467 Some(true),
468 Some(true),
469 Some(true),
470 Some(true),
471 Some(true),
472 )];
473
474 use crate::input_handler::InputHandler as _; assert_input_event_sequence_generates_media_buttons_events!(
477 input_handler: media_buttons_handler,
478 input_events: input_events,
479 expected_events: expected_events,
480 media_buttons_listener_request_stream: vec![listener_stream],
481 );
482 }
483
484 #[fasync::run_singlethreaded(test)]
486 async fn multiple_listeners_receive_event() {
487 let event_time = zx::MonotonicInstant::get();
488 let inspector = fuchsia_inspect::Inspector::default();
489 let test_node = inspector.root().create_child("test_node");
490 let inspect_status = InputHandlerStatus::new(
491 &test_node,
492 "media_buttons_handler",
493 false,
494 );
495 let media_buttons_handler =
496 MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
497 let device_listener_proxy =
498 spawn_device_listener_registry_server(media_buttons_handler.clone());
499
500 let (first_listener, first_listener_stream) =
502 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
503 let (second_listener, second_listener_stream) =
504 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
505 let _ = device_listener_proxy.register_listener(first_listener).await;
506 let _ = device_listener_proxy.register_listener(second_listener).await;
507
508 let descriptor = testing_utilities::consumer_controls_device_descriptor();
510 let input_events = vec![testing_utilities::create_consumer_controls_event(
511 vec![fidl_input_report::ConsumerControlButton::VolumeUp],
512 event_time,
513 &descriptor,
514 )];
515 let expected_events = vec![create_ui_input_media_buttons_event(
516 Some(1),
517 Some(false),
518 Some(false),
519 Some(false),
520 Some(false),
521 Some(false),
522 )];
523
524 use crate::input_handler::InputHandler as _; assert_input_event_sequence_generates_media_buttons_events!(
527 input_handler: media_buttons_handler,
528 input_events: input_events,
529 expected_events: expected_events,
530 media_buttons_listener_request_stream:
531 vec![first_listener_stream, second_listener_stream],
532 );
533 }
534
535 #[fuchsia::test]
537 fn unregister_listener_if_channel_closed() {
538 let mut exec = fasync::TestExecutor::new();
539
540 let event_time = zx::MonotonicInstant::get();
541 let inspector = fuchsia_inspect::Inspector::default();
542 let test_node = inspector.root().create_child("test_node");
543 let inspect_status = InputHandlerStatus::new(
544 &test_node,
545 "media_buttons_handler",
546 false,
547 );
548 let media_buttons_handler =
549 MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
550 let media_buttons_handler_clone = media_buttons_handler.clone();
551
552 let mut task = fasync::Task::local(async move {
553 let device_listener_proxy =
554 spawn_device_listener_registry_server(media_buttons_handler.clone());
555
556 let (first_listener, mut first_listener_stream) =
558 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>(
559 );
560 let (second_listener, mut second_listener_stream) =
561 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>(
562 );
563 let (third_listener, third_listener_stream) = fidl::endpoints::create_request_stream::<
564 fidl_ui_policy::MediaButtonsListenerMarker,
565 >();
566 let _ = device_listener_proxy.register_listener(first_listener).await;
567 let _ = device_listener_proxy.register_listener(second_listener).await;
568 let _ = device_listener_proxy.register_listener(third_listener).await;
569 assert_eq!(media_buttons_handler.inner.borrow().listeners.len(), 3);
570
571 let descriptor = testing_utilities::consumer_controls_device_descriptor();
573 let input_event = testing_utilities::create_consumer_controls_event(
574 vec![fidl_input_report::ConsumerControlButton::VolumeUp],
575 event_time,
576 &descriptor,
577 );
578
579 let expected_media_buttons_event = create_ui_input_media_buttons_event(
580 Some(1),
581 Some(false),
582 Some(false),
583 Some(false),
584 Some(false),
585 Some(false),
586 );
587
588 std::mem::drop(third_listener_stream);
590
591 let _ = media_buttons_handler.clone().handle_input_event(input_event).await;
592 if let Some(request) = first_listener_stream.next().await {
594 match request {
595 Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
596 event,
597 responder: _,
598 }) => {
599 pretty_assertions::assert_eq!(event, expected_media_buttons_event);
600
601 }
603 _ => assert!(false),
604 }
605 } else {
606 assert!(false);
607 }
608
609 if let Some(request) = second_listener_stream.next().await {
611 match request {
612 Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
613 event,
614 responder,
615 }) => {
616 pretty_assertions::assert_eq!(event, expected_media_buttons_event);
617 let _ = responder.send();
618 }
619 _ => assert!(false),
620 }
621 } else {
622 assert!(false);
623 }
624 });
625
626 let _ = exec.run_until_stalled(&mut task);
628
629 let _ = exec.run_singlethreaded(async {
631 assert_eq!(media_buttons_handler_clone.inner.borrow().listeners.len(), 2);
632 });
633 }
634
635 #[fasync::run_singlethreaded(test)]
637 async fn stuck_reader_wont_block_input_pipeline() {
638 let event_time = zx::MonotonicInstant::get();
639 let inspector = fuchsia_inspect::Inspector::default();
640 let test_node = inspector.root().create_child("test_node");
641 let inspect_status = InputHandlerStatus::new(
642 &test_node,
643 "media_buttons_handler",
644 false,
645 );
646 let media_buttons_handler =
647 MediaButtonsHandler::new_internal(inspect_status, metrics::MetricsLogger::default());
648 let device_listener_proxy =
649 spawn_device_listener_registry_server(media_buttons_handler.clone());
650
651 let (first_listener, mut first_listener_stream) =
652 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
653 let (second_listener, mut second_listener_stream) =
654 fidl::endpoints::create_request_stream::<fidl_ui_policy::MediaButtonsListenerMarker>();
655 let _ = device_listener_proxy.register_listener(first_listener).await;
656 let _ = device_listener_proxy.register_listener(second_listener).await;
657
658 let descriptor = testing_utilities::consumer_controls_device_descriptor();
660 let first_unhandled_input_event = input_device::UnhandledInputEvent {
661 device_event: input_device::InputDeviceEvent::ConsumerControls(
662 consumer_controls_binding::ConsumerControlsEvent::new(vec![
663 fidl_input_report::ConsumerControlButton::VolumeUp,
664 ]),
665 ),
666 device_descriptor: descriptor.clone(),
667 event_time,
668 trace_id: None,
669 };
670 let first_expected_media_buttons_event = create_ui_input_media_buttons_event(
671 Some(1),
672 Some(false),
673 Some(false),
674 Some(false),
675 Some(false),
676 Some(false),
677 );
678
679 assert_matches!(
680 media_buttons_handler
681 .clone()
682 .handle_unhandled_input_event(first_unhandled_input_event)
683 .await
684 .as_slice(),
685 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
686 );
687
688 let mut save_responder = None;
689
690 if let Some(request) = first_listener_stream.next().await {
692 match request {
693 Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
694 pretty_assertions::assert_eq!(event, first_expected_media_buttons_event);
695
696 save_responder = Some(responder);
700 }
701 _ => assert!(false),
702 }
703 } else {
704 assert!(false)
705 }
706
707 if let Some(request) = second_listener_stream.next().await {
709 match request {
710 Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
711 pretty_assertions::assert_eq!(event, first_expected_media_buttons_event);
712 let _ = responder.send();
713 }
714 _ => assert!(false),
715 }
716 } else {
717 assert!(false)
718 }
719
720 let second_unhandled_input_event = input_device::UnhandledInputEvent {
722 device_event: input_device::InputDeviceEvent::ConsumerControls(
723 consumer_controls_binding::ConsumerControlsEvent::new(vec![
724 fidl_input_report::ConsumerControlButton::MicMute,
725 ]),
726 ),
727 device_descriptor: descriptor.clone(),
728 event_time,
729 trace_id: None,
730 };
731 let second_expected_media_buttons_event = create_ui_input_media_buttons_event(
732 Some(0),
733 Some(true),
734 Some(false),
735 Some(false),
736 Some(false),
737 Some(false),
738 );
739
740 assert_matches!(
742 media_buttons_handler
743 .clone()
744 .handle_unhandled_input_event(second_unhandled_input_event)
745 .await
746 .as_slice(),
747 [input_device::InputEvent { handled: input_device::Handled::Yes, .. }]
748 );
749
750 if let Some(request) = second_listener_stream.next().await {
752 match request {
753 Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent { event, responder }) => {
754 pretty_assertions::assert_eq!(event, second_expected_media_buttons_event);
755 let _ = responder.send();
756 }
757 _ => assert!(false),
758 }
759 } else {
760 assert!(false)
761 }
762
763 match save_responder {
764 Some(save_responder) => {
765 let _ = save_responder.send();
767 if let Some(request) = first_listener_stream.next().await {
769 match request {
770 Ok(fidl_ui_policy::MediaButtonsListenerRequest::OnEvent {
771 event,
772 responder: _,
773 }) => {
774 pretty_assertions::assert_eq!(
775 event,
776 second_expected_media_buttons_event
777 );
778
779 }
781 _ => assert!(false),
782 }
783 } else {
784 assert!(false)
785 }
786 }
787 None => {
788 assert!(false)
789 }
790 }
791 }
792
793 #[fuchsia::test]
795 fn local_task_tracker_test() -> Result<(), Error> {
796 let mut exec = fasync::TestExecutor::new();
797
798 let (mut sender_1, task_1, completed_1) = make_signalable_task::<bool>();
799 let (sender_2, task_2, completed_2) = make_signalable_task::<bool>();
800
801 let mut tracker = LocalTaskTracker::new();
802
803 tracker.track(metrics::MetricsLogger::default(), task_1);
804 tracker.track(metrics::MetricsLogger::default(), task_2);
805
806 assert_matches!(exec.run_until_stalled(&mut tracker._receiver_task), Poll::Pending);
807 assert_eq!(Rc::strong_count(&completed_1), 2);
808 assert_eq!(Rc::strong_count(&completed_2), 2);
809 assert!(!sender_1.is_canceled());
810 assert!(!sender_2.is_canceled());
811
812 assert!(sender_2.send(true).is_ok());
813 assert_matches!(exec.run_until_stalled(&mut tracker._receiver_task), Poll::Pending);
814
815 assert_eq!(Rc::strong_count(&completed_1), 2);
816 assert_eq!(Rc::strong_count(&completed_2), 1);
817 assert_eq!(*completed_1.borrow(), false);
818 assert_eq!(*completed_2.borrow(), true);
819 assert!(!sender_1.is_canceled());
820
821 drop(tracker);
822 let mut sender_1_cancellation = sender_1.cancellation();
823 assert_matches!(exec.run_until_stalled(&mut sender_1_cancellation), Poll::Ready(()));
824 assert_eq!(Rc::strong_count(&completed_1), 1);
825 assert!(sender_1.is_canceled());
826
827 Ok(())
828 }
829
830 #[fasync::run_singlethreaded(test)]
831 async fn media_buttons_handler_initialized_with_inspect_node() {
832 let inspector = fuchsia_inspect::Inspector::default();
833 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
834 let _handler =
835 MediaButtonsHandler::new(&fake_handlers_node, metrics::MetricsLogger::default());
836 diagnostics_assertions::assert_data_tree!(inspector, root: {
837 input_handlers_node: {
838 media_buttons_handler: {
839 events_received_count: 0u64,
840 events_handled_count: 0u64,
841 last_received_timestamp_ns: 0u64,
842 "fuchsia.inspect.Health": {
843 status: "STARTING_UP",
844 start_timestamp_nanos: diagnostics_assertions::AnyProperty
847 },
848 }
849 }
850 });
851 }
852
853 #[fasync::run_singlethreaded(test)]
854 async fn media_buttons_handler_inspect_counts_events() {
855 let inspector = fuchsia_inspect::Inspector::default();
856 let fake_handlers_node = inspector.root().create_child("input_handlers_node");
857 let media_buttons_handler =
858 MediaButtonsHandler::new(&fake_handlers_node, metrics::MetricsLogger::default());
859
860 let descriptor = testing_utilities::consumer_controls_device_descriptor();
862 let events = vec![
863 input_device::InputEvent {
864 device_event: input_device::InputDeviceEvent::ConsumerControls(
865 consumer_controls_binding::ConsumerControlsEvent::new(vec![
866 fidl_input_report::ConsumerControlButton::VolumeUp,
867 ]),
868 ),
869 device_descriptor: descriptor.clone(),
870 event_time: zx::MonotonicInstant::get(),
871 handled: input_device::Handled::No,
872 trace_id: None,
873 },
874 input_device::InputEvent {
876 device_event: input_device::InputDeviceEvent::ConsumerControls(
877 consumer_controls_binding::ConsumerControlsEvent::new(vec![
878 fidl_input_report::ConsumerControlButton::VolumeUp,
879 ]),
880 ),
881 device_descriptor: descriptor.clone(),
882 event_time: zx::MonotonicInstant::get(),
883 handled: input_device::Handled::Yes,
884 trace_id: None,
885 },
886 input_device::InputEvent {
887 device_event: input_device::InputDeviceEvent::ConsumerControls(
888 consumer_controls_binding::ConsumerControlsEvent::new(vec![
889 fidl_input_report::ConsumerControlButton::VolumeDown,
890 ]),
891 ),
892 device_descriptor: descriptor.clone(),
893 event_time: zx::MonotonicInstant::get(),
894 handled: input_device::Handled::No,
895 trace_id: None,
896 },
897 ];
898
899 let last_event_timestamp: u64 =
900 events[2].clone().event_time.into_nanos().try_into().unwrap();
901
902 for event in events {
903 media_buttons_handler.clone().handle_input_event(event).await;
904 }
905
906 diagnostics_assertions::assert_data_tree!(inspector, root: {
907 input_handlers_node: {
908 media_buttons_handler: {
909 events_received_count: 2u64,
910 events_handled_count: 2u64,
911 last_received_timestamp_ns: last_event_timestamp,
912 "fuchsia.inspect.Health": {
913 status: "STARTING_UP",
914 start_timestamp_nanos: diagnostics_assertions::AnyProperty
917 },
918 }
919 }
920 });
921 }
922
923 #[fasync::run_singlethreaded(test)]
924 async fn clone_event_with_lease_duplicates_lease() {
925 let (event_pair, _) = fidl::EventPair::create();
926 let event_with_lease = fidl_ui_input::MediaButtonsEvent {
927 volume: Some(1),
928 mic_mute: Some(true),
929 pause: Some(true),
930 camera_disable: Some(true),
931 power: Some(true),
932 function: Some(true),
933 device_id: Some(1),
934 wake_lease: Some(event_pair),
935 ..Default::default()
936 };
937
938 let cloned_event = MediaButtonsHandler::clone_event(&event_with_lease);
941 assert_eq!(event_with_lease.volume, cloned_event.volume);
942 assert_eq!(event_with_lease.mic_mute, cloned_event.mic_mute);
943 assert_eq!(event_with_lease.pause, cloned_event.pause);
944 assert_eq!(event_with_lease.camera_disable, cloned_event.camera_disable);
945 assert_eq!(event_with_lease.power, cloned_event.power);
946 assert_eq!(event_with_lease.function, cloned_event.function);
947 assert_eq!(event_with_lease.device_id, cloned_event.device_id);
948 assert!(event_with_lease.wake_lease.is_some());
949 assert!(cloned_event.wake_lease.is_some());
950 assert_ne!(
951 event_with_lease.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle(),
952 cloned_event.wake_lease.as_ref().unwrap().as_handle_ref().raw_handle()
953 );
954 assert_eq!(
955 event_with_lease.wake_lease.as_ref().unwrap().get_koid(),
956 cloned_event.wake_lease.as_ref().unwrap().get_koid()
957 );
958 }
959
960 #[fasync::run_singlethreaded(test)]
961 async fn clone_event_without_lease_has_no_lease() {
962 let event_without_lease = fidl_ui_input::MediaButtonsEvent {
964 volume: Some(1),
965 mic_mute: Some(true),
966 pause: Some(true),
967 camera_disable: Some(true),
968 power: Some(true),
969 function: Some(true),
970 device_id: Some(1),
971 ..Default::default()
972 };
973
974 let cloned_event = MediaButtonsHandler::clone_event(&event_without_lease);
976 assert_eq!(event_without_lease.volume, cloned_event.volume);
977 assert_eq!(event_without_lease.mic_mute, cloned_event.mic_mute);
978 assert_eq!(event_without_lease.pause, cloned_event.pause);
979 assert_eq!(event_without_lease.camera_disable, cloned_event.camera_disable);
980 assert_eq!(event_without_lease.power, cloned_event.power);
981 assert_eq!(event_without_lease.function, cloned_event.function);
982 assert_eq!(event_without_lease.device_id, cloned_event.device_id);
983 assert!(cloned_event.wake_lease.is_none());
984 }
985}