blob: 72745bd2982cfbe2155d4ff926a573b90c70fada [file] [log] [blame]
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use {
crate::{inverse_keymap::InverseKeymap, keymaps},
anyhow::{ensure, Error},
async_trait::async_trait,
fidl_fuchsia_ui_input::{self, KeyboardReport, Touch},
fuchsia_zircon as zx,
std::{convert::TryFrom, thread, time::Duration},
};
// Abstracts over input injection services (which are provided by input device registries).
pub trait InputDeviceRegistry {
fn add_touchscreen_device(
&mut self,
width: u32,
height: u32,
) -> Result<Box<dyn InputDevice>, Error>;
fn add_keyboard_device(&mut self) -> Result<Box<dyn InputDevice>, Error>;
fn add_media_buttons_device(&mut self) -> Result<Box<dyn InputDevice>, Error>;
}
// Abstracts over the various interactions that a user might have with an input device.
// Note that the input-synthesis crate deliberately chooses not to "sub-type" input devices.
// This avoids additional code complexity, and allows the crate to support tests that
// deliberately send events that do not match the expected event type for a device.
#[async_trait(?Send)]
pub trait InputDevice {
fn media_buttons(
&mut self,
volume_up: bool,
volume_down: bool,
mic_mute: bool,
reset: bool,
pause: bool,
camera_disable: bool,
time: u64,
) -> Result<(), Error>;
fn key_press(&mut self, keyboard: KeyboardReport, time: u64) -> Result<(), Error>;
fn key_press_usage(&mut self, usage: Option<u32>, time: u64) -> Result<(), Error>;
fn tap(&mut self, pos: Option<(u32, u32)>, time: u64) -> Result<(), Error>;
fn multi_finger_tap(&mut self, fingers: Option<Vec<Touch>>, time: u64) -> Result<(), Error>;
// Returns a `Future` which resolves when all input reports for this device
// have been sent to the FIDL peer, or when an error occurs.
//
// The possible errors are implementation-specific, but may include:
// * Errors reading from the FIDL peer
// * Errors writing to the FIDL peer
//
// # Resolves to
// * `Ok(())` if all reports were written successfully
// * `Err` otherwise
//
// # Note
// When the future resolves, input reports may still be sitting unread in the
// channel to the FIDL peer.
async fn serve_reports(self: Box<Self>) -> Result<(), Error>;
}
fn monotonic_nanos() -> Result<u64, Error> {
u64::try_from(zx::Time::get_monotonic().into_nanos()).map_err(Into::into)
}
fn repeat_with_delay(
times: usize,
delay: Duration,
device: &mut dyn InputDevice,
f1: impl Fn(usize, &mut dyn InputDevice) -> Result<(), Error>,
f2: impl Fn(usize, &mut dyn InputDevice) -> Result<(), Error>,
) -> Result<(), Error> {
for i in 0..times {
f1(i, device)?;
thread::sleep(delay);
f2(i, device)?;
}
Ok(())
}
pub(crate) async fn media_button_event(
volume_up: bool,
volume_down: bool,
mic_mute: bool,
reset: bool,
pause: bool,
camera_disable: bool,
registry: &mut dyn InputDeviceRegistry,
) -> Result<(), Error> {
let mut input_device = registry.add_media_buttons_device()?;
input_device.media_buttons(
volume_up,
volume_down,
mic_mute,
reset,
pause,
camera_disable,
monotonic_nanos()?,
)?;
input_device.serve_reports().await
}
pub(crate) async fn keyboard_event(
usage: u32,
duration: Duration,
registry: &mut dyn InputDeviceRegistry,
) -> Result<(), Error> {
let mut input_device = registry.add_keyboard_device()?;
repeat_with_delay(
1,
duration,
input_device.as_mut(),
|_i, device| {
// Key pressed.
device.key_press_usage(Some(usage), monotonic_nanos()?)
},
|_i, device| {
// Key released.
device.key_press_usage(None, monotonic_nanos()?)
},
)?;
input_device.serve_reports().await
}
pub(crate) async fn text(
input: String,
key_event_duration: Duration,
registry: &mut dyn InputDeviceRegistry,
) -> Result<(), Error> {
let mut input_device = registry.add_keyboard_device()?;
let key_sequence = InverseKeymap::new(keymaps::QWERTY_MAP)
.derive_key_sequence(&input)
.ok_or_else(|| anyhow::format_err!("Cannot translate text to key sequence"))?;
let mut key_iter = key_sequence.into_iter().peekable();
while let Some(keyboard) = key_iter.next() {
input_device.key_press(keyboard, monotonic_nanos()?)?;
if key_iter.peek().is_some() {
thread::sleep(key_event_duration);
}
}
input_device.serve_reports().await
}
pub async fn tap_event(
x: u32,
y: u32,
width: u32,
height: u32,
tap_event_count: usize,
duration: Duration,
registry: &mut dyn InputDeviceRegistry,
) -> Result<(), Error> {
let mut input_device = registry.add_touchscreen_device(width, height)?;
let tap_duration = duration / tap_event_count as u32;
repeat_with_delay(
tap_event_count,
tap_duration,
input_device.as_mut(),
|_i, device| {
// Touch down.
device.tap(Some((x, y)), monotonic_nanos()?)
},
|_i, device| {
// Touch up.
device.tap(None, monotonic_nanos()?)
},
)?;
input_device.serve_reports().await
}
pub(crate) async fn multi_finger_tap_event(
fingers: Vec<Touch>,
width: u32,
height: u32,
tap_event_count: usize,
duration: Duration,
registry: &mut dyn InputDeviceRegistry,
) -> Result<(), Error> {
let mut input_device = registry.add_touchscreen_device(width, height)?;
let multi_finger_tap_duration = duration / tap_event_count as u32;
repeat_with_delay(
tap_event_count,
multi_finger_tap_duration,
input_device.as_mut(),
|_i, device| {
// Touch down.
device.multi_finger_tap(Some(fingers.clone()), monotonic_nanos()?)
},
|_i, device| {
// Touch up.
device.multi_finger_tap(None, monotonic_nanos()?)
},
)?;
input_device.serve_reports().await
}
pub(crate) async fn swipe(
x0: u32,
y0: u32,
x1: u32,
y1: u32,
width: u32,
height: u32,
move_event_count: usize,
duration: Duration,
registry: &mut dyn InputDeviceRegistry,
) -> Result<(), Error> {
multi_finger_swipe(
vec![(x0, y0)],
vec![(x1, y1)],
width,
height,
move_event_count,
duration,
registry,
)
.await
}
pub(crate) async fn multi_finger_swipe(
start_fingers: Vec<(u32, u32)>,
end_fingers: Vec<(u32, u32)>,
width: u32,
height: u32,
move_event_count: usize,
duration: Duration,
registry: &mut dyn InputDeviceRegistry,
) -> Result<(), Error> {
ensure!(
start_fingers.len() == end_fingers.len(),
"start_fingers.len() != end_fingers.len() ({} != {})",
start_fingers.len(),
end_fingers.len()
);
ensure!(
u32::try_from(start_fingers.len() + 1).is_ok(),
"fingers exceed capacity of `finger_id`!"
);
let mut input_device = registry.add_touchscreen_device(width, height)?;
// Note: coordinates are coverted to `f64` before subtraction, because u32 subtraction
// would overflow when swiping from higher coordinates to lower coordinates.
let finger_delta_x = start_fingers
.iter()
.zip(end_fingers.iter())
.map(|((start_x, _start_y), (end_x, _end_y))| {
(*end_x as f64 - *start_x as f64) / std::cmp::max(move_event_count, 1) as f64
})
.collect::<Vec<_>>();
let finger_delta_y = start_fingers
.iter()
.zip(end_fingers.iter())
.map(|((_start_x, start_y), (_end_x, end_y))| {
(*end_y as f64 - *start_y as f64) / std::cmp::max(move_event_count, 1) as f64
})
.collect::<Vec<_>>();
let swipe_event_delay = if move_event_count > 1 {
// We have move_event_count + 2 events:
// DOWN
// MOVE x move_event_count
// UP
// so we need (move_event_count + 1) delays.
duration / (move_event_count + 1) as u32
} else {
duration
};
repeat_with_delay(
move_event_count + 2, // +2 to account for DOWN and UP events
swipe_event_delay,
input_device.as_mut(),
|i, device| {
let time = monotonic_nanos()?;
match i {
// DOWN
0 => device.multi_finger_tap(
Some(
start_fingers
.iter()
.enumerate()
.map(|(finger_index, (x, y))| Touch {
finger_id: (finger_index + 1) as u32,
x: *x as i32,
y: *y as i32,
width: 0,
height: 0,
})
.collect(),
),
time,
),
// MOVE
i if i <= move_event_count => device.multi_finger_tap(
Some(
start_fingers
.iter()
.enumerate()
.map(|(finger_index, (x, y))| Touch {
finger_id: (finger_index + 1) as u32,
x: (*x as f64 + (i as f64 * finger_delta_x[finger_index]).round())
as i32,
y: (*y as f64 + (i as f64 * finger_delta_y[finger_index]).round())
as i32,
width: 0,
height: 0,
})
.collect(),
),
time,
),
// UP
i if i == (move_event_count + 1) => device.multi_finger_tap(None, time),
i => panic!("unexpected loop iteration {}", i),
}
},
|_, _| Ok(()),
)?;
input_device.serve_reports().await
}
#[cfg(test)]
mod tests {
use {super::*, fuchsia_async as fasync};
mod event_synthesis {
use {
super::*,
anyhow::Context as _,
fidl::endpoints,
fidl_fuchsia_ui_input::{
InputDeviceMarker, InputDeviceProxy as FidlInputDeviceProxy, InputDeviceRequest,
InputDeviceRequestStream, InputReport, KeyboardReport, MediaButtonsReport,
TouchscreenReport,
},
futures::stream::StreamExt,
};
// Like `InputReport`, but with the `Box`-ed items inlined.
struct InlineInputReport {
event_time: u64,
keyboard: Option<KeyboardReport>,
media_buttons: Option<MediaButtonsReport>,
touchscreen: Option<TouchscreenReport>,
}
impl InlineInputReport {
fn new(input_report: InputReport) -> Self {
Self {
event_time: input_report.event_time,
keyboard: input_report.keyboard.map(|boxed| *boxed),
media_buttons: input_report.media_buttons.map(|boxed| *boxed),
touchscreen: input_report.touchscreen.map(|boxed| *boxed),
}
}
}
// An `impl InputDeviceRegistry` which provides access to the `InputDeviceRequest`s sent to
// the device registered with the `InputDeviceRegistry`. Assumes that only one device is
// registered.
struct FakeInputDeviceRegistry {
event_stream: Option<InputDeviceRequestStream>,
}
impl InputDeviceRegistry for FakeInputDeviceRegistry {
fn add_touchscreen_device(
&mut self,
_width: u32,
_height: u32,
) -> Result<Box<dyn InputDevice>, Error> {
self.add_device()
}
fn add_keyboard_device(&mut self) -> Result<Box<dyn InputDevice>, Error> {
self.add_device()
}
fn add_media_buttons_device(&mut self) -> Result<Box<dyn InputDevice>, Error> {
self.add_device()
}
}
impl FakeInputDeviceRegistry {
fn new() -> Self {
Self { event_stream: None }
}
async fn get_events(self: Self) -> Vec<Result<InlineInputReport, String>> {
match self.event_stream {
Some(event_stream) => {
event_stream
.map(|fidl_result| match fidl_result {
Ok(InputDeviceRequest::DispatchReport { report, .. }) => {
Ok(InlineInputReport::new(report))
}
Err(fidl_error) => Err(format!("FIDL error: {}", fidl_error)),
})
.collect()
.await
}
None => vec![Err(format!(
"called get_events() on InputDeviceRegistry with no `event_stream`"
))],
}
}
fn add_device(&mut self) -> Result<Box<dyn InputDevice>, Error> {
let (proxy, event_stream) =
endpoints::create_proxy_and_stream::<InputDeviceMarker>()?;
self.event_stream = Some(event_stream);
Ok(Box::new(FakeInputDevice::new(proxy)))
}
}
// Provides an `impl InputDevice` which forwards requests to a `FidlInputDeviceProxy`.
// Useful when a test wants to inspect the requests to an `InputDevice`.
struct FakeInputDevice {
fidl_proxy: FidlInputDeviceProxy,
}
#[async_trait(?Send)]
impl InputDevice for FakeInputDevice {
fn media_buttons(
&mut self,
volume_up: bool,
volume_down: bool,
mic_mute: bool,
reset: bool,
pause: bool,
camera_disable: bool,
time: u64,
) -> Result<(), Error> {
self.fidl_proxy
.dispatch_report(&mut InputReport {
event_time: time,
keyboard: None,
media_buttons: Some(Box::new(MediaButtonsReport {
volume_up,
volume_down,
mic_mute,
reset,
camera_disable,
pause,
})),
mouse: None,
stylus: None,
touchscreen: None,
sensor: None,
trace_id: 0,
})
.map_err(Into::into)
}
fn key_press(&mut self, keyboard: KeyboardReport, time: u64) -> Result<(), Error> {
self.fidl_proxy
.dispatch_report(&mut InputReport {
event_time: time,
keyboard: Some(Box::new(keyboard)),
media_buttons: None,
mouse: None,
stylus: None,
touchscreen: None,
sensor: None,
trace_id: 0,
})
.map_err(Into::into)
}
fn key_press_usage(&mut self, usage: Option<u32>, time: u64) -> Result<(), Error> {
self.key_press(
KeyboardReport {
pressed_keys: match usage {
Some(usage) => vec![usage],
None => vec![],
},
},
time,
)
.map_err(Into::into)
}
fn tap(&mut self, pos: Option<(u32, u32)>, time: u64) -> Result<(), Error> {
match pos {
Some((x, y)) => self.multi_finger_tap(
Some(vec![Touch {
finger_id: 1,
x: x as i32,
y: y as i32,
width: 0,
height: 0,
}]),
time,
),
None => self.multi_finger_tap(None, time),
}
.map_err(Into::into)
}
fn multi_finger_tap(
&mut self,
fingers: Option<Vec<Touch>>,
time: u64,
) -> Result<(), Error> {
self.fidl_proxy
.dispatch_report(&mut InputReport {
event_time: time,
keyboard: None,
media_buttons: None,
mouse: None,
stylus: None,
touchscreen: Some(Box::new(TouchscreenReport {
touches: match fingers {
Some(fingers) => fingers,
None => vec![],
},
})),
sensor: None,
trace_id: 0,
})
.map_err(Into::into)
}
async fn serve_reports(self: Box<Self>) -> Result<(), Error> {
Ok(())
}
}
impl FakeInputDevice {
fn new(fidl_proxy: FidlInputDeviceProxy) -> Self {
Self { fidl_proxy }
}
}
/// Transforms an `IntoIterator<Item = Result<InlineInputReport, _>>` into a
/// `Vec<Result</* $field-specific-type */, _>>`, by projecting `$field` out of the
/// `InlineInputReport`s.
macro_rules! project {
( $events:expr, $field:ident ) => {
$events
.into_iter()
.map(|result| result.map(|report| report.$field))
.collect::<Vec<_>>()
};
}
#[fasync::run_singlethreaded(test)]
async fn media_event_report() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
media_button_event(true, false, true, false, true, true, &mut fake_event_listener)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, media_buttons),
[Ok(Some(MediaButtonsReport {
volume_up: true,
volume_down: false,
mic_mute: true,
reset: false,
pause: true,
camera_disable: true,
}))]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn keyboard_event_report() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
keyboard_event(40, Duration::from_millis(0), &mut fake_event_listener).await?;
assert_eq!(
project!(fake_event_listener.get_events().await, keyboard),
[
Ok(Some(KeyboardReport { pressed_keys: vec![40] })),
Ok(Some(KeyboardReport { pressed_keys: vec![] }))
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn text_event_report() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
text("A".to_string(), Duration::from_millis(0), &mut fake_event_listener).await?;
assert_eq!(
project!(fake_event_listener.get_events().await, keyboard),
[
Ok(Some(KeyboardReport { pressed_keys: vec![225] })),
Ok(Some(KeyboardReport { pressed_keys: vec![4, 225] })),
Ok(Some(KeyboardReport { pressed_keys: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn multi_finger_tap_event_report() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
let fingers = vec![
Touch { finger_id: 1, x: 0, y: 0, width: 0, height: 0 },
Touch { finger_id: 2, x: 20, y: 20, width: 0, height: 0 },
Touch { finger_id: 3, x: 40, y: 40, width: 0, height: 0 },
Touch { finger_id: 4, x: 60, y: 60, width: 0, height: 0 },
];
multi_finger_tap_event(
fingers,
1000,
1000,
1,
Duration::from_millis(0),
&mut fake_event_listener,
)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, touchscreen),
[
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 0, y: 0, width: 0, height: 0 },
Touch { finger_id: 2, x: 20, y: 20, width: 0, height: 0 },
Touch { finger_id: 3, x: 40, y: 40, width: 0, height: 0 },
Touch { finger_id: 4, x: 60, y: 60, width: 0, height: 0 },
],
})),
Ok(Some(TouchscreenReport { touches: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn tap_event_report() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
tap_event(10, 10, 1000, 1000, 1, Duration::from_millis(0), &mut fake_event_listener)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, touchscreen),
[
Ok(Some(TouchscreenReport {
touches: vec![Touch { finger_id: 1, x: 10, y: 10, width: 0, height: 0 }]
})),
Ok(Some(TouchscreenReport { touches: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn swipe_event_report() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
swipe(
10,
10,
100,
100,
1000,
1000,
2,
Duration::from_millis(0),
&mut fake_event_listener,
)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, touchscreen),
[
Ok(Some(TouchscreenReport {
touches: vec![Touch { finger_id: 1, x: 10, y: 10, width: 0, height: 0 }],
})),
Ok(Some(TouchscreenReport {
touches: vec![Touch { finger_id: 1, x: 55, y: 55, width: 0, height: 0 }],
})),
Ok(Some(TouchscreenReport {
touches: vec![Touch { finger_id: 1, x: 100, y: 100, width: 0, height: 0 }],
})),
Ok(Some(TouchscreenReport { touches: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn swipe_event_report_inverted() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
swipe(
100,
100,
10,
10,
1000,
1000,
2,
Duration::from_millis(0),
&mut fake_event_listener,
)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, touchscreen),
[
Ok(Some(TouchscreenReport {
touches: vec![Touch { finger_id: 1, x: 100, y: 100, width: 0, height: 0 }],
})),
Ok(Some(TouchscreenReport {
touches: vec![Touch { finger_id: 1, x: 55, y: 55, width: 0, height: 0 }],
})),
Ok(Some(TouchscreenReport {
touches: vec![Touch { finger_id: 1, x: 10, y: 10, width: 0, height: 0 }],
})),
Ok(Some(TouchscreenReport { touches: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn multi_finger_swipe_event_report() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
multi_finger_swipe(
vec![(10, 10), (20, 20), (30, 30)],
vec![(100, 100), (120, 120), (150, 150)],
1000,
1000,
2,
Duration::from_millis(0),
&mut fake_event_listener,
)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, touchscreen),
[
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 10, y: 10, width: 0, height: 0 },
Touch { finger_id: 2, x: 20, y: 20, width: 0, height: 0 },
Touch { finger_id: 3, x: 30, y: 30, width: 0, height: 0 }
],
})),
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 55, y: 55, width: 0, height: 0 },
Touch { finger_id: 2, x: 70, y: 70, width: 0, height: 0 },
Touch { finger_id: 3, x: 90, y: 90, width: 0, height: 0 }
],
})),
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 100, y: 100, width: 0, height: 0 },
Touch { finger_id: 2, x: 120, y: 120, width: 0, height: 0 },
Touch { finger_id: 3, x: 150, y: 150, width: 0, height: 0 }
],
})),
Ok(Some(TouchscreenReport { touches: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn multi_finger_swipe_event_report_inverted() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
multi_finger_swipe(
vec![(100, 100), (120, 120), (150, 150)],
vec![(10, 10), (20, 20), (30, 30)],
1000,
1000,
2,
Duration::from_millis(0),
&mut fake_event_listener,
)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, touchscreen),
[
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 100, y: 100, width: 0, height: 0 },
Touch { finger_id: 2, x: 120, y: 120, width: 0, height: 0 },
Touch { finger_id: 3, x: 150, y: 150, width: 0, height: 0 }
],
})),
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 55, y: 55, width: 0, height: 0 },
Touch { finger_id: 2, x: 70, y: 70, width: 0, height: 0 },
Touch { finger_id: 3, x: 90, y: 90, width: 0, height: 0 }
],
})),
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 10, y: 10, width: 0, height: 0 },
Touch { finger_id: 2, x: 20, y: 20, width: 0, height: 0 },
Touch { finger_id: 3, x: 30, y: 30, width: 0, height: 0 }
],
})),
Ok(Some(TouchscreenReport { touches: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn multi_finger_swipe_event_zero_move_events() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
multi_finger_swipe(
vec![(10, 10), (20, 20), (30, 30)],
vec![(100, 100), (120, 120), (150, 150)],
1000,
1000,
0,
Duration::from_millis(0),
&mut fake_event_listener,
)
.await?;
assert_eq!(
project!(fake_event_listener.get_events().await, touchscreen),
[
Ok(Some(TouchscreenReport {
touches: vec![
Touch { finger_id: 1, x: 10, y: 10, width: 0, height: 0 },
Touch { finger_id: 2, x: 20, y: 20, width: 0, height: 0 },
Touch { finger_id: 3, x: 30, y: 30, width: 0, height: 0 }
],
})),
Ok(Some(TouchscreenReport { touches: vec![] })),
]
);
Ok(())
}
#[fasync::run_singlethreaded(test)]
async fn events_use_monotonic_time() -> Result<(), Error> {
let mut fake_event_listener = FakeInputDeviceRegistry::new();
let synthesis_start_time = monotonic_nanos()?;
media_button_event(true, false, true, false, true, true, &mut fake_event_listener)
.await?;
let synthesis_end_time = monotonic_nanos()?;
let fidl_result = fake_event_listener
.get_events()
.await
.into_iter()
.nth(0)
.expect("received 0 events");
let timestamp =
fidl_result.map_err(anyhow::Error::msg).context("fidl call")?.event_time;
// Note well: neither condition is sufficient on its own, to verify that
// `synthesizer` has used the correct clock. For example:
//
// * `timestamp >= synthesis_start_time` would be true for a `UNIX_EPOCH` clock
// with the correct time, since the elapsed time from 1970-01-01T00:00:00+00:00
// to now is (much) larger than the elapsed time from boot to `synthesis_start_time`
// * `timestamp <= synthesis_end_time` would be true for a `UNIX_EPOCH` clock
// has been recently set to 0, because `synthesis_end_time` is highly unlikely to
// be near 0 (as it is monotonic from boot)
//
// By bracketing between monotonic clock reads before and after the event generation,
// this test avoids the hazards above. The test also avoids the hazard of using a
// fixed offset from the start time (which could flake on a slow builder).
assert!(
timestamp >= synthesis_start_time,
"timestamp={} should be >= start={}",
timestamp,
synthesis_start_time
);
assert!(
timestamp <= synthesis_end_time,
"timestamp={} should be <= end={}",
timestamp,
synthesis_end_time
);
Ok(())
}
}
mod device_registration {
use {super::*, matches::assert_matches};
#[derive(Debug)]
enum DeviceType {
Keyboard,
MediaButtons,
Touchscreen,
}
// An `impl InputDeviceRegistry` which provides access to the `DeviceType`s which have been
// registered with the `InputDeviceRegistry`.
struct FakeInputDeviceRegistry {
device_types: Vec<DeviceType>,
}
impl InputDeviceRegistry for FakeInputDeviceRegistry {
fn add_touchscreen_device(
&mut self,
_width: u32,
_height: u32,
) -> Result<Box<dyn InputDevice>, Error> {
self.add_device(DeviceType::Touchscreen)
}
fn add_keyboard_device(&mut self) -> Result<Box<dyn InputDevice>, Error> {
self.add_device(DeviceType::Keyboard)
}
fn add_media_buttons_device(&mut self) -> Result<Box<dyn InputDevice>, Error> {
self.add_device(DeviceType::MediaButtons)
}
}
impl FakeInputDeviceRegistry {
fn new() -> Self {
Self { device_types: vec![] }
}
fn add_device(
&mut self,
device_type: DeviceType,
) -> Result<Box<dyn InputDevice>, Error> {
self.device_types.push(device_type);
Ok(Box::new(FakeInputDevice))
}
}
// Provides an `impl InputDevice` which always returns `Ok(())`. Useful when the
// events themselves are not important to the test.
struct FakeInputDevice;
#[async_trait(?Send)]
impl InputDevice for FakeInputDevice {
fn media_buttons(
&mut self,
_volume_up: bool,
_volume_down: bool,
_mic_mute: bool,
_reset: bool,
_pause: bool,
_camera_disable: bool,
_time: u64,
) -> Result<(), Error> {
Ok(())
}
fn key_press(&mut self, _keyboard: KeyboardReport, _time: u64) -> Result<(), Error> {
Ok(())
}
fn key_press_usage(&mut self, _usage: Option<u32>, _time: u64) -> Result<(), Error> {
Ok(())
}
fn tap(&mut self, _pos: Option<(u32, u32)>, _time: u64) -> Result<(), Error> {
Ok(())
}
fn multi_finger_tap(
&mut self,
_fingers: Option<Vec<Touch>>,
_time: u64,
) -> Result<(), Error> {
Ok(())
}
async fn serve_reports(self: Box<Self>) -> Result<(), Error> {
Ok(())
}
}
#[fasync::run_until_stalled(test)]
async fn media_button_event_registers_media_buttons_device() -> Result<(), Error> {
let mut registry = FakeInputDeviceRegistry::new();
media_button_event(false, false, false, false, false, false, &mut registry).await?;
assert_matches!(registry.device_types.as_slice(), [DeviceType::MediaButtons]);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn keyboard_event_registers_keyboard() -> Result<(), Error> {
let mut registry = FakeInputDeviceRegistry::new();
keyboard_event(40, Duration::from_millis(0), &mut registry).await?;
assert_matches!(registry.device_types.as_slice(), [DeviceType::Keyboard]);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn text_event_registers_keyboard() -> Result<(), Error> {
let mut registry = FakeInputDeviceRegistry::new();
text("A".to_string(), Duration::from_millis(0), &mut registry).await?;
assert_matches!(registry.device_types.as_slice(), [DeviceType::Keyboard]);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn multi_finger_tap_event_registers_touchscreen() -> Result<(), Error> {
let mut registry = FakeInputDeviceRegistry::new();
multi_finger_tap_event(vec![], 1000, 1000, 1, Duration::from_millis(0), &mut registry)
.await?;
assert_matches!(registry.device_types.as_slice(), [DeviceType::Touchscreen]);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn tap_event_registers_touchscreen() -> Result<(), Error> {
let mut registry = FakeInputDeviceRegistry::new();
tap_event(0, 0, 1000, 1000, 1, Duration::from_millis(0), &mut registry).await?;
assert_matches!(registry.device_types.as_slice(), [DeviceType::Touchscreen]);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn swipe_registers_touchscreen() -> Result<(), Error> {
let mut registry = FakeInputDeviceRegistry::new();
swipe(0, 0, 1, 1, 1000, 1000, 1, Duration::from_millis(0), &mut registry).await?;
assert_matches!(registry.device_types.as_slice(), [DeviceType::Touchscreen]);
Ok(())
}
#[fasync::run_until_stalled(test)]
async fn multi_finger_swipe_registers_touchscreen() -> Result<(), Error> {
let mut registry = FakeInputDeviceRegistry::new();
multi_finger_swipe(
vec![],
vec![],
1000,
1000,
1,
Duration::from_millis(0),
&mut registry,
)
.await?;
assert_matches!(registry.device_types.as_slice(), [DeviceType::Touchscreen]);
Ok(())
}
}
}