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