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::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 log::debug!("ConsumerControlsEvent cloned without wake lease.");
39 Self { pressed_buttons: self.pressed_buttons.clone(), wake_lease: None }
40 }
41}
42
43impl PartialEq for ConsumerControlsEvent {
44 fn eq(&self, other: &Self) -> bool {
45 self.pressed_buttons == other.pressed_buttons
46 && self.wake_lease.as_ref().map(|h| h.koid())
47 == other.wake_lease.as_ref().map(|h| h.koid())
48 }
49}
50
51impl Drop for ConsumerControlsEvent {
52 fn drop(&mut self) {
53 log::debug!("ConsumerControlsEvent dropped, had_wake_lease: {:?}", self.wake_lease);
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 clone_with_wake_lease(&self) -> Self {
70 log::debug!("ConsumerControlsEvent cloned with wake lease: {:?}", self.wake_lease);
71 Self {
72 pressed_buttons: self.pressed_buttons.clone(),
73 wake_lease: self.wake_lease.as_ref().map(|lease| {
74 lease
75 .duplicate_handle(zx::Rights::SAME_RIGHTS)
76 .expect("failed to duplicate event pair")
77 }),
78 }
79 }
80
81 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
82 let pressed_buttons_node =
83 node.create_string_array("pressed_buttons", self.pressed_buttons.len());
84 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
85 let button_name: String = match button {
86 ConsumerControlButton::VolumeUp => "volume_up".into(),
87 ConsumerControlButton::VolumeDown => "volume_down".into(),
88 ConsumerControlButton::Pause => "pause".into(),
89 ConsumerControlButton::FactoryReset => "factory_reset".into(),
90 ConsumerControlButton::MicMute => "mic_mute".into(),
91 ConsumerControlButton::Reboot => "reboot".into(),
92 ConsumerControlButton::CameraDisable => "camera_disable".into(),
93 ConsumerControlButton::Power => "power".into(),
94 ConsumerControlButton::Function => "function".into(),
95 unknown_value => {
96 format!("unknown({:?})", unknown_value)
97 }
98 };
99 pressed_buttons_node.set(i, &button_name);
100 });
101 node.record(pressed_buttons_node);
102 }
103}
104
105pub struct ConsumerControlsBinding {
112 event_sender: UnboundedSender<input_device::InputEvent>,
114
115 device_descriptor: ConsumerControlsDeviceDescriptor,
117}
118
119#[derive(Clone, Debug, Eq, PartialEq)]
120pub struct ConsumerControlsDeviceDescriptor {
121 pub buttons: Vec<ConsumerControlButton>,
123 pub device_id: u32,
125}
126
127#[async_trait]
128impl input_device::InputDeviceBinding for ConsumerControlsBinding {
129 fn input_event_sender(&self) -> UnboundedSender<input_device::InputEvent> {
130 self.event_sender.clone()
131 }
132
133 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
134 input_device::InputDeviceDescriptor::ConsumerControls(self.device_descriptor.clone())
135 }
136}
137
138impl ConsumerControlsBinding {
139 pub async fn new(
154 device_proxy: InputDeviceProxy,
155 device_id: u32,
156 input_event_sender: UnboundedSender<input_device::InputEvent>,
157 device_node: fuchsia_inspect::Node,
158 metrics_logger: metrics::MetricsLogger,
159 ) -> Result<Self, Error> {
160 let (device_binding, mut inspect_status) =
161 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
162 inspect_status.health_node.set_ok();
163 input_device::initialize_report_stream(
164 device_proxy,
165 device_binding.get_device_descriptor(),
166 device_binding.input_event_sender(),
167 inspect_status,
168 metrics_logger,
169 Self::process_reports,
170 );
171
172 Ok(device_binding)
173 }
174
175 async fn bind_device(
187 device: &InputDeviceProxy,
188 device_id: u32,
189 input_event_sender: UnboundedSender<input_device::InputEvent>,
190 device_node: fuchsia_inspect::Node,
191 ) -> Result<(Self, InputDeviceStatus), Error> {
192 let mut input_device_status = InputDeviceStatus::new(device_node);
193 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
194 .get_descriptor()
195 .await
196 {
197 Ok(descriptor) => descriptor,
198 Err(_) => {
199 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
200 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
201 }
202 };
203
204 let consumer_controls_descriptor = device_descriptor.consumer_control.ok_or_else(|| {
205 input_device_status
206 .health_node
207 .set_unhealthy("DeviceDescriptor does not have a ConsumerControlDescriptor.");
208 format_err!("DeviceDescriptor does not have a ConsumerControlDescriptor")
209 })?;
210
211 let consumer_controls_input_descriptor =
212 consumer_controls_descriptor.input.ok_or_else(|| {
213 input_device_status.health_node.set_unhealthy(
214 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor.",
215 );
216 format_err!(
217 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor"
218 )
219 })?;
220
221 let device_descriptor: ConsumerControlsDeviceDescriptor =
222 ConsumerControlsDeviceDescriptor {
223 buttons: consumer_controls_input_descriptor.buttons.unwrap_or_default(),
224 device_id,
225 };
226
227 Ok((
228 ConsumerControlsBinding { event_sender: input_event_sender, device_descriptor },
229 input_device_status,
230 ))
231 }
232
233 fn process_reports(
254 reports: Vec<InputReport>,
255 mut previous_report: Option<InputReport>,
256 device_descriptor: &input_device::InputDeviceDescriptor,
257 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
258 inspect_status: &InputDeviceStatus,
259 metrics_logger: &metrics::MetricsLogger,
260 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
261 fuchsia_trace::duration!("input", "consumer-controls-binding-process-report", "num_reports" => reports.len());
262 for report in reports {
263 previous_report = Self::process_report(
264 report,
265 previous_report,
266 device_descriptor,
267 input_event_sender,
268 inspect_status,
269 metrics_logger,
270 );
271 }
272 (previous_report, None)
273 }
274
275 fn process_report(
276 mut report: InputReport,
277 previous_report: Option<InputReport>,
278 device_descriptor: &input_device::InputDeviceDescriptor,
279 input_event_sender: &mut UnboundedSender<input_device::InputEvent>,
280 inspect_status: &InputDeviceStatus,
281 metrics_logger: &metrics::MetricsLogger,
282 ) -> Option<InputReport> {
283 if let Some(trace_id) = report.trace_id {
284 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
285 }
286
287 inspect_status.count_received_report(&report);
288 let pressed_buttons: Vec<ConsumerControlButton> = match report.consumer_control {
290 Some(ref consumer_control_report) => consumer_control_report
291 .pressed_buttons
292 .as_ref()
293 .map(|buttons| buttons.iter().cloned().collect())
294 .unwrap_or_default(),
295 None => {
296 inspect_status.count_filtered_report();
297 return previous_report;
298 }
299 };
300
301 let wake_lease = report.wake_lease.take();
302 let trace_id = fuchsia_trace::Id::random();
303 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
304
305 send_consumer_controls_event(
306 pressed_buttons,
307 wake_lease,
308 device_descriptor,
309 input_event_sender,
310 inspect_status,
311 metrics_logger,
312 trace_id,
313 );
314
315 Some(report)
316 }
317}
318
319fn send_consumer_controls_event(
329 pressed_buttons: Vec<ConsumerControlButton>,
330 wake_lease: Option<zx::EventPair>,
331 device_descriptor: &input_device::InputDeviceDescriptor,
332 sender: &mut UnboundedSender<input_device::InputEvent>,
333 inspect_status: &InputDeviceStatus,
334 metrics_logger: &metrics::MetricsLogger,
335 trace_id: fuchsia_trace::Id,
336) {
337 let event = input_device::InputEvent {
338 device_event: input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
339 pressed_buttons,
340 wake_lease,
341 )),
342 device_descriptor: device_descriptor.clone(),
343 event_time: zx::MonotonicInstant::get(),
344 handled: Handled::No,
345 trace_id: Some(trace_id),
346 };
347
348 match sender.unbounded_send(event.clone_with_wake_lease()) {
349 Err(e) => metrics_logger.log_error(
350 InputPipelineErrorMetricDimensionEvent::ConsumerControlsSendEventFailed,
351 std::format!("Failed to send ConsumerControlsEvent with error: {:?}", e),
352 ),
353 _ => inspect_status.count_generated_event(event),
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360 use crate::testing_utilities;
361 use fuchsia_async as fasync;
362 use futures::StreamExt;
363
364 #[fasync::run_singlethreaded(test)]
367 async fn volume_up_only() {
368 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
369 let pressed_buttons = vec![ConsumerControlButton::VolumeUp];
370 let first_report = testing_utilities::create_consumer_control_input_report(
371 pressed_buttons.clone(),
372 event_time_i64,
373 );
374 let descriptor = testing_utilities::consumer_controls_device_descriptor();
375
376 let input_reports = vec![first_report];
377 let expected_events = vec![testing_utilities::create_consumer_controls_event(
378 pressed_buttons,
379 event_time_u64,
380 &descriptor,
381 )];
382
383 assert_input_report_sequence_generates_events!(
384 input_reports: input_reports,
385 expected_events: expected_events,
386 device_descriptor: descriptor,
387 device_type: ConsumerControlsBinding,
388 );
389 }
390
391 #[fasync::run_singlethreaded(test)]
394 async fn volume_up_and_down() {
395 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
396 let pressed_buttons =
397 vec![ConsumerControlButton::VolumeUp, ConsumerControlButton::VolumeDown];
398 let first_report = testing_utilities::create_consumer_control_input_report(
399 pressed_buttons.clone(),
400 event_time_i64,
401 );
402 let descriptor = testing_utilities::consumer_controls_device_descriptor();
403
404 let input_reports = vec![first_report];
405 let expected_events = vec![testing_utilities::create_consumer_controls_event(
406 pressed_buttons,
407 event_time_u64,
408 &descriptor,
409 )];
410
411 assert_input_report_sequence_generates_events!(
412 input_reports: input_reports,
413 expected_events: expected_events,
414 device_descriptor: descriptor,
415 device_type: ConsumerControlsBinding,
416 );
417 }
418
419 #[fasync::run_singlethreaded(test)]
422 async fn sequence_of_buttons() {
423 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
424 let first_report = testing_utilities::create_consumer_control_input_report(
425 vec![ConsumerControlButton::VolumeUp],
426 event_time_i64,
427 );
428 let second_report = testing_utilities::create_consumer_control_input_report(
429 vec![ConsumerControlButton::VolumeDown],
430 event_time_i64,
431 );
432 let third_report = testing_utilities::create_consumer_control_input_report(
433 vec![ConsumerControlButton::CameraDisable],
434 event_time_i64,
435 );
436 let descriptor = testing_utilities::consumer_controls_device_descriptor();
437
438 let input_reports = vec![first_report, second_report, third_report];
439 let expected_events = vec![
440 testing_utilities::create_consumer_controls_event(
441 vec![ConsumerControlButton::VolumeUp],
442 event_time_u64,
443 &descriptor,
444 ),
445 testing_utilities::create_consumer_controls_event(
446 vec![ConsumerControlButton::VolumeDown],
447 event_time_u64,
448 &descriptor,
449 ),
450 testing_utilities::create_consumer_controls_event(
451 vec![ConsumerControlButton::CameraDisable],
452 event_time_u64,
453 &descriptor,
454 ),
455 ];
456
457 assert_input_report_sequence_generates_events!(
458 input_reports: input_reports,
459 expected_events: expected_events,
460 device_descriptor: descriptor,
461 device_type: ConsumerControlsBinding,
462 );
463 }
464}