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