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