input_pipeline/
input_handler.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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/// An [`InputHandler`] dispatches InputEvents to an external service. It maintains
25/// service connections necessary to handle the events.
26///
27/// For example, an [`ImeInputHandler`] holds a proxy to IME and keyboard services.
28///
29/// [`InputHandler`]s process individual input events through [`handle_input_event()`], which can
30/// produce multiple events as an outcome. If the [`InputHandler`] sends an [`InputEvent`] to a
31/// service that consumes the event, then the [`InputHandler`] updates the [`InputEvent.handled`]
32/// accordingly.
33///
34/// # Notes
35/// * _Callers_ should not invoke [`handle_input_event()`] concurrently since sequences of events
36///   must be preserved. The state created by event n may affect the interpretation of event n+1.
37/// * _Callees_ should avoid blocking unnecessarily, as that prevents `InputEvent`s from
38///   propagating to downstream handlers in a timely manner. See
39///   [further discussion of blocking](https://cs.opensource.google/fuchsia/fuchsia/+/main:src/ui/lib/input_pipeline/docs/coding.md).
40#[async_trait(?Send)]
41pub trait InputHandler: AsRcAny {
42    /// Returns a vector of InputEvents to propagate to the next InputHandler.
43    ///
44    /// * The vector may be empty if, e.g., the handler chose to buffer the
45    ///   event.
46    /// * The vector may have multiple events if, e.g.,
47    ///   * the handler chose to release previously buffered events, or
48    ///   * the handler unpacked a single event into multiple events
49    ///
50    /// # Parameters
51    /// `input_event`: The InputEvent to be handled.
52    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    /// Returns the name of the input handler.
62    fn get_name(&self) -> &'static str;
63
64    /// Returns the types of input events this handler is interested in.
65    fn interest(&self) -> Vec<input_device::InputEventType>;
66}
67
68/// An [`UnhandledInputHandler`] is like an [`InputHandler`], but only deals in unhandled events.
69#[async_trait(?Send)]
70pub trait UnhandledInputHandler: AsRcAny {
71    /// Returns a vector of InputEvents to propagate to the next InputHandler.
72    ///
73    /// * The vector may be empty if, e.g., the handler chose to buffer the
74    ///   event.
75    /// * The vector may have multiple events if, e.g.,
76    ///   * the handler chose to release previously buffered events, or
77    ///   * the handler unpacked a single event into multiple events
78    ///
79    /// # Parameters
80    /// `input_event`: The InputEvent to be handled.
81    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    /// Returns the types of input events this handler is interested in.
93    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    /// A node that contains the state below.
141    pub inspect_node: fuchsia_inspect::Node,
142
143    /// The number of unhandled events received by the handler.
144    events_received_count: fuchsia_inspect::UintProperty,
145
146    /// The number of reports handled by the handler.
147    events_handled_count: fuchsia_inspect::UintProperty,
148
149    /// The event time the last received InputEvent was received.
150    last_received_timestamp_ns: fuchsia_inspect::UintProperty,
151
152    // This node records the health status of the `InputHandler`.
153    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            // No inspect data on FakeUnhandledInputHandler. Do nothing.
238        }
239
240        fn set_handler_unhealthy(self: std::rc::Rc<Self>, _msg: &str) {
241            // No inspect data on FakeUnhandledInputHandler. Do nothing.
242        }
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        // Drop `handler` to dispose of `event_sender`. This ensures
322        // that `event_receiver.next()` does not block.
323        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                            // Timestamp value is unpredictable and not relevant in this context,
407                            // so we only assert that the property is present.
408                            start_timestamp_nanos: diagnostics_assertions::AnyProperty
409                        },
410                    }
411                }
412            }
413        });
414    }
415}