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<Vec<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<Vec<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<Vec<InputEvent>>,
157 device_node: fuchsia_inspect::Node,
158 feature_flags: input_device::InputPipelineFeatureFlags,
159 metrics_logger: metrics::MetricsLogger,
160 ) -> Result<Self, Error> {
161 let (device_binding, mut inspect_status) =
162 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
163 inspect_status.health_node.set_ok();
164 input_device::initialize_report_stream(
165 device_proxy,
166 device_binding.get_device_descriptor(),
167 device_binding.input_event_sender(),
168 inspect_status,
169 metrics_logger,
170 feature_flags,
171 Self::process_reports,
172 );
173
174 Ok(device_binding)
175 }
176
177 async fn bind_device(
189 device: &InputDeviceProxy,
190 device_id: u32,
191 input_event_sender: UnboundedSender<Vec<InputEvent>>,
192 device_node: fuchsia_inspect::Node,
193 ) -> Result<(Self, InputDeviceStatus), Error> {
194 let mut input_device_status = InputDeviceStatus::new(device_node);
195 let device_descriptor: fidl_input_report::DeviceDescriptor = match device
196 .get_descriptor()
197 .await
198 {
199 Ok(descriptor) => descriptor,
200 Err(_) => {
201 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
202 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
203 }
204 };
205
206 let consumer_controls_descriptor = device_descriptor.consumer_control.ok_or_else(|| {
207 input_device_status
208 .health_node
209 .set_unhealthy("DeviceDescriptor does not have a ConsumerControlDescriptor.");
210 format_err!("DeviceDescriptor does not have a ConsumerControlDescriptor")
211 })?;
212
213 let consumer_controls_input_descriptor =
214 consumer_controls_descriptor.input.ok_or_else(|| {
215 input_device_status.health_node.set_unhealthy(
216 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor.",
217 );
218 format_err!(
219 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor"
220 )
221 })?;
222
223 let device_descriptor: ConsumerControlsDeviceDescriptor =
224 ConsumerControlsDeviceDescriptor {
225 buttons: consumer_controls_input_descriptor.buttons.unwrap_or_default(),
226 device_id,
227 };
228
229 Ok((
230 ConsumerControlsBinding { event_sender: input_event_sender, device_descriptor },
231 input_device_status,
232 ))
233 }
234
235 fn process_reports(
258 reports: Vec<InputReport>,
259 mut previous_report: Option<InputReport>,
260 device_descriptor: &input_device::InputDeviceDescriptor,
261 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
262 inspect_status: &InputDeviceStatus,
263 metrics_logger: &metrics::MetricsLogger,
264 _feature_flags: &input_device::InputPipelineFeatureFlags,
265 ) -> (Option<InputReport>, Option<UnboundedReceiver<InputEvent>>) {
266 fuchsia_trace::duration!("input", "consumer-controls-binding-process-report", "num_reports" => reports.len());
267 for report in reports {
268 previous_report = Self::process_report(
269 report,
270 previous_report,
271 device_descriptor,
272 input_event_sender,
273 inspect_status,
274 metrics_logger,
275 );
276 }
277 (previous_report, None)
278 }
279
280 fn process_report(
281 mut report: InputReport,
282 previous_report: Option<InputReport>,
283 device_descriptor: &input_device::InputDeviceDescriptor,
284 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
285 inspect_status: &InputDeviceStatus,
286 metrics_logger: &metrics::MetricsLogger,
287 ) -> Option<InputReport> {
288 if let Some(trace_id) = report.trace_id {
289 fuchsia_trace::flow_end!("input", "input_report", trace_id.into());
290 }
291
292 let wake_lease = report.wake_lease.take();
296
297 inspect_status.count_received_report(&report);
298 let pressed_buttons: Vec<ConsumerControlButton> = match report.consumer_control {
300 Some(ref consumer_control_report) => consumer_control_report
301 .pressed_buttons
302 .as_ref()
303 .map(|buttons| buttons.iter().cloned().collect())
304 .unwrap_or_default(),
305 None => {
306 inspect_status.count_filtered_report();
307 return previous_report;
308 }
309 };
310
311 let trace_id = fuchsia_trace::Id::random();
312 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
313
314 send_consumer_controls_event(
315 pressed_buttons,
316 wake_lease,
317 device_descriptor,
318 input_event_sender,
319 inspect_status,
320 metrics_logger,
321 trace_id,
322 );
323
324 Some(report)
325 }
326}
327
328fn send_consumer_controls_event(
338 pressed_buttons: Vec<ConsumerControlButton>,
339 wake_lease: Option<zx::EventPair>,
340 device_descriptor: &input_device::InputDeviceDescriptor,
341 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
342 inspect_status: &InputDeviceStatus,
343 metrics_logger: &metrics::MetricsLogger,
344 trace_id: fuchsia_trace::Id,
345) {
346 let event = input_device::InputEvent {
347 device_event: input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
348 pressed_buttons,
349 wake_lease,
350 )),
351 device_descriptor: device_descriptor.clone(),
352 event_time: zx::MonotonicInstant::get(),
353 handled: Handled::No,
354 trace_id: Some(trace_id),
355 };
356 let events = vec![event.clone_with_wake_lease()];
357
358 match sender.unbounded_send(events.clone()) {
359 Err(e) => metrics_logger.log_error(
360 InputPipelineErrorMetricDimensionEvent::ConsumerControlsSendEventFailed,
361 std::format!("Failed to send ConsumerControlsEvent with error: {:?}", e),
362 ),
363 _ => inspect_status.count_generated_events(&events),
364 }
365}
366
367#[cfg(test)]
368mod tests {
369 use super::*;
370 use crate::testing_utilities;
371 use fuchsia_async as fasync;
372 use futures::StreamExt;
373
374 #[fasync::run_singlethreaded(test)]
377 async fn volume_up_only() {
378 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
379 let pressed_buttons = vec![ConsumerControlButton::VolumeUp];
380 let first_report = testing_utilities::create_consumer_control_input_report(
381 pressed_buttons.clone(),
382 event_time_i64,
383 );
384 let descriptor = testing_utilities::consumer_controls_device_descriptor();
385
386 let input_reports = vec![first_report];
387 let expected_events = vec![testing_utilities::create_consumer_controls_event(
388 pressed_buttons,
389 event_time_u64,
390 &descriptor,
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
401 #[fasync::run_singlethreaded(test)]
404 async fn volume_up_and_down() {
405 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
406 let pressed_buttons =
407 vec![ConsumerControlButton::VolumeUp, ConsumerControlButton::VolumeDown];
408 let first_report = testing_utilities::create_consumer_control_input_report(
409 pressed_buttons.clone(),
410 event_time_i64,
411 );
412 let descriptor = testing_utilities::consumer_controls_device_descriptor();
413
414 let input_reports = vec![first_report];
415 let expected_events = vec![testing_utilities::create_consumer_controls_event(
416 pressed_buttons,
417 event_time_u64,
418 &descriptor,
419 )];
420
421 assert_input_report_sequence_generates_events!(
422 input_reports: input_reports,
423 expected_events: expected_events,
424 device_descriptor: descriptor,
425 device_type: ConsumerControlsBinding,
426 );
427 }
428
429 #[fasync::run_singlethreaded(test)]
432 async fn sequence_of_buttons() {
433 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
434 let first_report = testing_utilities::create_consumer_control_input_report(
435 vec![ConsumerControlButton::VolumeUp],
436 event_time_i64,
437 );
438 let second_report = testing_utilities::create_consumer_control_input_report(
439 vec![ConsumerControlButton::VolumeDown],
440 event_time_i64,
441 );
442 let third_report = testing_utilities::create_consumer_control_input_report(
443 vec![ConsumerControlButton::CameraDisable],
444 event_time_i64,
445 );
446 let descriptor = testing_utilities::consumer_controls_device_descriptor();
447
448 let input_reports = vec![first_report, second_report, third_report];
449 let expected_events = vec![
450 testing_utilities::create_consumer_controls_event(
451 vec![ConsumerControlButton::VolumeUp],
452 event_time_u64,
453 &descriptor,
454 ),
455 testing_utilities::create_consumer_controls_event(
456 vec![ConsumerControlButton::VolumeDown],
457 event_time_u64,
458 &descriptor,
459 ),
460 testing_utilities::create_consumer_controls_event(
461 vec![ConsumerControlButton::CameraDisable],
462 event_time_u64,
463 &descriptor,
464 ),
465 ];
466
467 assert_input_report_sequence_generates_events!(
468 input_reports: input_reports,
469 expected_events: expected_events,
470 device_descriptor: descriptor,
471 device_type: ConsumerControlsBinding,
472 );
473 }
474}