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