input_pipeline/
consumer_controls_binding.rs

1// Copyright 2021 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::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::metrics;
7use anyhow::{format_err, Error};
8use async_trait::async_trait;
9use fidl_fuchsia_input_report::{
10    self as fidl_input_report, ConsumerControlButton, InputDeviceProxy, InputReport,
11};
12use fuchsia_inspect::health::Reporter;
13use fuchsia_inspect::ArrayProperty;
14
15use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
16use metrics_registry::*;
17
18/// A [`ConsumerControlsEvent`] represents an event where one or more consumer control buttons
19/// were pressed.
20///
21/// # Example
22/// The following ConsumerControlsEvents represents an event where the volume up button was pressed.
23///
24/// ```
25/// let volume_event = input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
26///     vec![ConsumerControlButton::VOLUME_UP],
27/// ));
28/// ```
29#[derive(Clone, Debug, PartialEq)]
30pub struct ConsumerControlsEvent {
31    pub pressed_buttons: Vec<ConsumerControlButton>,
32}
33
34impl ConsumerControlsEvent {
35    /// Creates a new [`ConsumerControlsEvent`] with the relevant buttons.
36    ///
37    /// # Parameters
38    /// - `pressed_buttons`: The buttons relevant to this event.
39    pub fn new(pressed_buttons: Vec<ConsumerControlButton>) -> Self {
40        Self { pressed_buttons }
41    }
42
43    pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
44        let pressed_buttons_node =
45            node.create_string_array("pressed_buttons", self.pressed_buttons.len());
46        self.pressed_buttons.iter().enumerate().for_each(|(i, &ref button)| {
47            let button_name: String = match button {
48                ConsumerControlButton::VolumeUp => "volume_up".into(),
49                ConsumerControlButton::VolumeDown => "volume_down".into(),
50                ConsumerControlButton::Pause => "pause".into(),
51                ConsumerControlButton::FactoryReset => "factory_reset".into(),
52                ConsumerControlButton::MicMute => "mic_mute".into(),
53                ConsumerControlButton::Reboot => "reboot".into(),
54                ConsumerControlButton::CameraDisable => "camera_disable".into(),
55                ConsumerControlButton::Power => "power".into(),
56                ConsumerControlButton::Function => "function".into(),
57                unknown_value => {
58                    format!("unknown({:?})", unknown_value)
59                }
60            };
61            pressed_buttons_node.set(i, &button_name);
62        });
63        node.record(pressed_buttons_node);
64    }
65}
66
67/// A [`ConsumerControlsBinding`] represents a connection to a consumer controls input device with
68/// consumer controls. The buttons supported by this binding is returned by `supported_buttons()`.
69///
70/// The [`ConsumerControlsBinding`] parses and exposes consumer control descriptor properties
71/// for the device it is associated with. It also parses [`InputReport`]s
72/// from the device, and sends them to the device binding owner over `event_sender`.
73pub struct ConsumerControlsBinding {
74    /// The channel to stream InputEvents to.
75    event_sender: UnboundedSender<input_device::InputEvent>,
76
77    /// Holds information about this device.
78    device_descriptor: ConsumerControlsDeviceDescriptor,
79}
80
81#[derive(Clone, Debug, Eq, PartialEq)]
82pub struct ConsumerControlsDeviceDescriptor {
83    /// The list of buttons that this device contains.
84    pub buttons: Vec<ConsumerControlButton>,
85    /// Identifies the device originating this event.
86    pub device_id: u32,
87}
88
89#[async_trait]
90impl input_device::InputDeviceBinding for ConsumerControlsBinding {
91    fn input_event_sender(&self) -> UnboundedSender<input_device::InputEvent> {
92        self.event_sender.clone()
93    }
94
95    fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
96        input_device::InputDeviceDescriptor::ConsumerControls(self.device_descriptor.clone())
97    }
98}
99
100impl ConsumerControlsBinding {
101    /// Creates a new [`InputDeviceBinding`] from the `device_proxy`.
102    ///
103    /// The binding will start listening for input reports immediately and send new InputEvents
104    /// to the device binding owner over `input_event_sender`.
105    ///
106    /// # Parameters
107    /// - `device_proxy`: The proxy to bind the new [`InputDeviceBinding`] to.
108    /// - `device_id`: The id of the connected device.
109    /// - `input_event_sender`: The channel to send new InputEvents to.
110    /// - `device_node`: The inspect node for this device binding
111    /// - `metrics_logger`: The metrics logger.
112    ///
113    /// # Errors
114    /// If there was an error binding to the proxy.
115    pub async fn new(
116        device_proxy: InputDeviceProxy,
117        device_id: u32,
118        input_event_sender: UnboundedSender<input_device::InputEvent>,
119        device_node: fuchsia_inspect::Node,
120        metrics_logger: metrics::MetricsLogger,
121    ) -> Result<Self, Error> {
122        let (device_binding, mut inspect_status) =
123            Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
124        inspect_status.health_node.set_ok();
125        input_device::initialize_report_stream(
126            device_proxy,
127            device_binding.get_device_descriptor(),
128            device_binding.input_event_sender(),
129            inspect_status,
130            metrics_logger,
131            Self::process_reports,
132        );
133
134        Ok(device_binding)
135    }
136
137    /// Binds the provided input device to a new instance of `Self`.
138    ///
139    /// # Parameters
140    /// - `device`: The device to use to initialize the binding.
141    /// - `device_id`: The id of the connected device.
142    /// - `input_event_sender`: The channel to send new InputEvents to.
143    /// - `device_node`: The inspect node for this device binding
144    ///
145    /// # Errors
146    /// If the device descriptor could not be retrieved, or the descriptor could
147    /// not be parsed correctly.
148    async fn bind_device(
149        device: &InputDeviceProxy,
150        device_id: u32,
151        input_event_sender: UnboundedSender<input_device::InputEvent>,
152        device_node: fuchsia_inspect::Node,
153    ) -> Result<(Self, InputDeviceStatus), Error> {
154        let mut input_device_status = InputDeviceStatus::new(device_node);
155        let device_descriptor: fidl_input_report::DeviceDescriptor = match device
156            .get_descriptor()
157            .await
158        {
159            Ok(descriptor) => descriptor,
160            Err(_) => {
161                input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
162                return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
163            }
164        };
165
166        let consumer_controls_descriptor = device_descriptor.consumer_control.ok_or_else(|| {
167            input_device_status
168                .health_node
169                .set_unhealthy("DeviceDescriptor does not have a ConsumerControlDescriptor.");
170            format_err!("DeviceDescriptor does not have a ConsumerControlDescriptor")
171        })?;
172
173        let consumer_controls_input_descriptor =
174            consumer_controls_descriptor.input.ok_or_else(|| {
175                input_device_status.health_node.set_unhealthy(
176                    "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor.",
177                );
178                format_err!(
179                    "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor"
180                )
181            })?;
182
183        let device_descriptor: ConsumerControlsDeviceDescriptor =
184            ConsumerControlsDeviceDescriptor {
185                buttons: consumer_controls_input_descriptor.buttons.unwrap_or_default(),
186                device_id,
187            };
188
189        Ok((
190            ConsumerControlsBinding { event_sender: input_event_sender, device_descriptor },
191            input_device_status,
192        ))
193    }
194
195    /// Parses an [`InputReport`] into one or more [`InputEvent`]s. Sends the [`InputEvent`]s
196    /// to the device binding owner via [`input_event_sender`].
197    ///
198    /// # Parameters
199    /// `report`: The incoming [`InputReport`].
200    /// `previous_report`: The previous [`InputReport`] seen for the same device. This can be
201    ///                    used to determine, for example, which keys are no longer present in
202    ///                    a keyboard report to generate key released events. If `None`, no
203    ///                    previous report was found.
204    /// `device_descriptor`: The descriptor for the input device generating the input reports.
205    /// `input_event_sender`: The sender for the device binding's input event stream.
206    /// `metrics_logger`: The metrics logger.
207    ///
208    ///
209    /// # Returns
210    /// An [`InputReport`] which will be passed to the next call to [`process_reports`], as
211    /// [`previous_report`]. If `None`, the next call's [`previous_report`] will be `None`.
212    /// A [`UnboundedReceiver<InputEvent>`] which will poll asynchronously generated events to be
213    /// recorded by `inspect_status` in `input_device::initialize_report_stream()`. If device
214    /// binding does not generate InputEvents asynchronously, this will be `None`.
215    fn process_reports(
216        report: InputReport,
217        previous_report: Option<InputReport>,
218        device_descriptor: &input_device::InputDeviceDescriptor,
219        input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
220        inspect_status: &InputDeviceStatus,
221        metrics_logger: &metrics::MetricsLogger,
222    ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
223        fuchsia_trace::duration!(c"input", c"consumer-controls-binding-process-report");
224        if let Some(trace_id) = report.trace_id {
225            fuchsia_trace::flow_end!(c"input", c"input_report", trace_id.into());
226        }
227
228        inspect_status.count_received_report(&report);
229        // Input devices can have multiple types so ensure `report` is a ConsumerControlInputReport.
230        let pressed_buttons: Vec<ConsumerControlButton> = match report.consumer_control {
231            Some(ref consumer_control_report) => consumer_control_report
232                .pressed_buttons
233                .as_ref()
234                .map(|buttons| buttons.iter().cloned().collect())
235                .unwrap_or_default(),
236            None => {
237                inspect_status.count_filtered_report();
238                return (previous_report, None);
239            }
240        };
241
242        let trace_id = fuchsia_trace::Id::random();
243        fuchsia_trace::flow_begin!(c"input", c"event_in_input_pipeline", trace_id);
244
245        send_consumer_controls_event(
246            pressed_buttons,
247            device_descriptor,
248            input_event_sender,
249            inspect_status,
250            metrics_logger,
251            trace_id,
252        );
253
254        (Some(report), None)
255    }
256}
257
258/// Sends an InputEvent over `sender`.
259///
260/// # Parameters
261/// - `pressed_buttons`: The buttons relevant to the event.
262/// - `device_descriptor`: The descriptor for the input device generating the input reports.
263/// - `sender`: The stream to send the InputEvent to.
264/// - `metrics_logger`: The metrics logger.
265/// - `trace_id`: The trace_id of this button event.
266fn send_consumer_controls_event(
267    pressed_buttons: Vec<ConsumerControlButton>,
268    device_descriptor: &input_device::InputDeviceDescriptor,
269    sender: &mut UnboundedSender<input_device::InputEvent>,
270    inspect_status: &InputDeviceStatus,
271    metrics_logger: &metrics::MetricsLogger,
272    trace_id: fuchsia_trace::Id,
273) {
274    let event = input_device::InputEvent {
275        device_event: input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
276            pressed_buttons,
277        )),
278        device_descriptor: device_descriptor.clone(),
279        event_time: zx::MonotonicInstant::get(),
280        handled: Handled::No,
281        trace_id: Some(trace_id),
282    };
283
284    match sender.unbounded_send(event.clone()) {
285        Err(e) => metrics_logger.log_error(
286            InputPipelineErrorMetricDimensionEvent::ConsumerControlsSendEventFailed,
287            std::format!("Failed to send ConsumerControlsEvent with error: {:?}", e),
288        ),
289        _ => inspect_status.count_generated_event(event),
290    }
291}
292
293#[cfg(test)]
294mod tests {
295    use super::*;
296    use crate::testing_utilities;
297    use fuchsia_async as fasync;
298    use futures::StreamExt;
299
300    // Tests that an InputReport containing one consumer control button generates an InputEvent
301    // containing the same consumer control button.
302    #[fasync::run_singlethreaded(test)]
303    async fn volume_up_only() {
304        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
305        let pressed_buttons = vec![ConsumerControlButton::VolumeUp];
306        let first_report = testing_utilities::create_consumer_control_input_report(
307            pressed_buttons.clone(),
308            event_time_i64,
309        );
310        let descriptor = testing_utilities::consumer_controls_device_descriptor();
311
312        let input_reports = vec![first_report];
313        let expected_events = vec![testing_utilities::create_consumer_controls_event(
314            pressed_buttons,
315            event_time_u64,
316            &descriptor,
317        )];
318
319        assert_input_report_sequence_generates_events!(
320            input_reports: input_reports,
321            expected_events: expected_events,
322            device_descriptor: descriptor,
323            device_type: ConsumerControlsBinding,
324        );
325    }
326
327    // Tests that an InputReport containing two consumer control buttons generates an InputEvent
328    // containing both consumer control buttons.
329    #[fasync::run_singlethreaded(test)]
330    async fn volume_up_and_down() {
331        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
332        let pressed_buttons =
333            vec![ConsumerControlButton::VolumeUp, ConsumerControlButton::VolumeDown];
334        let first_report = testing_utilities::create_consumer_control_input_report(
335            pressed_buttons.clone(),
336            event_time_i64,
337        );
338        let descriptor = testing_utilities::consumer_controls_device_descriptor();
339
340        let input_reports = vec![first_report];
341        let expected_events = vec![testing_utilities::create_consumer_controls_event(
342            pressed_buttons,
343            event_time_u64,
344            &descriptor,
345        )];
346
347        assert_input_report_sequence_generates_events!(
348            input_reports: input_reports,
349            expected_events: expected_events,
350            device_descriptor: descriptor,
351            device_type: ConsumerControlsBinding,
352        );
353    }
354
355    // Tests that three InputReports containing one consumer control button generates three
356    // InputEvents containing the same consumer control button.
357    #[fasync::run_singlethreaded(test)]
358    async fn sequence_of_buttons() {
359        let (event_time_i64, event_time_u64) = testing_utilities::event_times();
360        let first_report = testing_utilities::create_consumer_control_input_report(
361            vec![ConsumerControlButton::VolumeUp],
362            event_time_i64,
363        );
364        let second_report = testing_utilities::create_consumer_control_input_report(
365            vec![ConsumerControlButton::VolumeDown],
366            event_time_i64,
367        );
368        let third_report = testing_utilities::create_consumer_control_input_report(
369            vec![ConsumerControlButton::CameraDisable],
370            event_time_i64,
371        );
372        let descriptor = testing_utilities::consumer_controls_device_descriptor();
373
374        let input_reports = vec![first_report, second_report, third_report];
375        let expected_events = vec![
376            testing_utilities::create_consumer_controls_event(
377                vec![ConsumerControlButton::VolumeUp],
378                event_time_u64,
379                &descriptor,
380            ),
381            testing_utilities::create_consumer_controls_event(
382                vec![ConsumerControlButton::VolumeDown],
383                event_time_u64,
384                &descriptor,
385            ),
386            testing_utilities::create_consumer_controls_event(
387                vec![ConsumerControlButton::CameraDisable],
388                event_time_u64,
389                &descriptor,
390            ),
391        ];
392
393        assert_input_report_sequence_generates_events!(
394            input_reports: input_reports,
395            expected_events: expected_events,
396            device_descriptor: descriptor,
397            device_type: ConsumerControlsBinding,
398        );
399    }
400}