1use 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#[derive(Clone, Debug, PartialEq)]
30pub struct ConsumerControlsEvent {
31 pub pressed_buttons: Vec<ConsumerControlButton>,
32}
33
34impl ConsumerControlsEvent {
35 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
67pub struct ConsumerControlsBinding {
74 event_sender: UnboundedSender<input_device::InputEvent>,
76
77 device_descriptor: ConsumerControlsDeviceDescriptor,
79}
80
81#[derive(Clone, Debug, Eq, PartialEq)]
82pub struct ConsumerControlsDeviceDescriptor {
83 pub buttons: Vec<ConsumerControlButton>,
85 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 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 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 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 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
258fn 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 #[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 #[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 #[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}