1use crate::input_device;
6use async_trait::async_trait;
7use fuchsia_inspect::health::Reporter;
8use fuchsia_inspect::{NumericProperty, Property};
9use std::any::Any;
10use std::cell::RefCell;
11use std::fmt::{Debug, Formatter};
12use std::rc::Rc;
13
14pub trait AsRcAny {
15 fn as_rc_any(self: Rc<Self>) -> Rc<dyn Any>;
16}
17
18impl<T: Any> AsRcAny for T {
19 fn as_rc_any(self: Rc<Self>) -> Rc<dyn Any> {
20 self
21 }
22}
23
24pub trait Handler: AsRcAny {
25 fn set_handler_healthy(self: std::rc::Rc<Self>);
26
27 fn set_handler_unhealthy(self: std::rc::Rc<Self>, msg: &str);
28
29 fn get_name(&self) -> &'static str;
31
32 fn interest(&self) -> Vec<input_device::InputEventType>;
34}
35
36#[async_trait(?Send)]
53pub trait InputHandler: Handler {
54 async fn handle_input_event(
65 self: std::rc::Rc<Self>,
66 input_event: input_device::InputEvent,
67 ) -> Vec<input_device::InputEvent>;
68}
69
70#[async_trait(?Send)]
72pub trait BatchInputHandler: Handler {
73 async fn handle_input_events(
78 self: std::rc::Rc<Self>,
79 input_events: Vec<input_device::InputEvent>,
80 ) -> Vec<input_device::InputEvent>;
81}
82
83#[async_trait(?Send)]
84impl<T> BatchInputHandler for T
85where
86 T: InputHandler,
87{
88 async fn handle_input_events(
89 self: std::rc::Rc<Self>,
90 input_events: Vec<input_device::InputEvent>,
91 ) -> Vec<input_device::InputEvent> {
92 let mut out_events = Vec::with_capacity(input_events.len());
96 for input_event in input_events {
97 out_events.extend(self.clone().handle_input_event(input_event).await);
98 }
99 out_events
100 }
101}
102
103#[async_trait(?Send)]
105pub trait UnhandledInputHandler: Handler {
106 async fn handle_unhandled_input_event(
117 self: std::rc::Rc<Self>,
118 unhandled_input_event: input_device::UnhandledInputEvent,
119 ) -> Vec<input_device::InputEvent>;
120}
121
122#[async_trait(?Send)]
123impl<T> InputHandler for T
124where
125 T: UnhandledInputHandler,
126{
127 async fn handle_input_event(
128 self: std::rc::Rc<Self>,
129 input_event: input_device::InputEvent,
130 ) -> Vec<input_device::InputEvent> {
131 match input_event.handled {
132 input_device::Handled::Yes => return vec![input_event],
133 input_device::Handled::No => {
134 T::handle_unhandled_input_event(
135 self,
136 input_device::UnhandledInputEvent {
137 device_event: input_event.device_event,
138 device_descriptor: input_event.device_descriptor,
139 event_time: input_event.event_time,
140 trace_id: input_event.trace_id,
141 },
142 )
143 .await
144 }
145 }
146 }
147}
148
149pub struct InputHandlerStatus {
150 pub inspect_node: fuchsia_inspect::Node,
152
153 events_received_count: fuchsia_inspect::UintProperty,
155
156 events_handled_count: fuchsia_inspect::UintProperty,
158
159 last_received_timestamp_ns: fuchsia_inspect::UintProperty,
161
162 pub health_node: RefCell<fuchsia_inspect::health::Node>,
164}
165
166impl PartialEq for InputHandlerStatus {
167 fn eq(&self, other: &Self) -> bool {
168 self.inspect_node == other.inspect_node
169 && self.events_received_count == other.events_received_count
170 && self.events_handled_count == other.events_handled_count
171 && self.last_received_timestamp_ns == other.last_received_timestamp_ns
172 }
173}
174
175impl Debug for InputHandlerStatus {
176 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
177 self.inspect_node.fmt(f)
178 }
179}
180
181impl Default for InputHandlerStatus {
182 fn default() -> Self {
183 let inspector = fuchsia_inspect::Inspector::default();
184 Self::new(&inspector.root(), "default", false)
185 }
186}
187
188impl InputHandlerStatus {
189 pub fn new(node: &fuchsia_inspect::Node, name: &str, _generates_events: bool) -> Self {
190 let handler_node = node.create_child(name);
191 let events_received_count = handler_node.create_uint("events_received_count", 0);
192 let events_handled_count = handler_node.create_uint("events_handled_count", 0);
193 let last_received_timestamp_ns = handler_node.create_uint("last_received_timestamp_ns", 0);
194 let mut health_node = fuchsia_inspect::health::Node::new(&handler_node);
195 health_node.set_starting_up();
196 Self {
197 inspect_node: handler_node,
198 events_received_count: events_received_count,
199 events_handled_count: events_handled_count,
200 last_received_timestamp_ns: last_received_timestamp_ns,
201 health_node: RefCell::new(health_node),
202 }
203 }
204
205 pub fn count_received_event(&self, event_time: &zx::MonotonicInstant) {
206 self.events_received_count.add(1);
207 self.last_received_timestamp_ns.set(event_time.into_nanos().try_into().unwrap());
208 }
209
210 pub fn count_handled_event(&self) {
211 self.events_handled_count.add(1);
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use crate::input_device::{
219 Handled, InputDeviceDescriptor, InputDeviceEvent, InputEvent, InputEventType,
220 UnhandledInputEvent,
221 };
222 use crate::input_handler::InputHandlerStatus;
223
224 use futures::StreamExt as _;
225 use futures::channel::mpsc;
226 use pretty_assertions::assert_eq;
227 use test_case::test_case;
228
229 struct FakeUnhandledInputHandler {
230 event_sender: mpsc::UnboundedSender<UnhandledInputEvent>,
231 mark_events_handled: bool,
232 }
233
234 impl super::Handler for FakeUnhandledInputHandler {
235 fn set_handler_healthy(self: std::rc::Rc<Self>) {
236 }
238
239 fn set_handler_unhealthy(self: std::rc::Rc<Self>, _msg: &str) {
240 }
242
243 fn get_name(&self) -> &'static str {
244 "FakeUnhandledInputHandler"
245 }
246
247 fn interest(&self) -> Vec<InputEventType> {
248 vec![InputEventType::Fake]
249 }
250 }
251
252 #[async_trait(?Send)]
253 impl UnhandledInputHandler for FakeUnhandledInputHandler {
254 async fn handle_unhandled_input_event(
255 self: std::rc::Rc<Self>,
256 unhandled_input_event: UnhandledInputEvent,
257 ) -> Vec<InputEvent> {
258 self.event_sender
259 .unbounded_send(unhandled_input_event.clone())
260 .expect("failed to send");
261 vec![InputEvent::from(unhandled_input_event).into_handled_if(self.mark_events_handled)]
262 }
263 }
264
265 #[fuchsia::test(allow_stalls = false)]
266 async fn blanket_impl_passes_unhandled_events_to_wrapped_handler() {
267 let expected_trace_id: Option<fuchsia_trace::Id> = Some(1234.into());
268 let (event_sender, mut event_receiver) = mpsc::unbounded();
269 let handler = std::rc::Rc::new(FakeUnhandledInputHandler {
270 event_sender,
271 mark_events_handled: false,
272 });
273 handler
274 .clone()
275 .handle_input_event(InputEvent {
276 device_event: InputDeviceEvent::Fake,
277 device_descriptor: InputDeviceDescriptor::Fake,
278 event_time: zx::MonotonicInstant::from_nanos(1),
279 handled: Handled::No,
280 trace_id: expected_trace_id,
281 })
282 .await;
283 assert_eq!(
284 event_receiver.next().await,
285 Some(UnhandledInputEvent {
286 device_event: InputDeviceEvent::Fake,
287 device_descriptor: InputDeviceDescriptor::Fake,
288 event_time: zx::MonotonicInstant::from_nanos(1),
289 trace_id: expected_trace_id,
290 })
291 )
292 }
293
294 #[test_case(false; "not marked by handler")]
295 #[test_case(true; "marked by handler")]
296 #[fuchsia::test(allow_stalls = false)]
297 async fn blanket_impl_propagates_wrapped_handlers_return_value(mark_events_handled: bool) {
298 let (event_sender, _event_receiver) = mpsc::unbounded();
299 let handler =
300 std::rc::Rc::new(FakeUnhandledInputHandler { event_sender, mark_events_handled });
301 let input_event = InputEvent {
302 device_event: InputDeviceEvent::Fake,
303 device_descriptor: InputDeviceDescriptor::Fake,
304 event_time: zx::MonotonicInstant::from_nanos(1),
305 handled: Handled::No,
306 trace_id: None,
307 };
308 let expected_propagated_event = input_event.clone().into_handled_if(mark_events_handled);
309 pretty_assertions::assert_eq!(
310 handler.clone().handle_input_event(input_event).await.as_slice(),
311 [expected_propagated_event]
312 );
313 }
314
315 #[fuchsia::test(allow_stalls = false)]
316 async fn blanket_impl_filters_handled_events_from_wrapped_handler() {
317 let (event_sender, mut event_receiver) = mpsc::unbounded();
318 let handler = std::rc::Rc::new(FakeUnhandledInputHandler {
319 event_sender,
320 mark_events_handled: false,
321 });
322 handler
323 .clone()
324 .handle_input_event(InputEvent {
325 device_event: InputDeviceEvent::Fake,
326 device_descriptor: InputDeviceDescriptor::Fake,
327 event_time: zx::MonotonicInstant::from_nanos(1),
328 handled: Handled::Yes,
329 trace_id: None,
330 })
331 .await;
332
333 std::mem::drop(handler);
336
337 assert_eq!(event_receiver.next().await, None)
338 }
339
340 #[fuchsia::test(allow_stalls = false)]
341 async fn blanket_impl_propagates_handled_events_to_next_handler() {
342 let (event_sender, _event_receiver) = mpsc::unbounded();
343 let handler = std::rc::Rc::new(FakeUnhandledInputHandler {
344 event_sender,
345 mark_events_handled: false,
346 });
347 assert_eq!(
348 handler
349 .clone()
350 .handle_input_event(InputEvent {
351 device_event: InputDeviceEvent::Fake,
352 device_descriptor: InputDeviceDescriptor::Fake,
353 event_time: zx::MonotonicInstant::from_nanos(1),
354 handled: Handled::Yes,
355 trace_id: None,
356 })
357 .await
358 .as_slice(),
359 [InputEvent {
360 device_event: InputDeviceEvent::Fake,
361 device_descriptor: InputDeviceDescriptor::Fake,
362 event_time: zx::MonotonicInstant::from_nanos(1),
363 handled: Handled::Yes,
364 trace_id: None,
365 }]
366 );
367 }
368
369 #[fuchsia::test]
370 fn get_name() {
371 struct NeuralInputHandler {}
372 impl super::Handler for NeuralInputHandler {
373 fn set_handler_healthy(self: std::rc::Rc<Self>) {
374 unimplemented!()
375 }
376
377 fn set_handler_unhealthy(self: std::rc::Rc<Self>, _msg: &str) {
378 unimplemented!()
379 }
380
381 fn get_name(&self) -> &'static str {
382 "NeuralInputHandler"
383 }
384
385 fn interest(&self) -> Vec<InputEventType> {
386 vec![InputEventType::Fake]
387 }
388 }
389
390 #[async_trait(?Send)]
391 impl InputHandler for NeuralInputHandler {
392 async fn handle_input_event(
393 self: std::rc::Rc<Self>,
394 _input_event: InputEvent,
395 ) -> Vec<InputEvent> {
396 unimplemented!()
397 }
398 }
399
400 let handler = std::rc::Rc::new(NeuralInputHandler {});
401 assert_eq!(handler.get_name(), "NeuralInputHandler");
402 }
403
404 #[fuchsia::test]
405 async fn input_handler_status_initialized_with_correct_properties() {
406 let inspector = fuchsia_inspect::Inspector::default();
407 let input_pipeline_node = inspector.root().create_child("input_pipeline");
408 let input_handlers_node = input_pipeline_node.create_child("input_handlers");
409 let _input_handler_status =
410 InputHandlerStatus::new(&input_handlers_node, "test_handler", false);
411 diagnostics_assertions::assert_data_tree!(inspector, root: {
412 input_pipeline: {
413 input_handlers: {
414 test_handler: {
415 events_received_count: 0u64,
416 events_handled_count: 0u64,
417 last_received_timestamp_ns: 0u64,
418 "fuchsia.inspect.Health": {
419 status: "STARTING_UP",
420 start_timestamp_nanos: diagnostics_assertions::AnyProperty
423 },
424 }
425 }
426 }
427 });
428 }
429}