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