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