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    ///
63    /// The default implementation returns the name of the struct implementing
64    /// the trait.
65    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/// An [`UnhandledInputHandler`] is like an [`InputHandler`], but only deals in unhandled events.
75#[async_trait(?Send)]
76pub trait UnhandledInputHandler: AsRcAny {
77    /// Returns a vector of InputEvents to propagate to the next InputHandler.
78    ///
79    /// * The vector may be empty if, e.g., the handler chose to buffer the
80    ///   event.
81    /// * The vector may have multiple events if, e.g.,
82    ///   * the handler chose to release previously buffered events, or
83    ///   * the handler unpacked a single event into multiple events
84    ///
85    /// # Parameters
86    /// `input_event`: The InputEvent to be handled.
87    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    /// A node that contains the state below.
134    pub inspect_node: fuchsia_inspect::Node,
135
136    /// The number of unhandled events received by the handler.
137    events_received_count: fuchsia_inspect::UintProperty,
138
139    /// The number of reports handled by the handler.
140    events_handled_count: fuchsia_inspect::UintProperty,
141
142    /// The event time the last received InputEvent was received.
143    last_received_timestamp_ns: fuchsia_inspect::UintProperty,
144
145    // This node records the health status of the `InputHandler`.
146    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            // No inspect data on FakeUnhandledInputHandler. Do nothing.
230        }
231
232        fn set_handler_unhealthy(self: std::rc::Rc<Self>, _msg: &str) {
233            // No inspect data on FakeUnhandledInputHandler. Do nothing.
234        }
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        // Drop `handler` to dispose of `event_sender`. This ensures
306        // that `event_receiver.next()` does not block.
307        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                            // Timestamp value is unpredictable and not relevant in this context,
383                            // so we only assert that the property is present.
384                            start_timestamp_nanos: diagnostics_assertions::AnyProperty
385                        },
386                    }
387                }
388            }
389        });
390    }
391}