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