1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::metrics;
7use anyhow::{Error, format_err};
8use async_trait::async_trait;
9use fidl_fuchsia_input_report::{
10 self as fidl_input_report, ConsumerControlButton, InputDeviceProxy, InputReport,
11};
12use fuchsia_inspect::ArrayProperty;
13use fuchsia_inspect::health::Reporter;
14
15use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
16use metrics_registry::*;
17use zx::{AsHandleRef, HandleBased};
18
19#[derive(Debug)]
31pub struct ConsumerControlsEvent {
32 pub pressed_buttons: Vec<ConsumerControlButton>,
33 pub wake_lease: Option<zx::EventPair>,
34}
35
36impl Clone for ConsumerControlsEvent {
37 fn clone(&self) -> Self {
38 Self {
39 pressed_buttons: self.pressed_buttons.clone(),
40 wake_lease: self.wake_lease.as_ref().map(|lease| {
41 lease
42 .duplicate_handle(zx::Rights::SAME_RIGHTS)
43 .expect("failed to duplicate event pair")
44 }),
45 }
46 }
47}
48
49impl PartialEq for ConsumerControlsEvent {
50 fn eq(&self, other: &Self) -> bool {
51 self.pressed_buttons == other.pressed_buttons
52 && self.wake_lease.as_ref().map(|h| h.get_koid())
53 == other.wake_lease.as_ref().map(|h| h.get_koid())
54 }
55}
56
57impl ConsumerControlsEvent {
58 pub fn new(
63 pressed_buttons: Vec<ConsumerControlButton>,
64 wake_lease: Option<zx::EventPair>,
65 ) -> Self {
66 Self { pressed_buttons, wake_lease }
67 }
68
69 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
70 let pressed_buttons_node =
71 node.create_string_array("pressed_buttons", self.pressed_buttons.len());
72 self.pressed_buttons.iter().enumerate().for_each(|(i, &ref button)| {
73 let button_name: String = match button {
74 ConsumerControlButton::VolumeUp => "volume_up".into(),
75 ConsumerControlButton::VolumeDown => "volume_down".into(),
76 ConsumerControlButton::Pause => "pause".into(),
77 ConsumerControlButton::FactoryReset => "factory_reset".into(),
78 ConsumerControlButton::MicMute => "mic_mute".into(),
79 ConsumerControlButton::Reboot => "reboot".into(),
80 ConsumerControlButton::CameraDisable => "camera_disable".into(),
81 ConsumerControlButton::Power => "power".into(),
82 ConsumerControlButton::Function => "function".into(),
83 unknown_value => {
84 format!("unknown({:?})", unknown_value)
85 }
86 };
87 pressed_buttons_node.set(i, &button_name);
88 });
89 node.record(pressed_buttons_node);
90 }
91}
92
93pub struct ConsumerControlsBinding {
100 event_sender: UnboundedSender<input_device::InputEvent>,
102
103 device_descriptor: ConsumerControlsDeviceDescriptor,
105}
106
107#[derive(Clone, Debug, Eq, PartialEq)]
108pub struct ConsumerControlsDeviceDescriptor {
109 pub buttons: Vec<ConsumerControlButton>,
111 pub device_id: u32,
113}
114
115#[async_trait]
116impl input_device::InputDeviceBinding for ConsumerControlsBinding {
117 fn input_event_sender(&self) -> UnboundedSender<input_device::InputEvent> {
118 self.event_sender.clone()
119 }
120
121 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
122 input_device::InputDeviceDescriptor::ConsumerControls(self.device_descriptor.clone())
123 }
124}
125
126impl ConsumerControlsBinding {
127 pub async fn new(
142 device_proxy: InputDeviceProxy,
143 device_id: u32,
144 input_event_sender: UnboundedSender<input_device::InputEvent>,
145 device_node: fuchsia_inspect::Node,
146 metrics_logger: metrics::MetricsLogger,
147 ) -> Result<Self, Error> {
148 let (device_binding, mut inspect_status) =
149 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
150 inspect_status.health_node.set_ok();
151 input_device::initialize_report_stream(
152 device_proxy,
153 device_binding.get_device_descriptor(),
154 device_binding.input_event_sender(),
155 inspect_status,
156 metrics_logger,
157 Self::process_reports,
158 );
159
160 Ok(device_binding)
161 }
162
163 async fn bind_device(
175 device: &InputDeviceProxy,
176 device_id: u32,
177 input_event_sender: UnboundedSender<input_device::InputEvent>,
178 device_node: fuchsia_inspect::Node,
179 ) -> Result<(Self, InputDeviceStatus), Error> {
180 let mut input_device_status = InputDeviceStatus::new(device_node);
181 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
182 .get_descriptor()
183 .await
184 {
185 Ok(descriptor) => descriptor,
186 Err(_) => {
187 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
188 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
189 }
190 };
191
192 let consumer_controls_descriptor = device_descriptor.consumer_control.ok_or_else(|| {
193 input_device_status
194 .health_node
195 .set_unhealthy("DeviceDescriptor does not have a ConsumerControlDescriptor.");
196 format_err!("DeviceDescriptor does not have a ConsumerControlDescriptor")
197 })?;
198
199 let consumer_controls_input_descriptor =
200 consumer_controls_descriptor.input.ok_or_else(|| {
201 input_device_status.health_node.set_unhealthy(
202 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor.",
203 );
204 format_err!(
205 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor"
206 )
207 })?;
208
209 let device_descriptor: ConsumerControlsDeviceDescriptor =
210 ConsumerControlsDeviceDescriptor {
211 buttons: consumer_controls_input_descriptor.buttons.unwrap_or_default(),
212 device_id,
213 };
214
215 Ok((
216 ConsumerControlsBinding { event_sender: input_event_sender, device_descriptor },
217 input_device_status,
218 ))
219 }
220
221 fn process_reports(
242 mut report: InputReport,
243 previous_report: Option<InputReport>,
244 device_descriptor: &input_device::InputDeviceDescriptor,
245 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
246 inspect_status: &InputDeviceStatus,
247 metrics_logger: &metrics::MetricsLogger,
248 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
249 fuchsia_trace::duration!(c"input", c"consumer-controls-binding-process-report");
250 if let Some(trace_id) = report.trace_id {
251 fuchsia_trace::flow_end!(c"input", c"input_report", trace_id.into());
252 }
253
254 inspect_status.count_received_report(&report);
255 let pressed_buttons: Vec<ConsumerControlButton> = match report.consumer_control {
257 Some(ref consumer_control_report) => consumer_control_report
258 .pressed_buttons
259 .as_ref()
260 .map(|buttons| buttons.iter().cloned().collect())
261 .unwrap_or_default(),
262 None => {
263 inspect_status.count_filtered_report();
264 return (previous_report, None);
265 }
266 };
267
268 let wake_lease = report.wake_lease.take();
269 let trace_id = fuchsia_trace::Id::random();
270 fuchsia_trace::flow_begin!(c"input", c"event_in_input_pipeline", trace_id);
271
272 send_consumer_controls_event(
273 pressed_buttons,
274 wake_lease,
275 device_descriptor,
276 input_event_sender,
277 inspect_status,
278 metrics_logger,
279 trace_id,
280 );
281
282 (Some(report), None)
283 }
284}
285
286fn send_consumer_controls_event(
296 pressed_buttons: Vec<ConsumerControlButton>,
297 wake_lease: Option<zx::EventPair>,
298 device_descriptor: &input_device::InputDeviceDescriptor,
299 sender: &mut UnboundedSender<input_device::InputEvent>,
300 inspect_status: &InputDeviceStatus,
301 metrics_logger: &metrics::MetricsLogger,
302 trace_id: fuchsia_trace::Id,
303) {
304 let event = input_device::InputEvent {
305 device_event: input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
306 pressed_buttons,
307 wake_lease,
308 )),
309 device_descriptor: device_descriptor.clone(),
310 event_time: zx::MonotonicInstant::get(),
311 handled: Handled::No,
312 trace_id: Some(trace_id),
313 };
314
315 match sender.unbounded_send(event.clone()) {
316 Err(e) => metrics_logger.log_error(
317 InputPipelineErrorMetricDimensionEvent::ConsumerControlsSendEventFailed,
318 std::format!("Failed to send ConsumerControlsEvent with error: {:?}", e),
319 ),
320 _ => inspect_status.count_generated_event(event),
321 }
322}
323
324#[cfg(test)]
325mod tests {
326 use super::*;
327 use crate::testing_utilities;
328 use fuchsia_async as fasync;
329 use futures::StreamExt;
330
331 #[fasync::run_singlethreaded(test)]
334 async fn volume_up_only() {
335 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
336 let pressed_buttons = vec![ConsumerControlButton::VolumeUp];
337 let first_report = testing_utilities::create_consumer_control_input_report(
338 pressed_buttons.clone(),
339 event_time_i64,
340 );
341 let descriptor = testing_utilities::consumer_controls_device_descriptor();
342
343 let input_reports = vec![first_report];
344 let expected_events = vec![testing_utilities::create_consumer_controls_event(
345 pressed_buttons,
346 event_time_u64,
347 &descriptor,
348 )];
349
350 assert_input_report_sequence_generates_events!(
351 input_reports: input_reports,
352 expected_events: expected_events,
353 device_descriptor: descriptor,
354 device_type: ConsumerControlsBinding,
355 );
356 }
357
358 #[fasync::run_singlethreaded(test)]
361 async fn volume_up_and_down() {
362 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
363 let pressed_buttons =
364 vec![ConsumerControlButton::VolumeUp, ConsumerControlButton::VolumeDown];
365 let first_report = testing_utilities::create_consumer_control_input_report(
366 pressed_buttons.clone(),
367 event_time_i64,
368 );
369 let descriptor = testing_utilities::consumer_controls_device_descriptor();
370
371 let input_reports = vec![first_report];
372 let expected_events = vec![testing_utilities::create_consumer_controls_event(
373 pressed_buttons,
374 event_time_u64,
375 &descriptor,
376 )];
377
378 assert_input_report_sequence_generates_events!(
379 input_reports: input_reports,
380 expected_events: expected_events,
381 device_descriptor: descriptor,
382 device_type: ConsumerControlsBinding,
383 );
384 }
385
386 #[fasync::run_singlethreaded(test)]
389 async fn sequence_of_buttons() {
390 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
391 let first_report = testing_utilities::create_consumer_control_input_report(
392 vec![ConsumerControlButton::VolumeUp],
393 event_time_i64,
394 );
395 let second_report = testing_utilities::create_consumer_control_input_report(
396 vec![ConsumerControlButton::VolumeDown],
397 event_time_i64,
398 );
399 let third_report = testing_utilities::create_consumer_control_input_report(
400 vec![ConsumerControlButton::CameraDisable],
401 event_time_i64,
402 );
403 let descriptor = testing_utilities::consumer_controls_device_descriptor();
404
405 let input_reports = vec![first_report, second_report, third_report];
406 let expected_events = vec![
407 testing_utilities::create_consumer_controls_event(
408 vec![ConsumerControlButton::VolumeUp],
409 event_time_u64,
410 &descriptor,
411 ),
412 testing_utilities::create_consumer_controls_event(
413 vec![ConsumerControlButton::VolumeDown],
414 event_time_u64,
415 &descriptor,
416 ),
417 testing_utilities::create_consumer_controls_event(
418 vec![ConsumerControlButton::CameraDisable],
419 event_time_u64,
420 &descriptor,
421 ),
422 ];
423
424 assert_input_report_sequence_generates_events!(
425 input_reports: input_reports,
426 expected_events: expected_events,
427 device_descriptor: descriptor,
428 device_type: ConsumerControlsBinding,
429 );
430 }
431}