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