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