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 inspect_status.count_received_report(&report);
293 let pressed_buttons: Vec<ConsumerControlButton> = match report.consumer_control {
295 Some(ref consumer_control_report) => consumer_control_report
296 .pressed_buttons
297 .as_ref()
298 .map(|buttons| buttons.iter().cloned().collect())
299 .unwrap_or_default(),
300 None => {
301 inspect_status.count_filtered_report();
302 return previous_report;
303 }
304 };
305
306 let wake_lease = report.wake_lease.take();
307 let trace_id = fuchsia_trace::Id::random();
308 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
309
310 send_consumer_controls_event(
311 pressed_buttons,
312 wake_lease,
313 device_descriptor,
314 input_event_sender,
315 inspect_status,
316 metrics_logger,
317 trace_id,
318 );
319
320 Some(report)
321 }
322}
323
324fn send_consumer_controls_event(
334 pressed_buttons: Vec<ConsumerControlButton>,
335 wake_lease: Option<zx::EventPair>,
336 device_descriptor: &input_device::InputDeviceDescriptor,
337 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
338 inspect_status: &InputDeviceStatus,
339 metrics_logger: &metrics::MetricsLogger,
340 trace_id: fuchsia_trace::Id,
341) {
342 let event = input_device::InputEvent {
343 device_event: input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
344 pressed_buttons,
345 wake_lease,
346 )),
347 device_descriptor: device_descriptor.clone(),
348 event_time: zx::MonotonicInstant::get(),
349 handled: Handled::No,
350 trace_id: Some(trace_id),
351 };
352 let events = vec![event.clone_with_wake_lease()];
353
354 match sender.unbounded_send(events.clone()) {
355 Err(e) => metrics_logger.log_error(
356 InputPipelineErrorMetricDimensionEvent::ConsumerControlsSendEventFailed,
357 std::format!("Failed to send ConsumerControlsEvent with error: {:?}", e),
358 ),
359 _ => inspect_status.count_generated_events(&events),
360 }
361}
362
363#[cfg(test)]
364mod tests {
365 use super::*;
366 use crate::testing_utilities;
367 use fuchsia_async as fasync;
368 use futures::StreamExt;
369
370 #[fasync::run_singlethreaded(test)]
373 async fn volume_up_only() {
374 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
375 let pressed_buttons = vec![ConsumerControlButton::VolumeUp];
376 let first_report = testing_utilities::create_consumer_control_input_report(
377 pressed_buttons.clone(),
378 event_time_i64,
379 );
380 let descriptor = testing_utilities::consumer_controls_device_descriptor();
381
382 let input_reports = vec![first_report];
383 let expected_events = vec![testing_utilities::create_consumer_controls_event(
384 pressed_buttons,
385 event_time_u64,
386 &descriptor,
387 )];
388
389 assert_input_report_sequence_generates_events!(
390 input_reports: input_reports,
391 expected_events: expected_events,
392 device_descriptor: descriptor,
393 device_type: ConsumerControlsBinding,
394 );
395 }
396
397 #[fasync::run_singlethreaded(test)]
400 async fn volume_up_and_down() {
401 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
402 let pressed_buttons =
403 vec![ConsumerControlButton::VolumeUp, ConsumerControlButton::VolumeDown];
404 let first_report = testing_utilities::create_consumer_control_input_report(
405 pressed_buttons.clone(),
406 event_time_i64,
407 );
408 let descriptor = testing_utilities::consumer_controls_device_descriptor();
409
410 let input_reports = vec![first_report];
411 let expected_events = vec![testing_utilities::create_consumer_controls_event(
412 pressed_buttons,
413 event_time_u64,
414 &descriptor,
415 )];
416
417 assert_input_report_sequence_generates_events!(
418 input_reports: input_reports,
419 expected_events: expected_events,
420 device_descriptor: descriptor,
421 device_type: ConsumerControlsBinding,
422 );
423 }
424
425 #[fasync::run_singlethreaded(test)]
428 async fn sequence_of_buttons() {
429 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
430 let first_report = testing_utilities::create_consumer_control_input_report(
431 vec![ConsumerControlButton::VolumeUp],
432 event_time_i64,
433 );
434 let second_report = testing_utilities::create_consumer_control_input_report(
435 vec![ConsumerControlButton::VolumeDown],
436 event_time_i64,
437 );
438 let third_report = testing_utilities::create_consumer_control_input_report(
439 vec![ConsumerControlButton::CameraDisable],
440 event_time_i64,
441 );
442 let descriptor = testing_utilities::consumer_controls_device_descriptor();
443
444 let input_reports = vec![first_report, second_report, third_report];
445 let expected_events = vec![
446 testing_utilities::create_consumer_controls_event(
447 vec![ConsumerControlButton::VolumeUp],
448 event_time_u64,
449 &descriptor,
450 ),
451 testing_utilities::create_consumer_controls_event(
452 vec![ConsumerControlButton::VolumeDown],
453 event_time_u64,
454 &descriptor,
455 ),
456 testing_utilities::create_consumer_controls_event(
457 vec![ConsumerControlButton::CameraDisable],
458 event_time_u64,
459 &descriptor,
460 ),
461 ];
462
463 assert_input_report_sequence_generates_events!(
464 input_reports: input_reports,
465 expected_events: expected_events,
466 device_descriptor: descriptor,
467 device_type: ConsumerControlsBinding,
468 );
469 }
470}