1use crate::{
6 Dispatcher, Incoming, Transport, consumer_controls_binding, keyboard_binding,
7 light_sensor_binding, metrics, mouse_binding, touch_binding,
8};
9use anyhow::{Error, format_err};
10use async_trait::async_trait;
11use fidl_fuchsia_io as fio;
12use fidl_next_fuchsia_input_report::InputDevice;
13use fuchsia_inspect::health::Reporter;
14use fuchsia_inspect::{
15 ExponentialHistogramParams, HistogramProperty as _, NumericProperty, Property,
16};
17use fuchsia_trace as ftrace;
18use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
19use futures::stream::StreamExt;
20use metrics_registry::*;
21use sorted_vec_map::SortedVecSet;
22use std::path::Path;
23use strum_macros::{Display, EnumCount};
24
25pub use input_device_constants::InputDeviceType;
26
27#[derive(Debug, Clone, Default)]
28pub struct InputPipelineFeatureFlags {
29 pub enable_merge_touch_events: bool,
31}
32
33pub static INPUT_REPORT_PATH: &str = "/svc/fuchsia.input.report.Service";
35
36const LATENCY_HISTOGRAM_PROPERTIES: ExponentialHistogramParams<i64> = ExponentialHistogramParams {
37 floor: 0,
38 initial_step: 1,
39 step_multiplier: 10,
40 buckets: 7,
51};
52
53pub struct InputDeviceStatus {
56 now: Box<dyn Fn() -> zx::MonotonicInstant>,
59
60 _node: fuchsia_inspect::Node,
62
63 reports_received_count: fuchsia_inspect::UintProperty,
65
66 reports_filtered_count: fuchsia_inspect::UintProperty,
69
70 events_generated: fuchsia_inspect::UintProperty,
73
74 last_received_timestamp_ns: fuchsia_inspect::UintProperty,
76
77 last_generated_timestamp_ns: fuchsia_inspect::UintProperty,
79
80 pub health_node: fuchsia_inspect::health::Node,
82
83 driver_to_binding_latency_ms: fuchsia_inspect::IntExponentialHistogramProperty,
88
89 wake_lease_leak_count: fuchsia_inspect::UintProperty,
91}
92
93impl InputDeviceStatus {
94 pub fn new(device_node: fuchsia_inspect::Node) -> Self {
95 Self::new_internal(device_node, Box::new(zx::MonotonicInstant::get))
96 }
97
98 fn new_internal(
99 device_node: fuchsia_inspect::Node,
100 now: Box<dyn Fn() -> zx::MonotonicInstant>,
101 ) -> Self {
102 let mut health_node = fuchsia_inspect::health::Node::new(&device_node);
103 health_node.set_starting_up();
104
105 let reports_received_count = device_node.create_uint("reports_received_count", 0);
106 let reports_filtered_count = device_node.create_uint("reports_filtered_count", 0);
107 let events_generated = device_node.create_uint("events_generated", 0);
108 let last_received_timestamp_ns = device_node.create_uint("last_received_timestamp_ns", 0);
109 let last_generated_timestamp_ns = device_node.create_uint("last_generated_timestamp_ns", 0);
110 let driver_to_binding_latency_ms = device_node.create_int_exponential_histogram(
111 "driver_to_binding_latency_ms",
112 LATENCY_HISTOGRAM_PROPERTIES,
113 );
114 let wake_lease_leak_count = device_node.create_uint("wake_lease_leak_count", 0);
115
116 Self {
117 now,
118 _node: device_node,
119 reports_received_count,
120 reports_filtered_count,
121 events_generated,
122 last_received_timestamp_ns,
123 last_generated_timestamp_ns,
124 health_node,
125 driver_to_binding_latency_ms,
126 wake_lease_leak_count,
127 }
128 }
129
130 pub fn count_received_report_wire(
131 &self,
132 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
133 ) {
134 self.reports_received_count.add(1);
135 match report.event_time() {
136 Some(event_time) => {
137 self.driver_to_binding_latency_ms.insert(
138 ((self.now)() - zx::MonotonicInstant::from_nanos(event_time.0)).into_millis(),
139 );
140 self.last_received_timestamp_ns.set(event_time.0.try_into().unwrap());
141 }
142 None => (),
143 }
144 }
145
146 pub fn count_filtered_report(&self) {
147 self.reports_filtered_count.add(1);
148 }
149
150 pub fn count_generated_event(&self, event: InputEvent) {
151 self.events_generated.add(1);
152 self.last_generated_timestamp_ns.set(event.event_time.into_nanos().try_into().unwrap());
153 }
154
155 pub fn count_generated_events(&self, events: &Vec<InputEvent>) {
156 self.events_generated.add(events.len() as u64);
157 if let Some(last_event) = events.last() {
158 self.last_generated_timestamp_ns
159 .set(last_event.event_time.into_nanos().try_into().unwrap());
160 }
161 }
162
163 pub fn count_wake_lease_leak(&self) {
164 self.wake_lease_leak_count.add(1);
165 }
166}
167
168#[derive(Clone, Debug, PartialEq)]
169pub enum PreviousDeviceState {
170 Keyboard {
171 pressed_keys: Vec<fidl_fuchsia_input::Key>,
172 },
173 Mouse {
174 pressed_buttons: SortedVecSet<mouse_binding::MouseButton>,
175 },
176 TouchScreen {
177 active_contacts: Vec<touch_binding::TouchContact>,
178 pressed_buttons: Vec<fidl_next_fuchsia_input_report::TouchButton>,
179 },
180 ConsumerControls {
181 pressed_buttons: Vec<fidl_fuchsia_input_report::ConsumerControlButton>,
182 },
183 LightSensor,
184 #[cfg(test)]
185 Fake,
186}
187
188#[derive(Clone, Debug, PartialEq)]
190pub struct InputEvent {
191 pub device_event: InputDeviceEvent,
193
194 pub device_descriptor: InputDeviceDescriptor,
197
198 pub event_time: zx::MonotonicInstant,
200
201 pub handled: Handled,
203
204 pub trace_id: Option<ftrace::Id>,
205}
206
207#[derive(Clone, Debug, PartialEq)]
213pub struct UnhandledInputEvent {
214 pub device_event: InputDeviceEvent,
216
217 pub device_descriptor: InputDeviceDescriptor,
220
221 pub event_time: zx::MonotonicInstant,
223
224 pub trace_id: Option<ftrace::Id>,
225}
226
227impl UnhandledInputEvent {
228 pub fn get_event_type(&self) -> &'static str {
230 match self.device_event {
231 InputDeviceEvent::Keyboard(_) => "keyboard_event",
232 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
233 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
234 InputDeviceEvent::Mouse(_) => "mouse_event",
235 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
236 InputDeviceEvent::Touchpad(_) => "touchpad_event",
237 #[cfg(test)]
238 InputDeviceEvent::Fake => "fake_event",
239 }
240 }
241}
242
243#[derive(Clone, Debug, PartialEq)]
252pub enum InputDeviceEvent {
253 Keyboard(keyboard_binding::KeyboardEvent),
254 LightSensor(light_sensor_binding::LightSensorEvent),
255 ConsumerControls(consumer_controls_binding::ConsumerControlsEvent),
256 Mouse(mouse_binding::MouseEvent),
257 TouchScreen(touch_binding::TouchScreenEvent),
258 Touchpad(touch_binding::TouchpadEvent),
259 #[cfg(test)]
260 Fake,
261}
262
263#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumCount, Display)]
265#[strum(serialize_all = "snake_case")]
266pub enum InputEventType {
267 Keyboard = 0,
268 LightSensor = 1,
269 ConsumerControls = 2,
270 Mouse = 3,
271 TouchScreen = 4,
272 Touchpad = 5,
273 #[cfg(test)]
274 Fake = 6,
275}
276
277impl From<&InputDeviceEvent> for InputEventType {
278 fn from(event: &InputDeviceEvent) -> Self {
279 match event {
280 InputDeviceEvent::Keyboard(_) => InputEventType::Keyboard,
281 InputDeviceEvent::LightSensor(_) => InputEventType::LightSensor,
282 InputDeviceEvent::ConsumerControls(_) => InputEventType::ConsumerControls,
283 InputDeviceEvent::Mouse(_) => InputEventType::Mouse,
284 InputDeviceEvent::TouchScreen(_) => InputEventType::TouchScreen,
285 InputDeviceEvent::Touchpad(_) => InputEventType::Touchpad,
286 #[cfg(test)]
287 InputDeviceEvent::Fake => InputEventType::Fake,
288 }
289 }
290}
291
292#[derive(Clone, Debug, PartialEq)]
302pub enum InputDeviceDescriptor {
303 Keyboard(keyboard_binding::KeyboardDeviceDescriptor),
304 LightSensor(light_sensor_binding::LightSensorDeviceDescriptor),
305 ConsumerControls(consumer_controls_binding::ConsumerControlsDeviceDescriptor),
306 Mouse(mouse_binding::MouseDeviceDescriptor),
307 TouchScreen(touch_binding::TouchScreenDeviceDescriptor),
308 Touchpad(touch_binding::TouchpadDeviceDescriptor),
309 #[cfg(test)]
310 Fake,
311}
312
313impl From<keyboard_binding::KeyboardDeviceDescriptor> for InputDeviceDescriptor {
314 fn from(b: keyboard_binding::KeyboardDeviceDescriptor) -> Self {
315 InputDeviceDescriptor::Keyboard(b)
316 }
317}
318
319impl InputDeviceDescriptor {
320 pub fn device_id(&self) -> u32 {
321 match self {
322 InputDeviceDescriptor::Keyboard(b) => b.device_id,
323 InputDeviceDescriptor::LightSensor(b) => b.device_id,
324 InputDeviceDescriptor::ConsumerControls(b) => b.device_id,
325 InputDeviceDescriptor::Mouse(b) => b.device_id,
326 InputDeviceDescriptor::TouchScreen(b) => b.device_id,
327 InputDeviceDescriptor::Touchpad(b) => b.device_id,
328 #[cfg(test)]
329 InputDeviceDescriptor::Fake => 0,
330 }
331 }
332}
333
334#[derive(Copy, Clone, Debug, PartialEq)]
336pub enum Handled {
337 Yes,
339 No,
341}
342
343#[async_trait]
352pub trait InputDeviceBinding: Send {
353 fn get_device_descriptor(&self) -> InputDeviceDescriptor;
355
356 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>>;
358}
359
360pub fn initialize_report_stream<InputDeviceProcessReportsFn>(
377 device_proxy: fidl_next::Client<InputDevice, Transport>,
378 device_descriptor: InputDeviceDescriptor,
379 mut event_sender: UnboundedSender<Vec<InputEvent>>,
380 inspect_status: InputDeviceStatus,
381 metrics_logger: metrics::MetricsLogger,
382 feature_flags: InputPipelineFeatureFlags,
383 mut process_reports: InputDeviceProcessReportsFn,
384) where
385 InputDeviceProcessReportsFn: 'static
386 + Send
387 + for<'de> FnMut(
388 &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
389 Option<PreviousDeviceState>,
390 &InputDeviceDescriptor,
391 &mut UnboundedSender<Vec<InputEvent>>,
392 &InputDeviceStatus,
393 &metrics::MetricsLogger,
394 &InputPipelineFeatureFlags,
395 )
396 -> (Option<PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>),
397{
398 Dispatcher::spawn_local(async move {
399 let mut previous_state: Option<PreviousDeviceState> = None;
400 let (report_reader, server_end) = fidl_next::fuchsia::create_channel();
401 let report_reader = Dispatcher::client_from_zx_channel(report_reader);
402 let result = device_proxy.get_input_reports_reader(server_end).await;
403 if result.is_err() {
404 metrics_logger.log_error(
405 InputPipelineErrorMetricDimensionEvent::InputDeviceGetInputReportsReaderError,
406 std::format!("error on GetInputReportsReader: {:?}", result),
407 );
408 return; }
410 let report_reader = report_reader.spawn();
411 loop {
412 let read_result = {
413 fuchsia_trace::duration!("input", "read_input_reports");
414 report_reader.read_input_reports().wire().await
415 };
416 match read_result {
417 Err(_fidl_error) => break,
418 Ok(decoded) => match decoded.as_ref() {
419 Err(_service_error) => break,
420 Ok(response) => {
421 fuchsia_trace::duration!("input", "input-device-process-reports");
422 let (prev_state, inspect_receiver) = process_reports(
425 response.reports.as_slice(),
426 previous_state,
427 &device_descriptor,
428 &mut event_sender,
429 &inspect_status,
430 &metrics_logger,
431 &feature_flags,
432 );
433 previous_state = prev_state;
434
435 match inspect_receiver {
439 Some(mut receiver) => {
440 while let Some(event) = receiver.next().await {
441 inspect_status.count_generated_event(event);
442 }
443 }
444 None => (),
445 };
446 }
447 },
448 }
449 }
450 log::warn!("initialize_report_stream exited - device binding no longer works");
453 })
454 .detach();
455}
456
457pub async fn is_device_type(
463 device_descriptor: &fidl_next_fuchsia_input_report::DeviceDescriptor,
464 device_type: InputDeviceType,
465) -> bool {
466 match device_type {
468 InputDeviceType::ConsumerControls => device_descriptor.consumer_control.is_some(),
469 InputDeviceType::Mouse => device_descriptor.mouse.is_some(),
470 InputDeviceType::Touch => device_descriptor.touch.is_some(),
471 InputDeviceType::Keyboard => device_descriptor.keyboard.is_some(),
472 InputDeviceType::LightSensor => device_descriptor.sensor.is_some(),
473 }
474}
475
476pub async fn get_device_binding(
484 device_type: InputDeviceType,
485 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
486 device_id: u32,
487 input_event_sender: UnboundedSender<Vec<InputEvent>>,
488 device_node: fuchsia_inspect::Node,
489 feature_flags: InputPipelineFeatureFlags,
490 metrics_logger: metrics::MetricsLogger,
491) -> Result<Box<dyn InputDeviceBinding>, Error> {
492 match device_type {
493 InputDeviceType::ConsumerControls => {
494 let binding = consumer_controls_binding::ConsumerControlsBinding::new(
495 device_proxy,
496 device_id,
497 input_event_sender,
498 device_node,
499 feature_flags.clone(),
500 metrics_logger,
501 )
502 .await?;
503 Ok(Box::new(binding))
504 }
505 InputDeviceType::Mouse => {
506 let binding = mouse_binding::MouseBinding::new(
507 device_proxy,
508 device_id,
509 input_event_sender,
510 device_node,
511 feature_flags.clone(),
512 metrics_logger,
513 )
514 .await?;
515 Ok(Box::new(binding))
516 }
517 InputDeviceType::Touch => {
518 let binding = touch_binding::TouchBinding::new(
519 device_proxy,
520 device_id,
521 input_event_sender,
522 device_node,
523 feature_flags.clone(),
524 metrics_logger,
525 )
526 .await?;
527 Ok(Box::new(binding))
528 }
529 InputDeviceType::Keyboard => {
530 let binding = keyboard_binding::KeyboardBinding::new(
531 device_proxy,
532 device_id,
533 input_event_sender,
534 device_node,
535 feature_flags.clone(),
536 metrics_logger,
537 )
538 .await?;
539 Ok(Box::new(binding))
540 }
541 InputDeviceType::LightSensor => {
542 let binding = light_sensor_binding::LightSensorBinding::new(
543 device_proxy,
544 device_id,
545 input_event_sender,
546 device_node,
547 feature_flags.clone(),
548 metrics_logger,
549 )
550 .await?;
551 Ok(Box::new(binding))
552 }
553 }
554}
555
556pub fn get_device_from_dir_entry_path(
565 dir_proxy: &fio::DirectoryProxy,
566 entry_path: &Path,
567) -> Result<fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>, Error> {
568 let input_device_path =
569 entry_path.to_str().ok_or_else(|| format_err!("Failed to get entry path as a string."))?;
570
571 let input_device = Incoming::connect_protocol_next_at(dir_proxy, input_device_path)
572 .map_err(|e| format_err!("Failed to connect to InputDevice: {:?}", e))?;
573 Ok(input_device.spawn())
574}
575
576pub fn event_time_or_now(event_time: Option<i64>) -> zx::MonotonicInstant {
581 match event_time {
582 Some(time) => zx::MonotonicInstant::from_nanos(time),
583 None => zx::MonotonicInstant::get(),
584 }
585}
586
587impl std::convert::From<UnhandledInputEvent> for InputEvent {
588 fn from(event: UnhandledInputEvent) -> Self {
589 Self {
590 device_event: event.device_event,
591 device_descriptor: event.device_descriptor,
592 event_time: event.event_time,
593 handled: Handled::No,
594 trace_id: event.trace_id,
595 }
596 }
597}
598
599#[cfg(test)]
606impl std::convert::TryFrom<InputEvent> for UnhandledInputEvent {
607 type Error = anyhow::Error;
608 fn try_from(event: InputEvent) -> Result<UnhandledInputEvent, Self::Error> {
609 match event.handled {
610 Handled::Yes => {
611 Err(format_err!("Attempted to treat a handled InputEvent as unhandled"))
612 }
613 Handled::No => Ok(UnhandledInputEvent {
614 device_event: event.device_event,
615 device_descriptor: event.device_descriptor,
616 event_time: event.event_time,
617 trace_id: event.trace_id,
618 }),
619 }
620 }
621}
622
623impl InputEvent {
624 pub(crate) fn into_handled_if(self, predicate: bool) -> Self {
627 if predicate { Self { handled: Handled::Yes, ..self } } else { self }
628 }
629
630 pub(crate) fn into_handled(self) -> Self {
632 Self { handled: Handled::Yes, ..self }
633 }
634
635 pub fn into_with_event_time(self, event_time: zx::MonotonicInstant) -> Self {
637 Self { event_time, ..self }
638 }
639
640 #[cfg(test)]
642 pub fn into_with_device_descriptor(self, device_descriptor: InputDeviceDescriptor) -> Self {
643 Self { device_descriptor, ..self }
644 }
645
646 pub fn is_handled(&self) -> bool {
648 self.handled == Handled::Yes
649 }
650
651 pub fn get_event_type(&self) -> &'static str {
653 match self.device_event {
654 InputDeviceEvent::Keyboard(_) => "keyboard_event",
655 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
656 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
657 InputDeviceEvent::Mouse(_) => "mouse_event",
658 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
659 InputDeviceEvent::Touchpad(_) => "touchpad_event",
660 #[cfg(test)]
661 InputDeviceEvent::Fake => "fake_event",
662 }
663 }
664
665 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
666 node.record_int("event_time", self.event_time.into_nanos());
667 match &self.device_event {
668 InputDeviceEvent::LightSensor(e) => e.record_inspect(node),
669 InputDeviceEvent::ConsumerControls(e) => e.record_inspect(node),
670 InputDeviceEvent::Mouse(e) => e.record_inspect(node),
671 InputDeviceEvent::TouchScreen(e) => e.record_inspect(node),
672 InputDeviceEvent::Touchpad(e) => e.record_inspect(node),
673 InputDeviceEvent::Keyboard(_) => (),
675 #[cfg(test)] InputDeviceEvent::Fake => (),
677 }
678 }
679}
680
681#[cfg(test)]
682mod tests {
683 use super::*;
684 use crate::testing_utilities::spawn_input_stream_handler;
685 use assert_matches::assert_matches;
686 use diagnostics_assertions::AnyProperty;
687 use fidl_fuchsia_input_report as fidl_input_report;
688 use fidl_next_fuchsia_input_report::InputReport;
689 use fuchsia_async as fasync;
690 use pretty_assertions::assert_eq;
691 use std::convert::TryFrom as _;
692 use test_case::test_case;
693
694 #[test]
695 fn max_event_time() {
696 let event_time = event_time_or_now(Some(i64::MAX));
697 assert_eq!(event_time, zx::MonotonicInstant::INFINITE);
698 }
699
700 #[test]
701 fn min_event_time() {
702 let event_time = event_time_or_now(Some(std::i64::MIN));
703 assert_eq!(event_time, zx::MonotonicInstant::INFINITE_PAST);
704 }
705
706 #[fasync::run_singlethreaded(test)]
707 async fn input_device_status_initialized_with_correct_properties() {
708 let inspector = fuchsia_inspect::Inspector::default();
709 let input_pipeline_node = inspector.root().create_child("input_pipeline");
710 let input_devices_node = input_pipeline_node.create_child("input_devices");
711 let device_node = input_devices_node.create_child("001_keyboard");
712 let _input_device_status = InputDeviceStatus::new(device_node);
713 diagnostics_assertions::assert_data_tree!(inspector, root: {
714 input_pipeline: {
715 input_devices: {
716 "001_keyboard": {
717 reports_received_count: 0u64,
718 reports_filtered_count: 0u64,
719 events_generated: 0u64,
720 last_received_timestamp_ns: 0u64,
721 last_generated_timestamp_ns: 0u64,
722 "fuchsia.inspect.Health": {
723 status: "STARTING_UP",
724 start_timestamp_nanos: AnyProperty
727 },
728 driver_to_binding_latency_ms: diagnostics_assertions::HistogramAssertion::exponential(super::LATENCY_HISTOGRAM_PROPERTIES),
729 wake_lease_leak_count: 0u64,
730 }
731 }
732 }
733 });
734 }
735
736 #[test_case(i64::MIN; "min value")]
737 #[test_case(-1; "negative value")]
738 #[test_case(0; "zero")]
739 #[test_case(1; "positive value")]
740 #[test_case(i64::MAX; "max value")]
741 #[fuchsia::test(allow_stalls = false)]
742 async fn input_device_status_updates_latency_histogram_on_count_received_report_wire(
743 latency_nsec: i64,
744 ) {
745 let mut expected_histogram = diagnostics_assertions::HistogramAssertion::exponential(
746 super::LATENCY_HISTOGRAM_PROPERTIES,
747 );
748 let inspector = fuchsia_inspect::Inspector::default();
749 let input_device_status = InputDeviceStatus::new_internal(
750 inspector.root().clone_weak(),
751 Box::new(move || zx::MonotonicInstant::from_nanos(latency_nsec)),
752 );
753 let decoded = crate::testing_utilities::report_to_wire(InputReport {
754 event_time: Some(0),
755 ..InputReport::default()
756 });
757 input_device_status.count_received_report_wire(&decoded);
758 expected_histogram.insert_values([latency_nsec / 1000 / 1000]);
759 diagnostics_assertions::assert_data_tree!(inspector, root: contains {
760 driver_to_binding_latency_ms: expected_histogram,
761 });
762 }
763
764 #[fasync::run_singlethreaded(test)]
767 async fn consumer_controls_input_device_exists() {
768 let (input_device_proxy, _task) =
769 spawn_input_stream_handler(move |input_device_request| async move {
770 match input_device_request {
771 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
772 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
773 device_information: None,
774 mouse: None,
775 sensor: None,
776 touch: None,
777 keyboard: None,
778 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
779 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
780 buttons: Some(vec![
781 fidl_input_report::ConsumerControlButton::VolumeUp,
782 fidl_input_report::ConsumerControlButton::VolumeDown,
783 ]),
784 ..Default::default()
785 }),
786 ..Default::default()
787 }),
788 ..Default::default()
789 });
790 }
791 _ => panic!("InputDevice handler received an unexpected request"),
792 }
793 });
794
795 assert!(
796 is_device_type(
797 &input_device_proxy
798 .get_descriptor()
799 .await
800 .expect("Failed to get device descriptor")
801 .descriptor,
802 InputDeviceType::ConsumerControls
803 )
804 .await
805 );
806 }
807
808 #[fasync::run_singlethreaded(test)]
810 async fn mouse_input_device_exists() {
811 let (input_device_proxy, _task) =
812 spawn_input_stream_handler(move |input_device_request| async move {
813 match input_device_request {
814 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
815 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
816 device_information: None,
817 mouse: Some(fidl_input_report::MouseDescriptor {
818 input: Some(fidl_input_report::MouseInputDescriptor {
819 movement_x: None,
820 movement_y: None,
821 position_x: None,
822 position_y: None,
823 scroll_v: None,
824 scroll_h: None,
825 buttons: None,
826 ..Default::default()
827 }),
828 ..Default::default()
829 }),
830 sensor: None,
831 touch: None,
832 keyboard: None,
833 consumer_control: None,
834 ..Default::default()
835 });
836 }
837 _ => panic!("InputDevice handler received an unexpected request"),
838 }
839 });
840
841 assert!(
842 is_device_type(
843 &input_device_proxy
844 .get_descriptor()
845 .await
846 .expect("Failed to get device descriptor")
847 .descriptor,
848 InputDeviceType::Mouse
849 )
850 .await
851 );
852 }
853
854 #[fasync::run_singlethreaded(test)]
857 async fn mouse_input_device_doesnt_exist() {
858 let (input_device_proxy, _task) =
859 spawn_input_stream_handler(move |input_device_request| async move {
860 match input_device_request {
861 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
862 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
863 device_information: None,
864 mouse: None,
865 sensor: None,
866 touch: None,
867 keyboard: None,
868 consumer_control: None,
869 ..Default::default()
870 });
871 }
872 _ => panic!("InputDevice handler received an unexpected request"),
873 }
874 });
875
876 assert!(
877 !is_device_type(
878 &input_device_proxy
879 .get_descriptor()
880 .await
881 .expect("Failed to get device descriptor")
882 .descriptor,
883 InputDeviceType::Mouse
884 )
885 .await
886 );
887 }
888
889 #[fasync::run_singlethreaded(test)]
892 async fn touch_input_device_exists() {
893 let (input_device_proxy, _task) =
894 spawn_input_stream_handler(move |input_device_request| async move {
895 match input_device_request {
896 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
897 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
898 device_information: None,
899 mouse: None,
900 sensor: None,
901 touch: Some(fidl_input_report::TouchDescriptor {
902 input: Some(fidl_input_report::TouchInputDescriptor {
903 contacts: None,
904 max_contacts: None,
905 touch_type: None,
906 buttons: None,
907 ..Default::default()
908 }),
909 ..Default::default()
910 }),
911 keyboard: None,
912 consumer_control: None,
913 ..Default::default()
914 });
915 }
916 _ => panic!("InputDevice handler received an unexpected request"),
917 }
918 });
919
920 assert!(
921 is_device_type(
922 &input_device_proxy
923 .get_descriptor()
924 .await
925 .expect("Failed to get device descriptor")
926 .descriptor,
927 InputDeviceType::Touch
928 )
929 .await
930 );
931 }
932
933 #[fasync::run_singlethreaded(test)]
936 async fn touch_input_device_doesnt_exist() {
937 let (input_device_proxy, _task) =
938 spawn_input_stream_handler(move |input_device_request| async move {
939 match input_device_request {
940 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
941 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
942 device_information: None,
943 mouse: None,
944 sensor: None,
945 touch: None,
946 keyboard: None,
947 consumer_control: None,
948 ..Default::default()
949 });
950 }
951 _ => panic!("InputDevice handler received an unexpected request"),
952 }
953 });
954
955 assert!(
956 !is_device_type(
957 &input_device_proxy
958 .get_descriptor()
959 .await
960 .expect("Failed to get device descriptor")
961 .descriptor,
962 InputDeviceType::Touch
963 )
964 .await
965 );
966 }
967
968 #[fasync::run_singlethreaded(test)]
971 async fn keyboard_input_device_exists() {
972 let (input_device_proxy, _task) =
973 spawn_input_stream_handler(move |input_device_request| async move {
974 match input_device_request {
975 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
976 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
977 device_information: None,
978 mouse: None,
979 sensor: None,
980 touch: None,
981 keyboard: Some(fidl_input_report::KeyboardDescriptor {
982 input: Some(fidl_input_report::KeyboardInputDescriptor {
983 keys3: None,
984 ..Default::default()
985 }),
986 output: None,
987 ..Default::default()
988 }),
989 consumer_control: None,
990 ..Default::default()
991 });
992 }
993 _ => panic!("InputDevice handler received an unexpected request"),
994 }
995 });
996
997 assert!(
998 is_device_type(
999 &input_device_proxy
1000 .get_descriptor()
1001 .await
1002 .expect("Failed to get device descriptor")
1003 .descriptor,
1004 InputDeviceType::Keyboard
1005 )
1006 .await
1007 );
1008 }
1009
1010 #[fasync::run_singlethreaded(test)]
1013 async fn keyboard_input_device_doesnt_exist() {
1014 let (input_device_proxy, _task) =
1015 spawn_input_stream_handler(move |input_device_request| async move {
1016 match input_device_request {
1017 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1018 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1019 device_information: None,
1020 mouse: None,
1021 sensor: None,
1022 touch: None,
1023 keyboard: None,
1024 consumer_control: None,
1025 ..Default::default()
1026 });
1027 }
1028 _ => panic!("InputDevice handler received an unexpected request"),
1029 }
1030 });
1031
1032 assert!(
1033 !is_device_type(
1034 &input_device_proxy
1035 .get_descriptor()
1036 .await
1037 .expect("Failed to get device descriptor")
1038 .descriptor,
1039 InputDeviceType::Keyboard
1040 )
1041 .await
1042 );
1043 }
1044
1045 #[fasync::run_singlethreaded(test)]
1047 async fn no_input_device_match() {
1048 let (input_device_proxy, _task) =
1049 spawn_input_stream_handler(move |input_device_request| async move {
1050 match input_device_request {
1051 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1052 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1053 device_information: None,
1054 mouse: Some(fidl_input_report::MouseDescriptor {
1055 input: Some(fidl_input_report::MouseInputDescriptor {
1056 movement_x: None,
1057 movement_y: None,
1058 position_x: None,
1059 position_y: None,
1060 scroll_v: None,
1061 scroll_h: None,
1062 buttons: None,
1063 ..Default::default()
1064 }),
1065 ..Default::default()
1066 }),
1067 sensor: None,
1068 touch: Some(fidl_input_report::TouchDescriptor {
1069 input: Some(fidl_input_report::TouchInputDescriptor {
1070 contacts: None,
1071 max_contacts: None,
1072 touch_type: None,
1073 buttons: None,
1074 ..Default::default()
1075 }),
1076 ..Default::default()
1077 }),
1078 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1079 input: Some(fidl_input_report::KeyboardInputDescriptor {
1080 keys3: None,
1081 ..Default::default()
1082 }),
1083 output: None,
1084 ..Default::default()
1085 }),
1086 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
1087 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
1088 buttons: Some(vec![
1089 fidl_input_report::ConsumerControlButton::VolumeUp,
1090 fidl_input_report::ConsumerControlButton::VolumeDown,
1091 ]),
1092 ..Default::default()
1093 }),
1094 ..Default::default()
1095 }),
1096 ..Default::default()
1097 });
1098 }
1099 _ => panic!("InputDevice handler received an unexpected request"),
1100 }
1101 });
1102
1103 let device_descriptor = &input_device_proxy
1104 .get_descriptor()
1105 .await
1106 .expect("Failed to get device descriptor")
1107 .descriptor;
1108 assert!(is_device_type(&device_descriptor, InputDeviceType::ConsumerControls).await);
1109 assert!(is_device_type(&device_descriptor, InputDeviceType::Mouse).await);
1110 assert!(is_device_type(&device_descriptor, InputDeviceType::Touch).await);
1111 assert!(is_device_type(&device_descriptor, InputDeviceType::Keyboard).await);
1112 }
1113
1114 #[fuchsia::test]
1115 fn unhandled_to_generic_conversion_sets_handled_flag_to_no() {
1116 assert_eq!(
1117 InputEvent::from(UnhandledInputEvent {
1118 device_event: InputDeviceEvent::Fake,
1119 device_descriptor: InputDeviceDescriptor::Fake,
1120 event_time: zx::MonotonicInstant::from_nanos(1),
1121 trace_id: None,
1122 })
1123 .handled,
1124 Handled::No
1125 );
1126 }
1127
1128 #[fuchsia::test]
1129 fn unhandled_to_generic_conversion_preserves_fields() {
1130 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1131 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1132 assert_eq!(
1133 InputEvent::from(UnhandledInputEvent {
1134 device_event: InputDeviceEvent::Fake,
1135 device_descriptor: InputDeviceDescriptor::Fake,
1136 event_time: EVENT_TIME,
1137 trace_id: expected_trace_id,
1138 }),
1139 InputEvent {
1140 device_event: InputDeviceEvent::Fake,
1141 device_descriptor: InputDeviceDescriptor::Fake,
1142 event_time: EVENT_TIME,
1143 handled: Handled::No,
1144 trace_id: expected_trace_id,
1145 },
1146 );
1147 }
1148
1149 #[fuchsia::test]
1150 fn generic_to_unhandled_conversion_fails_for_handled_events() {
1151 assert_matches!(
1152 UnhandledInputEvent::try_from(InputEvent {
1153 device_event: InputDeviceEvent::Fake,
1154 device_descriptor: InputDeviceDescriptor::Fake,
1155 event_time: zx::MonotonicInstant::from_nanos(1),
1156 handled: Handled::Yes,
1157 trace_id: None,
1158 }),
1159 Err(_)
1160 )
1161 }
1162
1163 #[fuchsia::test]
1164 fn generic_to_unhandled_conversion_preserves_fields_for_unhandled_events() {
1165 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1166 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1167 assert_eq!(
1168 UnhandledInputEvent::try_from(InputEvent {
1169 device_event: InputDeviceEvent::Fake,
1170 device_descriptor: InputDeviceDescriptor::Fake,
1171 event_time: EVENT_TIME,
1172 handled: Handled::No,
1173 trace_id: expected_trace_id,
1174 })
1175 .unwrap(),
1176 UnhandledInputEvent {
1177 device_event: InputDeviceEvent::Fake,
1178 device_descriptor: InputDeviceDescriptor::Fake,
1179 event_time: EVENT_TIME,
1180 trace_id: expected_trace_id,
1181 },
1182 )
1183 }
1184
1185 #[test_case(Handled::No; "initially not handled")]
1186 #[test_case(Handled::Yes; "initially handled")]
1187 fn into_handled_if_yields_handled_yes_on_true(initially_handled: Handled) {
1188 let event = InputEvent {
1189 device_event: InputDeviceEvent::Fake,
1190 device_descriptor: InputDeviceDescriptor::Fake,
1191 event_time: zx::MonotonicInstant::from_nanos(1),
1192 handled: initially_handled,
1193 trace_id: None,
1194 };
1195 pretty_assertions::assert_eq!(event.into_handled_if(true).handled, Handled::Yes);
1196 }
1197
1198 #[test_case(Handled::No; "initially not handled")]
1199 #[test_case(Handled::Yes; "initially handled")]
1200 fn into_handled_if_leaves_handled_unchanged_on_false(initially_handled: Handled) {
1201 let event = InputEvent {
1202 device_event: InputDeviceEvent::Fake,
1203 device_descriptor: InputDeviceDescriptor::Fake,
1204 event_time: zx::MonotonicInstant::from_nanos(1),
1205 handled: initially_handled.clone(),
1206 trace_id: None,
1207 };
1208 pretty_assertions::assert_eq!(event.into_handled_if(false).handled, initially_handled);
1209 }
1210
1211 #[test_case(Handled::No; "initially not handled")]
1212 #[test_case(Handled::Yes; "initially handled")]
1213 fn into_handled_yields_handled_yes(initially_handled: Handled) {
1214 let event = InputEvent {
1215 device_event: InputDeviceEvent::Fake,
1216 device_descriptor: InputDeviceDescriptor::Fake,
1217 event_time: zx::MonotonicInstant::from_nanos(1),
1218 handled: initially_handled,
1219 trace_id: None,
1220 };
1221 pretty_assertions::assert_eq!(event.into_handled().handled, Handled::Yes);
1222 }
1223}