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 let read_result = {
389 fuchsia_trace::duration!("input", "read_input_reports");
390 report_reader.read_input_reports().await
391 };
392 match read_result {
393 Ok(Err(_service_error)) => break,
394 Err(_fidl_error) => break,
395 Ok(Ok(fidl_next_input_report::InputReportsReaderReadInputReportsResponse {
396 reports,
397 })) => {
398 fuchsia_trace::duration!("input", "input-device-process-reports");
399 let (prev_report, inspect_receiver) = process_reports(
400 reports,
401 previous_report,
402 &device_descriptor,
403 &mut event_sender,
404 &inspect_status,
405 &metrics_logger,
406 &feature_flags,
407 );
408 previous_report = prev_report;
409
410 if let Some(previous_report) = previous_report.as_ref() {
411 if previous_report.wake_lease.is_some() {
412 inspect_status.count_wake_lease_leak();
413
414 let error_code = match device_descriptor {
415 InputDeviceDescriptor::TouchScreen(_) => {
416 Some(InputPipelineMetricDimensionEvent::TouchscreenPreviousReportHasWakeLease)
417 }
418 InputDeviceDescriptor::Touchpad(_) => {
419 Some(InputPipelineMetricDimensionEvent::TouchpadPreviousReportHasWakeLease)
420 }
421 InputDeviceDescriptor::Mouse(_) => {
422 Some(InputPipelineMetricDimensionEvent::MousePreviousReportHasWakeLease)
423 }
424 InputDeviceDescriptor::Keyboard(_) => {
425 Some(InputPipelineMetricDimensionEvent::KeyboardPreviousReportHasWakeLease)
426 }
427 InputDeviceDescriptor::ConsumerControls(_) => {
428 Some(InputPipelineMetricDimensionEvent::ButtonPreviousReportHasWakeLease)
429 }
430 InputDeviceDescriptor::LightSensor(_) => {
431 Some(InputPipelineMetricDimensionEvent::LightSensorPreviousReportHasWakeLease)
432 }
433 #[cfg(test)]
434 InputDeviceDescriptor::Fake => None,
435 };
436 if let Some(error_code) = error_code {
437 metrics_logger.log_error(error_code, std::format!("previous_report must not have a wake lease but does: {:?}", previous_report));
438 }
439 }
440 }
441
442 match inspect_receiver {
446 Some(mut receiver) => {
447 while let Some(event) = receiver.next().await {
448 inspect_status.count_generated_event(event);
449 }
450 }
451 None => (),
452 };
453 }
454 }
455 }
456 log::warn!("initialize_report_stream exited - device binding no longer works");
459 })
460 .detach();
461}
462
463pub async fn is_device_type(
469 device_descriptor: &fidl_next_fuchsia_input_report::DeviceDescriptor,
470 device_type: InputDeviceType,
471) -> bool {
472 match device_type {
474 InputDeviceType::ConsumerControls => device_descriptor.consumer_control.is_some(),
475 InputDeviceType::Mouse => device_descriptor.mouse.is_some(),
476 InputDeviceType::Touch => device_descriptor.touch.is_some(),
477 InputDeviceType::Keyboard => device_descriptor.keyboard.is_some(),
478 InputDeviceType::LightSensor => device_descriptor.sensor.is_some(),
479 }
480}
481
482pub async fn get_device_binding(
490 device_type: InputDeviceType,
491 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
492 device_id: u32,
493 input_event_sender: UnboundedSender<Vec<InputEvent>>,
494 device_node: fuchsia_inspect::Node,
495 feature_flags: InputPipelineFeatureFlags,
496 metrics_logger: metrics::MetricsLogger,
497) -> Result<Box<dyn InputDeviceBinding>, Error> {
498 match device_type {
499 InputDeviceType::ConsumerControls => {
500 let binding = consumer_controls_binding::ConsumerControlsBinding::new(
501 device_proxy,
502 device_id,
503 input_event_sender,
504 device_node,
505 feature_flags.clone(),
506 metrics_logger,
507 )
508 .await?;
509 Ok(Box::new(binding))
510 }
511 InputDeviceType::Mouse => {
512 let binding = mouse_binding::MouseBinding::new(
513 device_proxy,
514 device_id,
515 input_event_sender,
516 device_node,
517 feature_flags.clone(),
518 metrics_logger,
519 )
520 .await?;
521 Ok(Box::new(binding))
522 }
523 InputDeviceType::Touch => {
524 let binding = touch_binding::TouchBinding::new(
525 device_proxy,
526 device_id,
527 input_event_sender,
528 device_node,
529 feature_flags.clone(),
530 metrics_logger,
531 )
532 .await?;
533 Ok(Box::new(binding))
534 }
535 InputDeviceType::Keyboard => {
536 let binding = keyboard_binding::KeyboardBinding::new(
537 device_proxy,
538 device_id,
539 input_event_sender,
540 device_node,
541 feature_flags.clone(),
542 metrics_logger,
543 )
544 .await?;
545 Ok(Box::new(binding))
546 }
547 InputDeviceType::LightSensor => {
548 let binding = light_sensor_binding::LightSensorBinding::new(
549 device_proxy,
550 device_id,
551 input_event_sender,
552 device_node,
553 feature_flags.clone(),
554 metrics_logger,
555 )
556 .await?;
557 Ok(Box::new(binding))
558 }
559 }
560}
561
562pub fn get_device_from_dir_entry_path(
571 dir_proxy: &fio::DirectoryProxy,
572 entry_path: &PathBuf,
573) -> Result<fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>, Error> {
574 let input_device_path = entry_path.to_str();
575 if input_device_path.is_none() {
576 return Err(format_err!("Failed to get entry path as a string."));
577 }
578
579 let input_device = Incoming::connect_protocol_next_at(dir_proxy, input_device_path.unwrap())
580 .expect("Failed to connect to InputDevice.");
581 Ok(input_device.spawn())
582}
583
584pub fn event_time_or_now(event_time: Option<i64>) -> zx::MonotonicInstant {
589 match event_time {
590 Some(time) => zx::MonotonicInstant::from_nanos(time),
591 None => zx::MonotonicInstant::get(),
592 }
593}
594
595impl std::convert::From<UnhandledInputEvent> for InputEvent {
596 fn from(event: UnhandledInputEvent) -> Self {
597 Self {
598 device_event: event.device_event,
599 device_descriptor: event.device_descriptor,
600 event_time: event.event_time,
601 handled: Handled::No,
602 trace_id: event.trace_id,
603 }
604 }
605}
606
607#[cfg(test)]
614impl std::convert::TryFrom<InputEvent> for UnhandledInputEvent {
615 type Error = anyhow::Error;
616 fn try_from(event: InputEvent) -> Result<UnhandledInputEvent, Self::Error> {
617 match event.handled {
618 Handled::Yes => {
619 Err(format_err!("Attempted to treat a handled InputEvent as unhandled"))
620 }
621 Handled::No => Ok(UnhandledInputEvent {
622 device_event: event.device_event,
623 device_descriptor: event.device_descriptor,
624 event_time: event.event_time,
625 trace_id: event.trace_id,
626 }),
627 }
628 }
629}
630
631impl InputEvent {
632 pub fn clone_with_wake_lease(&self) -> Self {
633 let device_event = match &self.device_event {
634 InputDeviceEvent::ConsumerControls(event) => {
635 InputDeviceEvent::ConsumerControls(event.clone_with_wake_lease())
636 }
637 InputDeviceEvent::Mouse(event) => {
638 InputDeviceEvent::Mouse(event.clone_with_wake_lease())
639 }
640 InputDeviceEvent::TouchScreen(event) => {
641 InputDeviceEvent::TouchScreen(event.clone_with_wake_lease())
642 }
643 _ => self.device_event.clone(),
644 };
645 Self {
646 device_event,
647 device_descriptor: self.device_descriptor.clone(),
648 event_time: self.event_time,
649 handled: self.handled,
650 trace_id: self.trace_id,
651 }
652 }
653
654 pub(crate) fn into_handled_if(self, predicate: bool) -> Self {
657 if predicate { Self { handled: Handled::Yes, ..self } } else { self }
658 }
659
660 pub(crate) fn into_handled(self) -> Self {
662 Self { handled: Handled::Yes, ..self }
663 }
664
665 pub fn into_with_event_time(self, event_time: zx::MonotonicInstant) -> Self {
667 Self { event_time, ..self }
668 }
669
670 #[cfg(test)]
672 pub fn into_with_device_descriptor(self, device_descriptor: InputDeviceDescriptor) -> Self {
673 Self { device_descriptor, ..self }
674 }
675
676 pub fn is_handled(&self) -> bool {
678 self.handled == Handled::Yes
679 }
680
681 pub fn get_event_type(&self) -> &'static str {
683 match self.device_event {
684 InputDeviceEvent::Keyboard(_) => "keyboard_event",
685 InputDeviceEvent::LightSensor(_) => "light_sensor_event",
686 InputDeviceEvent::ConsumerControls(_) => "consumer_controls_event",
687 InputDeviceEvent::Mouse(_) => "mouse_event",
688 InputDeviceEvent::TouchScreen(_) => "touch_screen_event",
689 InputDeviceEvent::Touchpad(_) => "touchpad_event",
690 #[cfg(test)]
691 InputDeviceEvent::Fake => "fake_event",
692 }
693 }
694
695 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
696 node.record_int("event_time", self.event_time.into_nanos());
697 match &self.device_event {
698 InputDeviceEvent::LightSensor(e) => e.record_inspect(node),
699 InputDeviceEvent::ConsumerControls(e) => e.record_inspect(node),
700 InputDeviceEvent::Mouse(e) => e.record_inspect(node),
701 InputDeviceEvent::TouchScreen(e) => e.record_inspect(node),
702 InputDeviceEvent::Touchpad(e) => e.record_inspect(node),
703 InputDeviceEvent::Keyboard(_) => (),
705 #[cfg(test)] InputDeviceEvent::Fake => (),
707 }
708 }
709}
710
711#[cfg(test)]
712mod tests {
713 use super::*;
714 use crate::testing_utilities::spawn_input_stream_handler;
715 use assert_matches::assert_matches;
716 use diagnostics_assertions::AnyProperty;
717 use fidl_fuchsia_input_report as fidl_input_report;
718 use fuchsia_async as fasync;
719 use pretty_assertions::assert_eq;
720 use std::convert::TryFrom as _;
721 use test_case::test_case;
722
723 #[test]
724 fn max_event_time() {
725 let event_time = event_time_or_now(Some(i64::MAX));
726 assert_eq!(event_time, zx::MonotonicInstant::INFINITE);
727 }
728
729 #[test]
730 fn min_event_time() {
731 let event_time = event_time_or_now(Some(std::i64::MIN));
732 assert_eq!(event_time, zx::MonotonicInstant::INFINITE_PAST);
733 }
734
735 #[fasync::run_singlethreaded(test)]
736 async fn input_device_status_initialized_with_correct_properties() {
737 let inspector = fuchsia_inspect::Inspector::default();
738 let input_pipeline_node = inspector.root().create_child("input_pipeline");
739 let input_devices_node = input_pipeline_node.create_child("input_devices");
740 let device_node = input_devices_node.create_child("001_keyboard");
741 let _input_device_status = InputDeviceStatus::new(device_node);
742 diagnostics_assertions::assert_data_tree!(inspector, root: {
743 input_pipeline: {
744 input_devices: {
745 "001_keyboard": {
746 reports_received_count: 0u64,
747 reports_filtered_count: 0u64,
748 events_generated: 0u64,
749 last_received_timestamp_ns: 0u64,
750 last_generated_timestamp_ns: 0u64,
751 "fuchsia.inspect.Health": {
752 status: "STARTING_UP",
753 start_timestamp_nanos: AnyProperty
756 },
757 driver_to_binding_latency_ms: diagnostics_assertions::HistogramAssertion::exponential(super::LATENCY_HISTOGRAM_PROPERTIES),
758 wake_lease_leak_count: 0u64,
759 }
760 }
761 }
762 });
763 }
764
765 #[test_case(i64::MIN; "min value")]
766 #[test_case(-1; "negative value")]
767 #[test_case(0; "zero")]
768 #[test_case(1; "positive value")]
769 #[test_case(i64::MAX; "max value")]
770 #[fuchsia::test(allow_stalls = false)]
771 async fn input_device_status_updates_latency_histogram_on_count_received_report(
772 latency_nsec: i64,
773 ) {
774 let mut expected_histogram = diagnostics_assertions::HistogramAssertion::exponential(
775 super::LATENCY_HISTOGRAM_PROPERTIES,
776 );
777 let inspector = fuchsia_inspect::Inspector::default();
778 let input_device_status = InputDeviceStatus::new_internal(
779 inspector.root().clone_weak(),
780 Box::new(move || zx::MonotonicInstant::from_nanos(latency_nsec)),
781 );
782 input_device_status
783 .count_received_report(&InputReport { event_time: Some(0), ..InputReport::default() });
784 expected_histogram.insert_values([latency_nsec / 1000 / 1000]);
785 diagnostics_assertions::assert_data_tree!(inspector, root: contains {
786 driver_to_binding_latency_ms: expected_histogram,
787 });
788 }
789
790 #[fasync::run_singlethreaded(test)]
793 async fn consumer_controls_input_device_exists() {
794 let input_device_proxy =
795 spawn_input_stream_handler(move |input_device_request| async move {
796 match input_device_request {
797 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
798 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
799 device_information: None,
800 mouse: None,
801 sensor: None,
802 touch: None,
803 keyboard: None,
804 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
805 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
806 buttons: Some(vec![
807 fidl_input_report::ConsumerControlButton::VolumeUp,
808 fidl_input_report::ConsumerControlButton::VolumeDown,
809 ]),
810 ..Default::default()
811 }),
812 ..Default::default()
813 }),
814 ..Default::default()
815 });
816 }
817 _ => panic!("InputDevice handler received an unexpected request"),
818 }
819 });
820
821 assert!(
822 is_device_type(
823 &input_device_proxy
824 .get_descriptor()
825 .await
826 .expect("Failed to get device descriptor")
827 .descriptor,
828 InputDeviceType::ConsumerControls
829 )
830 .await
831 );
832 }
833
834 #[fasync::run_singlethreaded(test)]
836 async fn mouse_input_device_exists() {
837 let input_device_proxy =
838 spawn_input_stream_handler(move |input_device_request| async move {
839 match input_device_request {
840 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
841 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
842 device_information: None,
843 mouse: Some(fidl_input_report::MouseDescriptor {
844 input: Some(fidl_input_report::MouseInputDescriptor {
845 movement_x: None,
846 movement_y: None,
847 position_x: None,
848 position_y: None,
849 scroll_v: None,
850 scroll_h: None,
851 buttons: None,
852 ..Default::default()
853 }),
854 ..Default::default()
855 }),
856 sensor: None,
857 touch: None,
858 keyboard: None,
859 consumer_control: None,
860 ..Default::default()
861 });
862 }
863 _ => panic!("InputDevice handler received an unexpected request"),
864 }
865 });
866
867 assert!(
868 is_device_type(
869 &input_device_proxy
870 .get_descriptor()
871 .await
872 .expect("Failed to get device descriptor")
873 .descriptor,
874 InputDeviceType::Mouse
875 )
876 .await
877 );
878 }
879
880 #[fasync::run_singlethreaded(test)]
883 async fn mouse_input_device_doesnt_exist() {
884 let input_device_proxy =
885 spawn_input_stream_handler(move |input_device_request| async move {
886 match input_device_request {
887 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
888 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
889 device_information: None,
890 mouse: None,
891 sensor: None,
892 touch: None,
893 keyboard: None,
894 consumer_control: None,
895 ..Default::default()
896 });
897 }
898 _ => panic!("InputDevice handler received an unexpected request"),
899 }
900 });
901
902 assert!(
903 !is_device_type(
904 &input_device_proxy
905 .get_descriptor()
906 .await
907 .expect("Failed to get device descriptor")
908 .descriptor,
909 InputDeviceType::Mouse
910 )
911 .await
912 );
913 }
914
915 #[fasync::run_singlethreaded(test)]
918 async fn touch_input_device_exists() {
919 let input_device_proxy =
920 spawn_input_stream_handler(move |input_device_request| async move {
921 match input_device_request {
922 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
923 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
924 device_information: None,
925 mouse: None,
926 sensor: None,
927 touch: Some(fidl_input_report::TouchDescriptor {
928 input: Some(fidl_input_report::TouchInputDescriptor {
929 contacts: None,
930 max_contacts: None,
931 touch_type: None,
932 buttons: None,
933 ..Default::default()
934 }),
935 ..Default::default()
936 }),
937 keyboard: None,
938 consumer_control: None,
939 ..Default::default()
940 });
941 }
942 _ => panic!("InputDevice handler received an unexpected request"),
943 }
944 });
945
946 assert!(
947 is_device_type(
948 &input_device_proxy
949 .get_descriptor()
950 .await
951 .expect("Failed to get device descriptor")
952 .descriptor,
953 InputDeviceType::Touch
954 )
955 .await
956 );
957 }
958
959 #[fasync::run_singlethreaded(test)]
962 async fn touch_input_device_doesnt_exist() {
963 let input_device_proxy =
964 spawn_input_stream_handler(move |input_device_request| async move {
965 match input_device_request {
966 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
967 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
968 device_information: None,
969 mouse: None,
970 sensor: None,
971 touch: None,
972 keyboard: None,
973 consumer_control: None,
974 ..Default::default()
975 });
976 }
977 _ => panic!("InputDevice handler received an unexpected request"),
978 }
979 });
980
981 assert!(
982 !is_device_type(
983 &input_device_proxy
984 .get_descriptor()
985 .await
986 .expect("Failed to get device descriptor")
987 .descriptor,
988 InputDeviceType::Touch
989 )
990 .await
991 );
992 }
993
994 #[fasync::run_singlethreaded(test)]
997 async fn keyboard_input_device_exists() {
998 let input_device_proxy =
999 spawn_input_stream_handler(move |input_device_request| async move {
1000 match input_device_request {
1001 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1002 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1003 device_information: None,
1004 mouse: None,
1005 sensor: None,
1006 touch: None,
1007 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1008 input: Some(fidl_input_report::KeyboardInputDescriptor {
1009 keys3: None,
1010 ..Default::default()
1011 }),
1012 output: None,
1013 ..Default::default()
1014 }),
1015 consumer_control: None,
1016 ..Default::default()
1017 });
1018 }
1019 _ => panic!("InputDevice handler received an unexpected request"),
1020 }
1021 });
1022
1023 assert!(
1024 is_device_type(
1025 &input_device_proxy
1026 .get_descriptor()
1027 .await
1028 .expect("Failed to get device descriptor")
1029 .descriptor,
1030 InputDeviceType::Keyboard
1031 )
1032 .await
1033 );
1034 }
1035
1036 #[fasync::run_singlethreaded(test)]
1039 async fn keyboard_input_device_doesnt_exist() {
1040 let input_device_proxy =
1041 spawn_input_stream_handler(move |input_device_request| async move {
1042 match input_device_request {
1043 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1044 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1045 device_information: None,
1046 mouse: None,
1047 sensor: None,
1048 touch: None,
1049 keyboard: None,
1050 consumer_control: None,
1051 ..Default::default()
1052 });
1053 }
1054 _ => panic!("InputDevice handler received an unexpected request"),
1055 }
1056 });
1057
1058 assert!(
1059 !is_device_type(
1060 &input_device_proxy
1061 .get_descriptor()
1062 .await
1063 .expect("Failed to get device descriptor")
1064 .descriptor,
1065 InputDeviceType::Keyboard
1066 )
1067 .await
1068 );
1069 }
1070
1071 #[fasync::run_singlethreaded(test)]
1073 async fn no_input_device_match() {
1074 let input_device_proxy =
1075 spawn_input_stream_handler(move |input_device_request| async move {
1076 match input_device_request {
1077 fidl_input_report::InputDeviceRequest::GetDescriptor { responder } => {
1078 let _ = responder.send(&fidl_input_report::DeviceDescriptor {
1079 device_information: None,
1080 mouse: Some(fidl_input_report::MouseDescriptor {
1081 input: Some(fidl_input_report::MouseInputDescriptor {
1082 movement_x: None,
1083 movement_y: None,
1084 position_x: None,
1085 position_y: None,
1086 scroll_v: None,
1087 scroll_h: None,
1088 buttons: None,
1089 ..Default::default()
1090 }),
1091 ..Default::default()
1092 }),
1093 sensor: None,
1094 touch: Some(fidl_input_report::TouchDescriptor {
1095 input: Some(fidl_input_report::TouchInputDescriptor {
1096 contacts: None,
1097 max_contacts: None,
1098 touch_type: None,
1099 buttons: None,
1100 ..Default::default()
1101 }),
1102 ..Default::default()
1103 }),
1104 keyboard: Some(fidl_input_report::KeyboardDescriptor {
1105 input: Some(fidl_input_report::KeyboardInputDescriptor {
1106 keys3: None,
1107 ..Default::default()
1108 }),
1109 output: None,
1110 ..Default::default()
1111 }),
1112 consumer_control: Some(fidl_input_report::ConsumerControlDescriptor {
1113 input: Some(fidl_input_report::ConsumerControlInputDescriptor {
1114 buttons: Some(vec![
1115 fidl_input_report::ConsumerControlButton::VolumeUp,
1116 fidl_input_report::ConsumerControlButton::VolumeDown,
1117 ]),
1118 ..Default::default()
1119 }),
1120 ..Default::default()
1121 }),
1122 ..Default::default()
1123 });
1124 }
1125 _ => panic!("InputDevice handler received an unexpected request"),
1126 }
1127 });
1128
1129 let device_descriptor = &input_device_proxy
1130 .get_descriptor()
1131 .await
1132 .expect("Failed to get device descriptor")
1133 .descriptor;
1134 assert!(is_device_type(&device_descriptor, InputDeviceType::ConsumerControls).await);
1135 assert!(is_device_type(&device_descriptor, InputDeviceType::Mouse).await);
1136 assert!(is_device_type(&device_descriptor, InputDeviceType::Touch).await);
1137 assert!(is_device_type(&device_descriptor, InputDeviceType::Keyboard).await);
1138 }
1139
1140 #[fuchsia::test]
1141 fn unhandled_to_generic_conversion_sets_handled_flag_to_no() {
1142 assert_eq!(
1143 InputEvent::from(UnhandledInputEvent {
1144 device_event: InputDeviceEvent::Fake,
1145 device_descriptor: InputDeviceDescriptor::Fake,
1146 event_time: zx::MonotonicInstant::from_nanos(1),
1147 trace_id: None,
1148 })
1149 .handled,
1150 Handled::No
1151 );
1152 }
1153
1154 #[fuchsia::test]
1155 fn unhandled_to_generic_conversion_preserves_fields() {
1156 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1157 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1158 assert_eq!(
1159 InputEvent::from(UnhandledInputEvent {
1160 device_event: InputDeviceEvent::Fake,
1161 device_descriptor: InputDeviceDescriptor::Fake,
1162 event_time: EVENT_TIME,
1163 trace_id: expected_trace_id,
1164 }),
1165 InputEvent {
1166 device_event: InputDeviceEvent::Fake,
1167 device_descriptor: InputDeviceDescriptor::Fake,
1168 event_time: EVENT_TIME,
1169 handled: Handled::No,
1170 trace_id: expected_trace_id,
1171 },
1172 );
1173 }
1174
1175 #[fuchsia::test]
1176 fn generic_to_unhandled_conversion_fails_for_handled_events() {
1177 assert_matches!(
1178 UnhandledInputEvent::try_from(InputEvent {
1179 device_event: InputDeviceEvent::Fake,
1180 device_descriptor: InputDeviceDescriptor::Fake,
1181 event_time: zx::MonotonicInstant::from_nanos(1),
1182 handled: Handled::Yes,
1183 trace_id: None,
1184 }),
1185 Err(_)
1186 )
1187 }
1188
1189 #[fuchsia::test]
1190 fn generic_to_unhandled_conversion_preserves_fields_for_unhandled_events() {
1191 const EVENT_TIME: zx::MonotonicInstant = zx::MonotonicInstant::from_nanos(42);
1192 let expected_trace_id: Option<ftrace::Id> = Some(1234.into());
1193 assert_eq!(
1194 UnhandledInputEvent::try_from(InputEvent {
1195 device_event: InputDeviceEvent::Fake,
1196 device_descriptor: InputDeviceDescriptor::Fake,
1197 event_time: EVENT_TIME,
1198 handled: Handled::No,
1199 trace_id: expected_trace_id,
1200 })
1201 .unwrap(),
1202 UnhandledInputEvent {
1203 device_event: InputDeviceEvent::Fake,
1204 device_descriptor: InputDeviceDescriptor::Fake,
1205 event_time: EVENT_TIME,
1206 trace_id: expected_trace_id,
1207 },
1208 )
1209 }
1210
1211 #[test_case(Handled::No; "initially not handled")]
1212 #[test_case(Handled::Yes; "initially handled")]
1213 fn into_handled_if_yields_handled_yes_on_true(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_if(true).handled, Handled::Yes);
1222 }
1223
1224 #[test_case(Handled::No; "initially not handled")]
1225 #[test_case(Handled::Yes; "initially handled")]
1226 fn into_handled_if_leaves_handled_unchanged_on_false(initially_handled: Handled) {
1227 let event = InputEvent {
1228 device_event: InputDeviceEvent::Fake,
1229 device_descriptor: InputDeviceDescriptor::Fake,
1230 event_time: zx::MonotonicInstant::from_nanos(1),
1231 handled: initially_handled.clone(),
1232 trace_id: None,
1233 };
1234 pretty_assertions::assert_eq!(event.into_handled_if(false).handled, initially_handled);
1235 }
1236
1237 #[test_case(Handled::No; "initially not handled")]
1238 #[test_case(Handled::Yes; "initially handled")]
1239 fn into_handled_yields_handled_yes(initially_handled: Handled) {
1240 let event = InputEvent {
1241 device_event: InputDeviceEvent::Fake,
1242 device_descriptor: InputDeviceDescriptor::Fake,
1243 event_time: zx::MonotonicInstant::from_nanos(1),
1244 handled: initially_handled,
1245 trace_id: None,
1246 };
1247 pretty_assertions::assert_eq!(event.into_handled().handled, Handled::Yes);
1248 }
1249}