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