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
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    /// Returns the name of the input handler.
30    fn get_name(&self) -> &'static str;
31
32    /// Returns the types of input events this handler is interested in.
33    fn interest(&self) -> Vec<input_device::InputEventType>;
34}
35
36/// An [`InputHandler`] dispatches InputEvents to an external service. It maintains
37/// service connections necessary to handle the events.
38///
39/// For example, an [`ImeInputHandler`] holds a proxy to IME and keyboard services.
40///
41/// [`InputHandler`]s process individual input events through [`handle_input_event()`], which can
42/// produce multiple events as an outcome. If the [`InputHandler`] sends an [`InputEvent`] to a
43/// service that consumes the event, then the [`InputHandler`] updates the [`InputEvent.handled`]
44/// accordingly.
45///
46/// # Notes
47/// * _Callers_ should not invoke [`handle_input_event()`] concurrently since sequences of events
48///   must be preserved. The state created by event n may affect the interpretation of event n+1.
49/// * _Callees_ should avoid blocking unnecessarily, as that prevents `InputEvent`s from
50///   propagating to downstream handlers in a timely manner. See
51///   [further discussion of blocking](https://cs.opensource.google/fuchsia/fuchsia/+/main:src/ui/lib/input_pipeline/docs/coding.md).
52#[async_trait(?Send)]
53pub trait InputHandler: Handler {
54    /// Returns a vector of InputEvents to propagate to the next InputHandler.
55    ///
56    /// * The vector may be empty if, e.g., the handler chose to buffer the
57    ///   event.
58    /// * The vector may have multiple events if, e.g.,
59    ///   * the handler chose to release previously buffered events, or
60    ///   * the handler unpacked a single event into multiple events
61    ///
62    /// # Parameters
63    /// `input_event`: The InputEvent to be handled.
64    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/// A [`BatchInputHandler`] dispatches multiple InputEvents to an external service.
71#[async_trait(?Send)]
72pub trait BatchInputHandler: Handler {
73    /// Returns a vector of InputEvents to propagate to the next InputHandler.
74    ///
75    /// # Parameters
76    /// `input_events`: The InputEvents to be handled.
77    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        // Pre-allocate the output vector to avoid reallocations when the handler generates
93        // the same number of events or fewer. It will still reallocate if the handler
94        // produces more events.
95        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/// An [`UnhandledInputHandler`] is like an [`InputHandler`], but only deals in unhandled events.
104#[async_trait(?Send)]
105pub trait UnhandledInputHandler: Handler {
106    /// Returns a vector of InputEvents to propagate to the next InputHandler.
107    ///
108    /// * The vector may be empty if, e.g., the handler chose to buffer the
109    ///   event.
110    /// * The vector may have multiple events if, e.g.,
111    ///   * the handler chose to release previously buffered events, or
112    ///   * the handler unpacked a single event into multiple events
113    ///
114    /// # Parameters
115    /// `input_event`: The InputEvent to be handled.
116    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    /// A node that contains the state below.
151    pub inspect_node: fuchsia_inspect::Node,
152
153    /// The number of unhandled events received by the handler.
154    events_received_count: fuchsia_inspect::UintProperty,
155
156    /// The number of reports handled by the handler.
157    events_handled_count: fuchsia_inspect::UintProperty,
158
159    /// The event time the last received InputEvent was received.
160    last_received_timestamp_ns: fuchsia_inspect::UintProperty,
161
162    // This node records the health status of the `InputHandler`.
163    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            // No inspect data on FakeUnhandledInputHandler. Do nothing.
237        }
238
239        fn set_handler_unhealthy(self: std::rc::Rc<Self>, _msg: &str) {
240            // No inspect data on FakeUnhandledInputHandler. Do nothing.
241        }
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        // Drop `handler` to dispose of `event_sender`. This ensures
334        // that `event_receiver.next()` does not block.
335        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                            // Timestamp value is unpredictable and not relevant in this context,
421                            // so we only assert that the property is present.
422                            start_timestamp_nanos: diagnostics_assertions::AnyProperty
423                        },
424                    }
425                }
426            }
427        });
428    }
429}