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