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