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