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