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, InputReport};
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 std::path::PathBuf;
22use strum_macros::{Display, EnumCount};
23
24pub use input_device_constants::InputDeviceType;
25
26#[derive(Debug, Clone, Default)]
27pub struct InputPipelineFeatureFlags {
28 pub enable_merge_touch_events: bool,
30}
31
32pub static INPUT_REPORT_PATH: &str = "/dev/class/input-report";
34
35const LATENCY_HISTOGRAM_PROPERTIES: ExponentialHistogramParams<i64> = ExponentialHistogramParams {
36 floor: 0,
37 initial_step: 1,
38 step_multiplier: 10,
39 buckets: 7,
50};
51
52pub struct InputDeviceStatus {
55 now: Box<dyn Fn() -> zx::MonotonicInstant>,
58
59 _node: fuchsia_inspect::Node,
61
62 reports_received_count: fuchsia_inspect::UintProperty,
64
65 reports_filtered_count: fuchsia_inspect::UintProperty,
68
69 events_generated: fuchsia_inspect::UintProperty,
72
73 last_received_timestamp_ns: fuchsia_inspect::UintProperty,
75
76 last_generated_timestamp_ns: fuchsia_inspect::UintProperty,
78
79 pub health_node: fuchsia_inspect::health::Node,
81
82 driver_to_binding_latency_ms: fuchsia_inspect::IntExponentialHistogramProperty,
87
88 wake_lease_leak_count: fuchsia_inspect::UintProperty,
90}
91
92impl InputDeviceStatus {
93 pub fn new(device_node: fuchsia_inspect::Node) -> Self {
94 Self::new_internal(device_node, Box::new(zx::MonotonicInstant::get))
95 }
96
97 fn new_internal(
98 device_node: fuchsia_inspect::Node,
99 now: Box<dyn Fn() -> zx::MonotonicInstant>,
100 ) -> Self {
101 let mut health_node = fuchsia_inspect::health::Node::new(&device_node);
102 health_node.set_starting_up();
103
104 let reports_received_count = device_node.create_uint("reports_received_count", 0);
105 let reports_filtered_count = device_node.create_uint("reports_filtered_count", 0);
106 let events_generated = device_node.create_uint("events_generated", 0);
107 let last_received_timestamp_ns = device_node.create_uint("last_received_timestamp_ns", 0);
108 let last_generated_timestamp_ns = device_node.create_uint("last_generated_timestamp_ns", 0);
109 let driver_to_binding_latency_ms = device_node.create_int_exponential_histogram(
110 "driver_to_binding_latency_ms",
111 LATENCY_HISTOGRAM_PROPERTIES,
112 );
113 let wake_lease_leak_count = device_node.create_uint("wake_lease_leak_count", 0);
114
115 Self {
116 now,
117 _node: device_node,
118 reports_received_count,
119 reports_filtered_count,
120 events_generated,
121 last_received_timestamp_ns,
122 last_generated_timestamp_ns,
123 health_node,
124 driver_to_binding_latency_ms,
125 wake_lease_leak_count,
126 }
127 }
128
129 pub fn count_received_report_wire(
130 &self,
131 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
132 ) {
133 self.reports_received_count.add(1);
134 match report.event_time() {
135 Some(event_time) => {
136 self.driver_to_binding_latency_ms.insert(
137 ((self.now)() - zx::MonotonicInstant::from_nanos(event_time.0)).into_millis(),
138 );
139 self.last_received_timestamp_ns.set(event_time.0.try_into().unwrap());
140 }
141 None => (),
142 }
143 }
144
145 pub fn count_filtered_report(&self) {
146 self.reports_filtered_count.add(1);
147 }
148
149 pub fn count_generated_event(&self, event: InputEvent) {
150 self.events_generated.add(1);
151 self.last_generated_timestamp_ns.set(event.event_time.into_nanos().try_into().unwrap());
152 }
153
154 pub fn count_generated_events(&self, events: &Vec<InputEvent>) {
155 self.events_generated.add(events.len() as u64);
156 if let Some(last_event) = events.last() {
157 self.last_generated_timestamp_ns
158 .set(last_event.event_time.into_nanos().try_into().unwrap());
159 }
160 }
161
162 pub fn count_wake_lease_leak(&self) {
163 self.wake_lease_leak_count.add(1);
164 }
165}
166
167#[derive(Clone, Debug, PartialEq)]
169pub struct InputEvent {
170 pub device_event: InputDeviceEvent,
172
173 pub device_descriptor: InputDeviceDescriptor,
176
177 pub event_time: zx::MonotonicInstant,
179
180 pub handled: Handled,
182
183 pub trace_id: Option<ftrace::Id>,
184}
185
186#[derive(Clone, Debug, PartialEq)]
192pub struct UnhandledInputEvent {
193 pub device_event: InputDeviceEvent,
195
196 pub device_descriptor: InputDeviceDescriptor,
199
200 pub event_time: zx::MonotonicInstant,
202
203 pub trace_id: Option<ftrace::Id>,
204}
205
206impl UnhandledInputEvent {
207 pub fn get_event_type(&self) -> &'static str {
209 match self.device_event {
210 InputDeviceEvent::Keyboard(_) => "keyboard_event",
211 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
212 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
213 InputDeviceEvent::Mouse(_) => "mouse_event",
214 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
215 InputDeviceEvent::Touchpad(_) => "touchpad_event",
216 #[cfg(test)]
217 InputDeviceEvent::Fake => "fake_event",
218 }
219 }
220}
221
222#[derive(Clone, Debug, PartialEq)]
231pub enum InputDeviceEvent {
232 Keyboard(keyboard_binding::KeyboardEvent),
233 LightSensor(light_sensor_binding::LightSensorEvent),
234 ConsumerControls(consumer_controls_binding::ConsumerControlsEvent),
235 Mouse(mouse_binding::MouseEvent),
236 TouchScreen(touch_binding::TouchScreenEvent),
237 Touchpad(touch_binding::TouchpadEvent),
238 #[cfg(test)]
239 Fake,
240}
241
242#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, EnumCount, Display)]
244#[strum(serialize_all = "snake_case")]
245pub enum InputEventType {
246 Keyboard = 0,
247 LightSensor = 1,
248 ConsumerControls = 2,
249 Mouse = 3,
250 TouchScreen = 4,
251 Touchpad = 5,
252 #[cfg(test)]
253 Fake = 6,
254}
255
256impl From<&InputDeviceEvent> for InputEventType {
257 fn from(event: &InputDeviceEvent) -> Self {
258 match event {
259 InputDeviceEvent::Keyboard(_) => InputEventType::Keyboard,
260 InputDeviceEvent::LightSensor(_) => InputEventType::LightSensor,
261 InputDeviceEvent::ConsumerControls(_) => InputEventType::ConsumerControls,
262 InputDeviceEvent::Mouse(_) => InputEventType::Mouse,
263 InputDeviceEvent::TouchScreen(_) => InputEventType::TouchScreen,
264 InputDeviceEvent::Touchpad(_) => InputEventType::Touchpad,
265 #[cfg(test)]
266 InputDeviceEvent::Fake => InputEventType::Fake,
267 }
268 }
269}
270
271#[derive(Clone, Debug, PartialEq)]
281pub enum InputDeviceDescriptor {
282 Keyboard(keyboard_binding::KeyboardDeviceDescriptor),
283 LightSensor(light_sensor_binding::LightSensorDeviceDescriptor),
284 ConsumerControls(consumer_controls_binding::ConsumerControlsDeviceDescriptor),
285 Mouse(mouse_binding::MouseDeviceDescriptor),
286 TouchScreen(touch_binding::TouchScreenDeviceDescriptor),
287 Touchpad(touch_binding::TouchpadDeviceDescriptor),
288 #[cfg(test)]
289 Fake,
290}
291
292impl From<keyboard_binding::KeyboardDeviceDescriptor> for InputDeviceDescriptor {
293 fn from(b: keyboard_binding::KeyboardDeviceDescriptor) -> Self {
294 InputDeviceDescriptor::Keyboard(b)
295 }
296}
297
298impl InputDeviceDescriptor {
299 pub fn device_id(&self) -> u32 {
300 match self {
301 InputDeviceDescriptor::Keyboard(b) => b.device_id,
302 InputDeviceDescriptor::LightSensor(b) => b.device_id,
303 InputDeviceDescriptor::ConsumerControls(b) => b.device_id,
304 InputDeviceDescriptor::Mouse(b) => b.device_id,
305 InputDeviceDescriptor::TouchScreen(b) => b.device_id,
306 InputDeviceDescriptor::Touchpad(b) => b.device_id,
307 #[cfg(test)]
308 InputDeviceDescriptor::Fake => 0,
309 }
310 }
311}
312
313#[derive(Copy, Clone, Debug, PartialEq)]
315pub enum Handled {
316 Yes,
318 No,
320}
321
322#[async_trait]
331pub trait InputDeviceBinding: Send {
332 fn get_device_descriptor(&self) -> InputDeviceDescriptor;
334
335 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>>;
337}
338
339pub fn initialize_report_stream<InputDeviceProcessReportsFn>(
356 device_proxy: fidl_next::Client<InputDevice, Transport>,
357 device_descriptor: InputDeviceDescriptor,
358 mut event_sender: UnboundedSender<Vec<InputEvent>>,
359 inspect_status: InputDeviceStatus,
360 metrics_logger: metrics::MetricsLogger,
361 feature_flags: InputPipelineFeatureFlags,
362 mut process_reports: InputDeviceProcessReportsFn,
363) where
364 InputDeviceProcessReportsFn: 'static
365 + Send
366 + for<'de> FnMut(
367 &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
368 Option<InputReport>,
369 &InputDeviceDescriptor,
370 &mut UnboundedSender<Vec<InputEvent>>,
371 &InputDeviceStatus,
372 &metrics::MetricsLogger,
373 &InputPipelineFeatureFlags,
374 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>),
375{
376 Dispatcher::spawn_local(async move {
377 let mut previous_report: Option<InputReport> = None;
378 let (report_reader, server_end) = fidl_next::fuchsia::create_channel();
379 let report_reader = Dispatcher::client_from_zx_channel(report_reader);
380 let result = device_proxy.get_input_reports_reader(server_end).await;
381 if result.is_err() {
382 metrics_logger.log_error(
383 InputPipelineErrorMetricDimensionEvent::InputDeviceGetInputReportsReaderError,
384 std::format!("error on GetInputReportsReader: {:?}", result),
385 );
386 return; }
388 let report_reader = report_reader.spawn();
389 loop {
390 let read_result = {
391 fuchsia_trace::duration!("input", "read_input_reports");
392 report_reader.read_input_reports().wire().await
393 };
394 match read_result {
395 Err(_fidl_error) => break,
396 Ok(decoded) => match decoded.as_ref() {
397 Err(_service_error) => break,
398 Ok(response) => {
399 fuchsia_trace::duration!("input", "input-device-process-reports");
400 let (prev_report, inspect_receiver) = process_reports(
403 response.reports.as_slice(),
404 previous_report,
405 &device_descriptor,
406 &mut event_sender,
407 &inspect_status,
408 &metrics_logger,
409 &feature_flags,
410 );
411 previous_report = prev_report;
412
413 if let Some(previous_report) = previous_report.as_ref() {
414 if previous_report.wake_lease.is_some() {
415 inspect_status.count_wake_lease_leak();
416
417 let error_code = match device_descriptor {
418 InputDeviceDescriptor::TouchScreen(_) => {
419 Some(InputPipelineMetricDimensionEvent::TouchscreenPreviousReportHasWakeLease)
420 }
421 InputDeviceDescriptor::Touchpad(_) => {
422 Some(InputPipelineMetricDimensionEvent::TouchpadPreviousReportHasWakeLease)
423 }
424 InputDeviceDescriptor::Mouse(_) => {
425 Some(InputPipelineMetricDimensionEvent::MousePreviousReportHasWakeLease)
426 }
427 InputDeviceDescriptor::Keyboard(_) => {
428 Some(InputPipelineMetricDimensionEvent::KeyboardPreviousReportHasWakeLease)
429 }
430 InputDeviceDescriptor::ConsumerControls(_) => {
431 Some(InputPipelineMetricDimensionEvent::ButtonPreviousReportHasWakeLease)
432 }
433 InputDeviceDescriptor::LightSensor(_) => {
434 Some(InputPipelineMetricDimensionEvent::LightSensorPreviousReportHasWakeLease)
435 }
436 #[cfg(test)]
437 InputDeviceDescriptor::Fake => None,
438 };
439 if let Some(error_code) = error_code {
440 metrics_logger.log_error(error_code, std::format!("previous_report must not have a wake lease but does: {:?}", previous_report));
441 }
442 }
443 }
444
445 match inspect_receiver {
449 Some(mut receiver) => {
450 while let Some(event) = receiver.next().await {
451 inspect_status.count_generated_event(event);
452 }
453 }
454 None => (),
455 };
456 }
457 }
458 }
459 }
460 log::warn!("initialize_report_stream exited - device binding no longer works");
463 })
464 .detach();
465}
466
467pub async fn is_device_type(
473 device_descriptor: &fidl_next_fuchsia_input_report::DeviceDescriptor,
474 device_type: InputDeviceType,
475) -> bool {
476 match device_type {
478 InputDeviceType::ConsumerControls => device_descriptor.consumer_control.is_some(),
479 InputDeviceType::Mouse => device_descriptor.mouse.is_some(),
480 InputDeviceType::Touch => device_descriptor.touch.is_some(),
481 InputDeviceType::Keyboard => device_descriptor.keyboard.is_some(),
482 InputDeviceType::LightSensor => device_descriptor.sensor.is_some(),
483 }
484}
485
486pub async fn get_device_binding(
494 device_type: InputDeviceType,
495 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
496 device_id: u32,
497 input_event_sender: UnboundedSender<Vec<InputEvent>>,
498 device_node: fuchsia_inspect::Node,
499 feature_flags: InputPipelineFeatureFlags,
500 metrics_logger: metrics::MetricsLogger,
501) -> Result<Box<dyn InputDeviceBinding>, Error> {
502 match device_type {
503 InputDeviceType::ConsumerControls => {
504 let binding = consumer_controls_binding::ConsumerControlsBinding::new(
505 device_proxy,
506 device_id,
507 input_event_sender,
508 device_node,
509 feature_flags.clone(),
510 metrics_logger,
511 )
512 .await?;
513 Ok(Box::new(binding))
514 }
515 InputDeviceType::Mouse => {
516 let binding = mouse_binding::MouseBinding::new(
517 device_proxy,
518 device_id,
519 input_event_sender,
520 device_node,
521 feature_flags.clone(),
522 metrics_logger,
523 )
524 .await?;
525 Ok(Box::new(binding))
526 }
527 InputDeviceType::Touch => {
528 let binding = touch_binding::TouchBinding::new(
529 device_proxy,
530 device_id,
531 input_event_sender,
532 device_node,
533 feature_flags.clone(),
534 metrics_logger,
535 )
536 .await?;
537 Ok(Box::new(binding))
538 }
539 InputDeviceType::Keyboard => {
540 let binding = keyboard_binding::KeyboardBinding::new(
541 device_proxy,
542 device_id,
543 input_event_sender,
544 device_node,
545 feature_flags.clone(),
546 metrics_logger,
547 )
548 .await?;
549 Ok(Box::new(binding))
550 }
551 InputDeviceType::LightSensor => {
552 let binding = light_sensor_binding::LightSensorBinding::new(
553 device_proxy,
554 device_id,
555 input_event_sender,
556 device_node,
557 feature_flags.clone(),
558 metrics_logger,
559 )
560 .await?;
561 Ok(Box::new(binding))
562 }
563 }
564}
565
566pub fn get_device_from_dir_entry_path(
575 dir_proxy: &fio::DirectoryProxy,
576 entry_path: &PathBuf,
577) -> Result<fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>, Error> {
578 let input_device_path = entry_path.to_str();
579 if input_device_path.is_none() {
580 return Err(format_err!("Failed to get entry path as a string."));
581 }
582
583 let input_device = Incoming::connect_protocol_next_at(dir_proxy, input_device_path.unwrap())
584 .expect("Failed to connect to InputDevice.");
585 Ok(input_device.spawn())
586}
587
588pub fn event_time_or_now(event_time: Option<i64>) -> zx::MonotonicInstant {
593 match event_time {
594 Some(time) => zx::MonotonicInstant::from_nanos(time),
595 None => zx::MonotonicInstant::get(),
596 }
597}
598
599impl std::convert::From<UnhandledInputEvent> for InputEvent {
600 fn from(event: UnhandledInputEvent) -> Self {
601 Self {
602 device_event: event.device_event,
603 device_descriptor: event.device_descriptor,
604 event_time: event.event_time,
605 handled: Handled::No,
606 trace_id: event.trace_id,
607 }
608 }
609}
610
611#[cfg(test)]
618impl std::convert::TryFrom<InputEvent> for UnhandledInputEvent {
619 type Error = anyhow::Error;
620 fn try_from(event: InputEvent) -> Result<UnhandledInputEvent, Self::Error> {
621 match event.handled {
622 Handled::Yes => {
623 Err(format_err!("Attempted to treat a handled InputEvent as unhandled"))
624 }
625 Handled::No => Ok(UnhandledInputEvent {
626 device_event: event.device_event,
627 device_descriptor: event.device_descriptor,
628 event_time: event.event_time,
629 trace_id: event.trace_id,
630 }),
631 }
632 }
633}
634
635impl InputEvent {
636 pub fn clone_with_wake_lease(&self) -> Self {
637 let device_event = match &self.device_event {
638 InputDeviceEvent::ConsumerControls(event) => {
639 InputDeviceEvent::ConsumerControls(event.clone_with_wake_lease())
640 }
641 InputDeviceEvent::Mouse(event) => {
642 InputDeviceEvent::Mouse(event.clone_with_wake_lease())
643 }
644 InputDeviceEvent::TouchScreen(event) => {
645 InputDeviceEvent::TouchScreen(event.clone_with_wake_lease())
646 }
647 _ => self.device_event.clone(),
648 };
649 Self {
650 device_event,
651 device_descriptor: self.device_descriptor.clone(),
652 event_time: self.event_time,
653 handled: self.handled,
654 trace_id: self.trace_id,
655 }
656 }
657
658 pub(crate) fn into_handled_if(self, predicate: bool) -> Self {
661 if predicate { Self { handled: Handled::Yes, ..self } } else { self }
662 }
663
664 pub(crate) fn into_handled(self) -> Self {
666 Self { handled: Handled::Yes, ..self }
667 }
668
669 pub fn into_with_event_time(self, event_time: zx::MonotonicInstant) -> Self {
671 Self { event_time, ..self }
672 }
673
674 #[cfg(test)]
676 pub fn into_with_device_descriptor(self, device_descriptor: InputDeviceDescriptor) -> Self {
677 Self { device_descriptor, ..self }
678 }
679
680 pub fn is_handled(&self) -> bool {
682 self.handled == Handled::Yes
683 }
684
685 pub fn get_event_type(&self) -> &'static str {
687 match self.device_event {
688 InputDeviceEvent::Keyboard(_) => "keyboard_event",
689 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
690 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
691 InputDeviceEvent::Mouse(_) => "mouse_event",
692 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
693 InputDeviceEvent::Touchpad(_) => "touchpad_event",
694 #[cfg(test)]
695 InputDeviceEvent::Fake => "fake_event",
696 }
697 }
698
699 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
700 node.record_int("event_time", self.event_time.into_nanos());
701 match &self.device_event {
702 InputDeviceEvent::LightSensor(e) => e.record_inspect(node),
703 InputDeviceEvent::ConsumerControls(e) => e.record_inspect(node),
704 InputDeviceEvent::Mouse(e) => e.record_inspect(node),
705 InputDeviceEvent::TouchScreen(e) => e.record_inspect(node),
706 InputDeviceEvent::Touchpad(e) => e.record_inspect(node),
707 InputDeviceEvent::Keyboard(_) => (),
709 #[cfg(test)] InputDeviceEvent::Fake => (),
711 }
712 }
713}
714
715#[cfg(test)]
716mod tests {
717 use super::*;
718 use crate::testing_utilities::spawn_input_stream_handler;
719 use assert_matches::assert_matches;
720 use diagnostics_assertions::AnyProperty;
721 use fidl_fuchsia_input_report as fidl_input_report;
722 use fuchsia_async as fasync;
723 use pretty_assertions::assert_eq;
724 use std::convert::TryFrom as _;
725 use test_case::test_case;
726
727 #[test]
728 fn max_event_time() {
729 let event_time = event_time_or_now(Some(i64::MAX));
730 assert_eq!(event_time, zx::MonotonicInstant::INFINITE);
731 }
732
733 #[test]
734 fn min_event_time() {
735 let event_time = event_time_or_now(Some(std::i64::MIN));
736 assert_eq!(event_time, zx::MonotonicInstant::INFINITE_PAST);
737 }
738
739 #[fasync::run_singlethreaded(test)]
740 async fn input_device_status_initialized_with_correct_properties() {
741 let inspector = fuchsia_inspect::Inspector::default();
742 let input_pipeline_node = inspector.root().create_child("input_pipeline");
743 let input_devices_node = input_pipeline_node.create_child("input_devices");
744 let device_node = input_devices_node.create_child("001_keyboard");
745 let _input_device_status = InputDeviceStatus::new(device_node);
746 diagnostics_assertions::assert_data_tree!(inspector, root: {
747 input_pipeline: {
748 input_devices: {
749 "001_keyboard": {
750 reports_received_count: 0u64,
751 reports_filtered_count: 0u64,
752 events_generated: 0u64,
753 last_received_timestamp_ns: 0u64,
754 last_generated_timestamp_ns: 0u64,
755 "fuchsia.inspect.Health": {
756 status: "STARTING_UP",
757 start_timestamp_nanos: AnyProperty
760 },
761 driver_to_binding_latency_ms: diagnostics_assertions::HistogramAssertion::exponential(super::LATENCY_HISTOGRAM_PROPERTIES),
762 wake_lease_leak_count: 0u64,
763 }
764 }
765 }
766 });
767 }
768
769 #[test_case(i64::MIN; "min value")]
770 #[test_case(-1; "negative value")]
771 #[test_case(0; "zero")]
772 #[test_case(1; "positive value")]
773 #[test_case(i64::MAX; "max value")]
774 #[fuchsia::test(allow_stalls = false)]
775 async fn input_device_status_updates_latency_histogram_on_count_received_report_wire(
776 latency_nsec: i64,
777 ) {
778 let mut expected_histogram = diagnostics_assertions::HistogramAssertion::exponential(
779 super::LATENCY_HISTOGRAM_PROPERTIES,
780 );
781 let inspector = fuchsia_inspect::Inspector::default();
782 let input_device_status = InputDeviceStatus::new_internal(
783 inspector.root().clone_weak(),
784 Box::new(move || zx::MonotonicInstant::from_nanos(latency_nsec)),
785 );
786 let decoded = crate::testing_utilities::report_to_wire(InputReport {
787 event_time: Some(0),
788 ..InputReport::default()
789 });
790 input_device_status.count_received_report_wire(&decoded);
791 expected_histogram.insert_values([latency_nsec / 1000 / 1000]);
792 diagnostics_assertions::assert_data_tree!(inspector, root: contains {
793 driver_to_binding_latency_ms: expected_histogram,
794 });
795 }
796
797 #[fasync::run_singlethreaded(test)]
800 async fn consumer_controls_input_device_exists() {
801 let input_device_proxy =
802 spawn_input_stream_handler(move |input_device_request| async move {
803 match input_device_request {
804 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
805 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
806 device_information: None,
807 mouse: None,
808 sensor: None,
809 touch: None,
810 keyboard: None,
811 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
812 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
813 buttons: Some(vec![
814 fidl_input_report::ConsumerControlButton::VolumeUp,
815 fidl_input_report::ConsumerControlButton::VolumeDown,
816 ]),
817 ..Default::default()
818 }),
819 ..Default::default()
820 }),
821 ..Default::default()
822 });
823 }
824 _ => panic!("InputDevice handler received an unexpected request"),
825 }
826 });
827
828 assert!(
829 is_device_type(
830 &input_device_proxy
831 .get_descriptor()
832 .await
833 .expect("Failed to get device descriptor")
834 .descriptor,
835 InputDeviceType::ConsumerControls
836 )
837 .await
838 );
839 }
840
841 #[fasync::run_singlethreaded(test)]
843 async fn mouse_input_device_exists() {
844 let input_device_proxy =
845 spawn_input_stream_handler(move |input_device_request| async move {
846 match input_device_request {
847 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
848 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
849 device_information: None,
850 mouse: Some(fidl_input_report::MouseDescriptor {
851 input: Some(fidl_input_report::MouseInputDescriptor {
852 movement_x: None,
853 movement_y: None,
854 position_x: None,
855 position_y: None,
856 scroll_v: None,
857 scroll_h: None,
858 buttons: None,
859 ..Default::default()
860 }),
861 ..Default::default()
862 }),
863 sensor: None,
864 touch: None,
865 keyboard: None,
866 consumer_control: None,
867 ..Default::default()
868 });
869 }
870 _ => panic!("InputDevice handler received an unexpected request"),
871 }
872 });
873
874 assert!(
875 is_device_type(
876 &input_device_proxy
877 .get_descriptor()
878 .await
879 .expect("Failed to get device descriptor")
880 .descriptor,
881 InputDeviceType::Mouse
882 )
883 .await
884 );
885 }
886
887 #[fasync::run_singlethreaded(test)]
890 async fn mouse_input_device_doesnt_exist() {
891 let input_device_proxy =
892 spawn_input_stream_handler(move |input_device_request| async move {
893 match input_device_request {
894 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
895 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
896 device_information: None,
897 mouse: None,
898 sensor: None,
899 touch: None,
900 keyboard: None,
901 consumer_control: None,
902 ..Default::default()
903 });
904 }
905 _ => panic!("InputDevice handler received an unexpected request"),
906 }
907 });
908
909 assert!(
910 !is_device_type(
911 &input_device_proxy
912 .get_descriptor()
913 .await
914 .expect("Failed to get device descriptor")
915 .descriptor,
916 InputDeviceType::Mouse
917 )
918 .await
919 );
920 }
921
922 #[fasync::run_singlethreaded(test)]
925 async fn touch_input_device_exists() {
926 let input_device_proxy =
927 spawn_input_stream_handler(move |input_device_request| async move {
928 match input_device_request {
929 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
930 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
931 device_information: None,
932 mouse: None,
933 sensor: None,
934 touch: Some(fidl_input_report::TouchDescriptor {
935 input: Some(fidl_input_report::TouchInputDescriptor {
936 contacts: None,
937 max_contacts: None,
938 touch_type: None,
939 buttons: None,
940 ..Default::default()
941 }),
942 ..Default::default()
943 }),
944 keyboard: None,
945 consumer_control: None,
946 ..Default::default()
947 });
948 }
949 _ => panic!("InputDevice handler received an unexpected request"),
950 }
951 });
952
953 assert!(
954 is_device_type(
955 &input_device_proxy
956 .get_descriptor()
957 .await
958 .expect("Failed to get device descriptor")
959 .descriptor,
960 InputDeviceType::Touch
961 )
962 .await
963 );
964 }
965
966 #[fasync::run_singlethreaded(test)]
969 async fn touch_input_device_doesnt_exist() {
970 let input_device_proxy =
971 spawn_input_stream_handler(move |input_device_request| async move {
972 match input_device_request {
973 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
974 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
975 device_information: None,
976 mouse: None,
977 sensor: None,
978 touch: None,
979 keyboard: None,
980 consumer_control: None,
981 ..Default::default()
982 });
983 }
984 _ => panic!("InputDevice handler received an unexpected request"),
985 }
986 });
987
988 assert!(
989 !is_device_type(
990 &input_device_proxy
991 .get_descriptor()
992 .await
993 .expect("Failed to get device descriptor")
994 .descriptor,
995 InputDeviceType::Touch
996 )
997 .await
998 );
999 }
1000
1001 #[fasync::run_singlethreaded(test)]
1004 async fn keyboard_input_device_exists() {
1005 let input_device_proxy =
1006 spawn_input_stream_handler(move |input_device_request| async move {
1007 match input_device_request {
1008 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1009 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1010 device_information: None,
1011 mouse: None,
1012 sensor: None,
1013 touch: None,
1014 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1015 input: Some(fidl_input_report::KeyboardInputDescriptor {
1016 keys3: None,
1017 ..Default::default()
1018 }),
1019 output: None,
1020 ..Default::default()
1021 }),
1022 consumer_control: None,
1023 ..Default::default()
1024 });
1025 }
1026 _ => panic!("InputDevice handler received an unexpected request"),
1027 }
1028 });
1029
1030 assert!(
1031 is_device_type(
1032 &input_device_proxy
1033 .get_descriptor()
1034 .await
1035 .expect("Failed to get device descriptor")
1036 .descriptor,
1037 InputDeviceType::Keyboard
1038 )
1039 .await
1040 );
1041 }
1042
1043 #[fasync::run_singlethreaded(test)]
1046 async fn keyboard_input_device_doesnt_exist() {
1047 let input_device_proxy =
1048 spawn_input_stream_handler(move |input_device_request| async move {
1049 match input_device_request {
1050 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1051 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1052 device_information: None,
1053 mouse: None,
1054 sensor: None,
1055 touch: None,
1056 keyboard: None,
1057 consumer_control: None,
1058 ..Default::default()
1059 });
1060 }
1061 _ => panic!("InputDevice handler received an unexpected request"),
1062 }
1063 });
1064
1065 assert!(
1066 !is_device_type(
1067 &input_device_proxy
1068 .get_descriptor()
1069 .await
1070 .expect("Failed to get device descriptor")
1071 .descriptor,
1072 InputDeviceType::Keyboard
1073 )
1074 .await
1075 );
1076 }
1077
1078 #[fasync::run_singlethreaded(test)]
1080 async fn no_input_device_match() {
1081 let input_device_proxy =
1082 spawn_input_stream_handler(move |input_device_request| async move {
1083 match input_device_request {
1084 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1085 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1086 device_information: None,
1087 mouse: Some(fidl_input_report::MouseDescriptor {
1088 input: Some(fidl_input_report::MouseInputDescriptor {
1089 movement_x: None,
1090 movement_y: None,
1091 position_x: None,
1092 position_y: None,
1093 scroll_v: None,
1094 scroll_h: None,
1095 buttons: None,
1096 ..Default::default()
1097 }),
1098 ..Default::default()
1099 }),
1100 sensor: None,
1101 touch: Some(fidl_input_report::TouchDescriptor {
1102 input: Some(fidl_input_report::TouchInputDescriptor {
1103 contacts: None,
1104 max_contacts: None,
1105 touch_type: None,
1106 buttons: None,
1107 ..Default::default()
1108 }),
1109 ..Default::default()
1110 }),
1111 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1112 input: Some(fidl_input_report::KeyboardInputDescriptor {
1113 keys3: None,
1114 ..Default::default()
1115 }),
1116 output: None,
1117 ..Default::default()
1118 }),
1119 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
1120 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
1121 buttons: Some(vec![
1122 fidl_input_report::ConsumerControlButton::VolumeUp,
1123 fidl_input_report::ConsumerControlButton::VolumeDown,
1124 ]),
1125 ..Default::default()
1126 }),
1127 ..Default::default()
1128 }),
1129 ..Default::default()
1130 });
1131 }
1132 _ => panic!("InputDevice handler received an unexpected request"),
1133 }
1134 });
1135
1136 let device_descriptor = &input_device_proxy
1137 .get_descriptor()
1138 .await
1139 .expect("Failed to get device descriptor")
1140 .descriptor;
1141 assert!(is_device_type(&device_descriptor, InputDeviceType::ConsumerControls).await);
1142 assert!(is_device_type(&device_descriptor, InputDeviceType::Mouse).await);
1143 assert!(is_device_type(&device_descriptor, InputDeviceType::Touch).await);
1144 assert!(is_device_type(&device_descriptor, InputDeviceType::Keyboard).await);
1145 }
1146
1147 #[fuchsia::test]
1148 fn unhandled_to_generic_conversion_sets_handled_flag_to_no() {
1149 assert_eq!(
1150 InputEvent::from(UnhandledInputEvent {
1151 device_event: InputDeviceEvent::Fake,
1152 device_descriptor: InputDeviceDescriptor::Fake,
1153 event_time: zx::MonotonicInstant::from_nanos(1),
1154 trace_id: None,
1155 })
1156 .handled,
1157 Handled::No
1158 );
1159 }
1160
1161 #[fuchsia::test]
1162 fn unhandled_to_generic_conversion_preserves_fields() {
1163 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1164 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1165 assert_eq!(
1166 InputEvent::from(UnhandledInputEvent {
1167 device_event: InputDeviceEvent::Fake,
1168 device_descriptor: InputDeviceDescriptor::Fake,
1169 event_time: EVENT_TIME,
1170 trace_id: expected_trace_id,
1171 }),
1172 InputEvent {
1173 device_event: InputDeviceEvent::Fake,
1174 device_descriptor: InputDeviceDescriptor::Fake,
1175 event_time: EVENT_TIME,
1176 handled: Handled::No,
1177 trace_id: expected_trace_id,
1178 },
1179 );
1180 }
1181
1182 #[fuchsia::test]
1183 fn generic_to_unhandled_conversion_fails_for_handled_events() {
1184 assert_matches!(
1185 UnhandledInputEvent::try_from(InputEvent {
1186 device_event: InputDeviceEvent::Fake,
1187 device_descriptor: InputDeviceDescriptor::Fake,
1188 event_time: zx::MonotonicInstant::from_nanos(1),
1189 handled: Handled::Yes,
1190 trace_id: None,
1191 }),
1192 Err(_)
1193 )
1194 }
1195
1196 #[fuchsia::test]
1197 fn generic_to_unhandled_conversion_preserves_fields_for_unhandled_events() {
1198 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1199 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1200 assert_eq!(
1201 UnhandledInputEvent::try_from(InputEvent {
1202 device_event: InputDeviceEvent::Fake,
1203 device_descriptor: InputDeviceDescriptor::Fake,
1204 event_time: EVENT_TIME,
1205 handled: Handled::No,
1206 trace_id: expected_trace_id,
1207 })
1208 .unwrap(),
1209 UnhandledInputEvent {
1210 device_event: InputDeviceEvent::Fake,
1211 device_descriptor: InputDeviceDescriptor::Fake,
1212 event_time: EVENT_TIME,
1213 trace_id: expected_trace_id,
1214 },
1215 )
1216 }
1217
1218 #[test_case(Handled::No; "initially not handled")]
1219 #[test_case(Handled::Yes; "initially handled")]
1220 fn into_handled_if_yields_handled_yes_on_true(initially_handled: Handled) {
1221 let event = InputEvent {
1222 device_event: InputDeviceEvent::Fake,
1223 device_descriptor: InputDeviceDescriptor::Fake,
1224 event_time: zx::MonotonicInstant::from_nanos(1),
1225 handled: initially_handled,
1226 trace_id: None,
1227 };
1228 pretty_assertions::assert_eq!(event.into_handled_if(true).handled, Handled::Yes);
1229 }
1230
1231 #[test_case(Handled::No; "initially not handled")]
1232 #[test_case(Handled::Yes; "initially handled")]
1233 fn into_handled_if_leaves_handled_unchanged_on_false(initially_handled: Handled) {
1234 let event = InputEvent {
1235 device_event: InputDeviceEvent::Fake,
1236 device_descriptor: InputDeviceDescriptor::Fake,
1237 event_time: zx::MonotonicInstant::from_nanos(1),
1238 handled: initially_handled.clone(),
1239 trace_id: None,
1240 };
1241 pretty_assertions::assert_eq!(event.into_handled_if(false).handled, initially_handled);
1242 }
1243
1244 #[test_case(Handled::No; "initially not handled")]
1245 #[test_case(Handled::Yes; "initially handled")]
1246 fn into_handled_yields_handled_yes(initially_handled: Handled) {
1247 let event = InputEvent {
1248 device_event: InputDeviceEvent::Fake,
1249 device_descriptor: InputDeviceDescriptor::Fake,
1250 event_time: zx::MonotonicInstant::from_nanos(1),
1251 handled: initially_handled,
1252 trace_id: None,
1253 };
1254 pretty_assertions::assert_eq!(event.into_handled().handled, Handled::Yes);
1255 }
1256}