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