use crate::input_device::{self, InputEvent};
use crate::input_handler::InputHandlerStatus;
use crate::keyboard_binding::{KeyboardDeviceDescriptor, KeyboardEvent};
use anyhow::{Context, Result};
use fidl_fuchsia_ui_composition_internal as fcomp;
use fidl_fuchsia_ui_input3::KeyEventType;
use fuchsia_async::{OnSignals, Task};
use fuchsia_inspect::health::Reporter;
use futures::channel::mpsc::{self, UnboundedReceiver, UnboundedSender};
use futures::{select, StreamExt};
use keymaps::KeyState;
use lazy_static::lazy_static;
use std::cell::RefCell;
use std::rc::Rc;
use zx::{AsHandleRef, MonotonicDuration, MonotonicInstant, Signals, Status};
lazy_static! {
static ref DISPLAY_OWNED: Signals = Signals::from_bits(fcomp::SIGNAL_DISPLAY_OWNED)
.expect("static init should not fail") ;
static ref DISPLAY_UNOWNED: Signals = Signals::from_bits(fcomp::SIGNAL_DISPLAY_NOT_OWNED)
.expect("static init should not fail") ;
static ref ANY_DISPLAY_EVENT: Signals = *DISPLAY_OWNED | *DISPLAY_UNOWNED;
}
#[derive(Debug, Clone, PartialEq)]
struct Ownership {
signals: Signals,
}
impl std::convert::From<Signals> for Ownership {
fn from(signals: Signals) -> Self {
Ownership { signals }
}
}
impl Ownership {
fn is_display_ownership_lost(&self) -> bool {
self.signals.contains(*DISPLAY_UNOWNED)
}
fn next_signal(&self) -> Signals {
match self.is_display_ownership_lost() {
true => *DISPLAY_OWNED,
false => *DISPLAY_UNOWNED,
}
}
async fn wait_ownership_change<'a, T: AsHandleRef>(
&self,
event: &'a T,
) -> Result<Signals, Status> {
OnSignals::new(event, self.next_signal()).await
}
}
pub struct DisplayOwnership {
ownership: Rc<RefCell<Ownership>>,
key_state: RefCell<KeyState>,
display_ownership_change_receiver: RefCell<UnboundedReceiver<Ownership>>,
_display_ownership_task: Task<()>,
inspect_status: InputHandlerStatus,
#[cfg(test)]
loop_done: RefCell<Option<UnboundedSender<()>>>,
}
impl DisplayOwnership {
pub fn new(
display_ownership_event: impl AsHandleRef + 'static,
input_handlers_node: &fuchsia_inspect::Node,
) -> Rc<Self> {
DisplayOwnership::new_internal(display_ownership_event, None, input_handlers_node)
}
#[cfg(test)]
pub fn new_for_test(
display_ownership_event: impl AsHandleRef + 'static,
loop_done: UnboundedSender<()>,
) -> Rc<Self> {
let inspector = fuchsia_inspect::Inspector::default();
let fake_handlers_node = inspector.root().create_child("input_handlers_node");
DisplayOwnership::new_internal(
display_ownership_event,
Some(loop_done),
&fake_handlers_node,
)
}
fn new_internal(
display_ownership_event: impl AsHandleRef + 'static,
_loop_done: Option<UnboundedSender<()>>,
input_handlers_node: &fuchsia_inspect::Node,
) -> Rc<Self> {
let initial_state = display_ownership_event
.wait_handle(*ANY_DISPLAY_EVENT, MonotonicInstant::INFINITE_PAST)
.expect("unable to set the initial display state");
tracing::debug!("setting initial display ownership to: {:?}", &initial_state);
let initial_ownership: Ownership = initial_state.into();
let ownership = Rc::new(RefCell::new(initial_ownership.clone()));
let mut ownership_clone = initial_ownership;
let (ownership_sender, ownership_receiver) = mpsc::unbounded();
let display_ownership_task = Task::local(async move {
loop {
let signals = ownership_clone.wait_ownership_change(&display_ownership_event).await;
match signals {
Err(e) => {
tracing::warn!("could not read display state: {:?}", e);
break;
}
Ok(signals) => {
tracing::debug!("setting display ownership to: {:?}", &signals);
ownership_sender.unbounded_send(signals.into()).unwrap();
ownership_clone = signals.into();
}
}
}
tracing::warn!("display loop exiting and will no longer monitor display changes - this is not expected");
});
tracing::info!("Display ownership handler installed");
let inspect_status = InputHandlerStatus::new(
input_handlers_node,
"display_ownership",
false,
);
Rc::new(Self {
ownership,
key_state: RefCell::new(KeyState::new()),
display_ownership_change_receiver: RefCell::new(ownership_receiver),
_display_ownership_task: display_ownership_task,
inspect_status,
#[cfg(test)]
loop_done: RefCell::new(_loop_done),
})
}
fn is_display_ownership_lost(&self) -> bool {
self.ownership.borrow().is_display_ownership_lost()
}
pub async fn handle_input_events(
self: &Rc<Self>,
mut input: UnboundedReceiver<InputEvent>,
output: UnboundedSender<InputEvent>,
) -> Result<()> {
loop {
let mut ownership_source = self.display_ownership_change_receiver.borrow_mut();
select! {
new_ownership = ownership_source.select_next_some() => {
let is_display_ownership_lost = new_ownership.is_display_ownership_lost();
let event_type = match is_display_ownership_lost {
true => KeyEventType::Cancel,
false => KeyEventType::Sync,
};
let keys = self.key_state.borrow().get_set();
let mut event_time = MonotonicInstant::get();
for key in keys.into_iter() {
let key_event = KeyboardEvent::new(key, event_type);
output.unbounded_send(into_input_event(key_event, event_time))
.context("unable to send display updates")?;
event_time = event_time + MonotonicDuration::from_nanos(1);
}
*(self.ownership.borrow_mut()) = new_ownership;
},
event = input.select_next_some() => {
if event.is_handled() {
output.unbounded_send(event).context("unable to send handled event")?;
continue;
}
self.inspect_status.count_received_event(input_device::InputEvent::from(event.clone()));
match event.device_event {
input_device::InputDeviceEvent::Keyboard(ref e) => {
self.key_state.borrow_mut().update(e.get_event_type(), e.get_key());
},
_ => {},
}
let is_display_ownership_lost = self.is_display_ownership_lost();
if is_display_ownership_lost {
self.inspect_status.count_handled_event();
}
output.unbounded_send(
input_device::InputEvent::from(event)
.into_handled_if(is_display_ownership_lost)
).context("unable to send input event updates")?;
},
};
#[cfg(test)]
{
self.loop_done.borrow_mut().as_ref().unwrap().unbounded_send(()).unwrap();
}
}
}
pub fn set_handler_healthy(self: std::rc::Rc<Self>) {
self.inspect_status.health_node.borrow_mut().set_ok();
}
pub fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str) {
self.inspect_status.health_node.borrow_mut().set_unhealthy(msg);
}
}
fn empty_keyboard_device_descriptor() -> input_device::InputDeviceDescriptor {
input_device::InputDeviceDescriptor::Keyboard(
KeyboardDeviceDescriptor {
keys: vec![],
device_information: fidl_fuchsia_input_report::DeviceInformation {
vendor_id: Some(0),
product_id: Some(0),
version: Some(0),
polling_rate: Some(0),
..Default::default()
},
device_id: 0,
},
)
}
fn into_input_event(
keyboard_event: KeyboardEvent,
event_time: MonotonicInstant,
) -> input_device::InputEvent {
input_device::InputEvent {
device_event: input_device::InputDeviceEvent::Keyboard(keyboard_event),
device_descriptor: empty_keyboard_device_descriptor(),
event_time,
handled: input_device::Handled::No,
trace_id: None,
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::testing_utilities::{create_fake_input_event, create_input_event};
use fidl_fuchsia_input::Key;
use fuchsia_async as fasync;
use pretty_assertions::assert_eq;
use zx::{EventPair, Peered};
struct DisplayWrangler {
event: EventPair,
last: Signals,
}
impl DisplayWrangler {
fn new(event: EventPair) -> Self {
let mut instance = DisplayWrangler { event, last: *DISPLAY_OWNED };
instance.set_unowned();
instance
}
fn set_unowned(&mut self) {
assert!(self.last != *DISPLAY_UNOWNED, "display is already unowned");
self.event.signal_peer(*DISPLAY_OWNED, *DISPLAY_UNOWNED).unwrap();
self.last = *DISPLAY_UNOWNED;
}
fn set_owned(&mut self) {
assert!(self.last != *DISPLAY_OWNED, "display is already owned");
self.event.signal_peer(*DISPLAY_UNOWNED, *DISPLAY_OWNED).unwrap();
self.last = *DISPLAY_OWNED;
}
}
#[fuchsia::test]
async fn display_ownership_change() {
let (test_event, handler_event) = EventPair::create();
let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
let mut wrangler = DisplayWrangler::new(test_event);
let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
let _task = fasync::Task::local(async move {
handler.handle_input_events(handler_receiver, handler_sender).await.unwrap();
});
let fake_time = MonotonicInstant::from_nanos(42);
wrangler.set_owned();
loop_done.next().await;
test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
loop_done.next().await;
wrangler.set_unowned();
loop_done.next().await;
test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
loop_done.next().await;
wrangler.set_owned();
loop_done.next().await;
test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
loop_done.next().await;
wrangler.set_unowned();
loop_done.next().await;
test_sender.unbounded_send(create_fake_input_event(fake_time)).unwrap();
loop_done.next().await;
let actual: Vec<InputEvent> =
test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
assert_eq!(
actual,
vec![
create_fake_input_event(fake_time),
create_fake_input_event(fake_time).into_handled(),
create_fake_input_event(fake_time),
create_fake_input_event(fake_time).into_handled(),
]
);
}
fn new_keyboard_input_event(key: Key, event_type: KeyEventType) -> InputEvent {
let fake_time = MonotonicInstant::from_nanos(42);
create_input_event(
KeyboardEvent::new(key, event_type),
&input_device::InputDeviceDescriptor::Fake,
fake_time,
input_device::Handled::No,
)
}
#[fuchsia::test]
async fn basic_key_state_handling() {
let (test_event, handler_event) = EventPair::create();
let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
let mut wrangler = DisplayWrangler::new(test_event);
let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
let _task = fasync::Task::local(async move {
handler.handle_input_events(handler_receiver, handler_sender).await.unwrap();
});
let fake_time = MonotonicInstant::from_nanos(42);
wrangler.set_owned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
.unwrap();
loop_done.next().await;
wrangler.set_unowned();
loop_done.next().await;
wrangler.set_owned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
.unwrap();
loop_done.next().await;
let actual: Vec<InputEvent> =
test_receiver.take(4).map(|e| e.into_with_event_time(fake_time)).collect().await;
assert_eq!(
actual,
vec![
new_keyboard_input_event(Key::A, KeyEventType::Pressed),
new_keyboard_input_event(Key::A, KeyEventType::Cancel)
.into_with_device_descriptor(empty_keyboard_device_descriptor()),
new_keyboard_input_event(Key::A, KeyEventType::Sync)
.into_with_device_descriptor(empty_keyboard_device_descriptor()),
new_keyboard_input_event(Key::A, KeyEventType::Released),
]
);
}
#[fuchsia::test]
async fn more_key_state_handling() {
let (test_event, handler_event) = EventPair::create();
let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
let (handler_sender, test_receiver) = mpsc::unbounded::<InputEvent>();
let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
let mut wrangler = DisplayWrangler::new(test_event);
let handler = DisplayOwnership::new_for_test(handler_event, loop_done_sender);
let _task = fasync::Task::local(async move {
handler.handle_input_events(handler_receiver, handler_sender).await.unwrap();
});
let fake_time = MonotonicInstant::from_nanos(42);
wrangler.set_owned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
.unwrap();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
.unwrap();
loop_done.next().await;
wrangler.set_unowned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Released))
.unwrap();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Pressed))
.unwrap();
loop_done.next().await;
wrangler.set_owned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
.unwrap();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::C, KeyEventType::Released))
.unwrap();
loop_done.next().await;
let actual: Vec<InputEvent> =
test_receiver.take(10).map(|e| e.into_with_event_time(fake_time)).collect().await;
assert_eq!(
actual,
vec![
new_keyboard_input_event(Key::A, KeyEventType::Pressed),
new_keyboard_input_event(Key::B, KeyEventType::Pressed),
new_keyboard_input_event(Key::A, KeyEventType::Cancel)
.into_with_device_descriptor(empty_keyboard_device_descriptor()),
new_keyboard_input_event(Key::B, KeyEventType::Cancel)
.into_with_device_descriptor(empty_keyboard_device_descriptor()),
new_keyboard_input_event(Key::B, KeyEventType::Released).into_handled(),
new_keyboard_input_event(Key::C, KeyEventType::Pressed).into_handled(),
new_keyboard_input_event(Key::A, KeyEventType::Sync)
.into_with_device_descriptor(empty_keyboard_device_descriptor()),
new_keyboard_input_event(Key::C, KeyEventType::Sync)
.into_with_device_descriptor(empty_keyboard_device_descriptor()),
new_keyboard_input_event(Key::A, KeyEventType::Released),
new_keyboard_input_event(Key::C, KeyEventType::Released),
]
);
}
#[fuchsia::test]
async fn display_ownership_initialized_with_inspect_node() {
let (test_event, handler_event) = EventPair::create();
let (loop_done_sender, _) = mpsc::unbounded::<()>();
let inspector = fuchsia_inspect::Inspector::default();
let fake_handlers_node = inspector.root().create_child("input_handlers_node");
let _ = DisplayWrangler::new(test_event);
let _handler = DisplayOwnership::new_internal(
handler_event,
Some(loop_done_sender),
&fake_handlers_node,
);
diagnostics_assertions::assert_data_tree!(inspector, root: {
input_handlers_node: {
display_ownership: {
events_received_count: 0u64,
events_handled_count: 0u64,
last_received_timestamp_ns: 0u64,
"fuchsia.inspect.Health": {
status: "STARTING_UP",
start_timestamp_nanos: diagnostics_assertions::AnyProperty
},
}
}
});
}
#[fuchsia::test]
async fn display_ownership_inspect_counts_events() {
let (test_event, handler_event) = EventPair::create();
let (test_sender, handler_receiver) = mpsc::unbounded::<InputEvent>();
let (handler_sender, _test_receiver) = mpsc::unbounded::<InputEvent>();
let (loop_done_sender, mut loop_done) = mpsc::unbounded::<()>();
let mut wrangler = DisplayWrangler::new(test_event);
let inspector = fuchsia_inspect::Inspector::default();
let fake_handlers_node = inspector.root().create_child("input_handlers_node");
let handler = DisplayOwnership::new_internal(
handler_event,
Some(loop_done_sender),
&fake_handlers_node,
);
let _task = fasync::Task::local(async move {
handler.handle_input_events(handler_receiver, handler_sender).await.unwrap();
});
wrangler.set_owned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Pressed))
.unwrap();
loop_done.next().await;
wrangler.set_unowned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::B, KeyEventType::Pressed))
.unwrap();
loop_done.next().await;
wrangler.set_owned();
loop_done.next().await;
test_sender
.unbounded_send(new_keyboard_input_event(Key::A, KeyEventType::Released))
.unwrap();
loop_done.next().await;
diagnostics_assertions::assert_data_tree!(inspector, root: {
input_handlers_node: {
display_ownership: {
events_received_count: 3u64,
events_handled_count: 1u64,
last_received_timestamp_ns: 42u64,
"fuchsia.inspect.Health": {
status: "STARTING_UP",
start_timestamp_nanos: diagnostics_assertions::AnyProperty
},
}
}
});
}
}