1use crate::input_device::{self, Handled, InputDeviceBinding, InputDeviceStatus, InputEvent};
6use crate::{Transport, metrics, utils};
7use anyhow::{Error, format_err};
8use async_trait::async_trait;
9use fidl_fuchsia_input_report::ConsumerControlButton;
10use fuchsia_inspect::ArrayProperty;
11use fuchsia_inspect::health::Reporter;
12
13use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender};
14use metrics_registry::*;
15
16#[derive(Debug)]
28pub struct ConsumerControlsEvent {
29 pub pressed_buttons: Vec<ConsumerControlButton>,
30 pub wake_lease: Option<zx::EventPair>,
31}
32
33impl Clone for ConsumerControlsEvent {
34 fn clone(&self) -> Self {
35 log::debug!("ConsumerControlsEvent cloned without wake lease.");
36 Self { pressed_buttons: self.pressed_buttons.clone(), wake_lease: None }
37 }
38}
39
40impl PartialEq for ConsumerControlsEvent {
41 fn eq(&self, other: &Self) -> bool {
42 self.pressed_buttons == other.pressed_buttons
43 && self.wake_lease.as_ref().map(|h| h.koid())
44 == other.wake_lease.as_ref().map(|h| h.koid())
45 }
46}
47
48impl Drop for ConsumerControlsEvent {
49 fn drop(&mut self) {
50 log::debug!("ConsumerControlsEvent dropped, had_wake_lease: {:?}", self.wake_lease);
51 }
52}
53
54impl ConsumerControlsEvent {
55 pub fn new(
60 pressed_buttons: Vec<ConsumerControlButton>,
61 wake_lease: Option<zx::EventPair>,
62 ) -> Self {
63 Self { pressed_buttons, wake_lease }
64 }
65
66 pub fn record_inspect(&self, node: &fuchsia_inspect::Node) {
67 let pressed_buttons_node =
68 node.create_string_array("pressed_buttons", self.pressed_buttons.len());
69 self.pressed_buttons.iter().enumerate().for_each(|(i, button)| {
70 let button_name: String = match button {
71 ConsumerControlButton::VolumeUp => "volume_up".into(),
72 ConsumerControlButton::VolumeDown => "volume_down".into(),
73 ConsumerControlButton::Pause => "pause".into(),
74 ConsumerControlButton::FactoryReset => "factory_reset".into(),
75 ConsumerControlButton::MicMute => "mic_mute".into(),
76 ConsumerControlButton::Reboot => "reboot".into(),
77 ConsumerControlButton::CameraDisable => "camera_disable".into(),
78 ConsumerControlButton::Power => "power".into(),
79 ConsumerControlButton::Function => "function".into(),
80 unknown_value => {
81 format!("unknown({:?})", unknown_value)
82 }
83 };
84 pressed_buttons_node.set(i, &button_name);
85 });
86 node.record(pressed_buttons_node);
87 }
88}
89
90pub struct ConsumerControlsBinding {
97 event_sender: UnboundedSender<Vec<InputEvent>>,
99
100 device_descriptor: ConsumerControlsDeviceDescriptor,
102}
103
104#[derive(Clone, Debug, Eq, PartialEq)]
105pub struct ConsumerControlsDeviceDescriptor {
106 pub buttons: Vec<ConsumerControlButton>,
108 pub device_id: u32,
110}
111
112#[async_trait]
113impl input_device::InputDeviceBinding for ConsumerControlsBinding {
114 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
115 self.event_sender.clone()
116 }
117
118 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
119 input_device::InputDeviceDescriptor::ConsumerControls(self.device_descriptor.clone())
120 }
121}
122
123impl ConsumerControlsBinding {
124 pub async fn new(
139 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
140 device_id: u32,
141 input_event_sender: UnboundedSender<Vec<InputEvent>>,
142 device_node: fuchsia_inspect::Node,
143 feature_flags: input_device::InputPipelineFeatureFlags,
144 metrics_logger: metrics::MetricsLogger,
145 ) -> Result<Self, Error> {
146 let (device_binding, mut inspect_status) =
147 Self::bind_device(&device_proxy, device_id, input_event_sender, device_node).await?;
148 inspect_status.health_node.set_ok();
149 input_device::initialize_report_stream(
150 device_proxy,
151 device_binding.get_device_descriptor(),
152 device_binding.input_event_sender(),
153 inspect_status,
154 metrics_logger,
155 feature_flags,
156 Self::process_reports,
157 );
158
159 Ok(device_binding)
160 }
161
162 async fn bind_device(
174 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
175 device_id: u32,
176 input_event_sender: UnboundedSender<Vec<InputEvent>>,
177 device_node: fuchsia_inspect::Node,
178 ) -> Result<(Self, InputDeviceStatus), Error> {
179 let mut input_device_status = InputDeviceStatus::new(device_node);
180 let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
181 .get_descriptor()
182 .await
183 {
184 Ok(descriptor) => descriptor.descriptor,
185 Err(_) => {
186 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
187 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
188 }
189 };
190
191 let consumer_controls_descriptor = device_descriptor.consumer_control.ok_or_else(|| {
192 input_device_status
193 .health_node
194 .set_unhealthy("DeviceDescriptor does not have a ConsumerControlDescriptor.");
195 format_err!("DeviceDescriptor does not have a ConsumerControlDescriptor")
196 })?;
197
198 let consumer_controls_input_descriptor =
199 consumer_controls_descriptor.input.ok_or_else(|| {
200 input_device_status.health_node.set_unhealthy(
201 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor.",
202 );
203 format_err!(
204 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor"
205 )
206 })?;
207
208 let device_descriptor: ConsumerControlsDeviceDescriptor =
209 ConsumerControlsDeviceDescriptor {
210 buttons: consumer_controls_input_descriptor
211 .buttons
212 .unwrap_or_default()
213 .into_iter()
214 .map(|b| utils::consumer_control_button_to_old(&b))
215 .collect(),
216 device_id,
217 };
218
219 Ok((
220 ConsumerControlsBinding { event_sender: input_event_sender, device_descriptor },
221 input_device_status,
222 ))
223 }
224
225 fn process_reports(
248 reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
249 mut previous_state: Option<input_device::PreviousDeviceState>,
250 device_descriptor: &input_device::InputDeviceDescriptor,
251 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
252 inspect_status: &InputDeviceStatus,
253 metrics_logger: &metrics::MetricsLogger,
254 _feature_flags: &input_device::InputPipelineFeatureFlags,
255 ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
256 fuchsia_trace::duration!("input", "consumer-controls-binding-process-report", "num_reports" => reports.len());
257 for report in reports {
258 previous_state = Self::process_report(
259 report,
260 previous_state,
261 device_descriptor,
262 input_event_sender,
263 inspect_status,
264 metrics_logger,
265 );
266 }
267 (previous_state, None)
268 }
269
270 fn process_report(
271 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
272 previous_state: Option<input_device::PreviousDeviceState>,
273 device_descriptor: &input_device::InputDeviceDescriptor,
274 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
275 inspect_status: &InputDeviceStatus,
276 metrics_logger: &metrics::MetricsLogger,
277 ) -> Option<input_device::PreviousDeviceState> {
278 if let Some(trace_id) = report.trace_id() {
279 fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
280 }
281
282 let wake_lease = utils::duplicate_wake_lease(report.wake_lease());
286
287 inspect_status.count_received_report_wire(report);
288 let pressed_buttons: Vec<ConsumerControlButton> = match report.consumer_control() {
290 Some(ref consumer_control_report) => consumer_control_report
291 .pressed_buttons()
292 .map(|buttons| {
293 buttons
294 .iter()
295 .map(|&b| {
296 let natural_button = fidl_next::FromWire::from_wire(b);
297 utils::consumer_control_button_to_old(&natural_button)
298 })
299 .collect()
300 })
301 .unwrap_or_default(),
302 None => {
303 inspect_status.count_filtered_report();
304 return previous_state;
305 }
306 };
307
308 let trace_id = fuchsia_trace::Id::new();
309 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
310
311 send_consumer_controls_event(
312 pressed_buttons.clone(),
313 wake_lease,
314 device_descriptor,
315 input_event_sender,
316 inspect_status,
317 metrics_logger,
318 trace_id,
319 );
320
321 Some(input_device::PreviousDeviceState::ConsumerControls { pressed_buttons })
322 }
323}
324
325fn send_consumer_controls_event(
335 pressed_buttons: Vec<ConsumerControlButton>,
336 wake_lease: Option<zx::EventPair>,
337 device_descriptor: &input_device::InputDeviceDescriptor,
338 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
339 inspect_status: &InputDeviceStatus,
340 metrics_logger: &metrics::MetricsLogger,
341 trace_id: fuchsia_trace::Id,
342) {
343 let event = input_device::InputEvent {
344 device_event: input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
345 pressed_buttons,
346 wake_lease,
347 )),
348 device_descriptor: device_descriptor.clone(),
349 event_time: zx::MonotonicInstant::get(),
350 handled: Handled::No,
351 trace_id: Some(trace_id),
352 };
353 let events = vec![event];
354 inspect_status.count_generated_events(&events);
355
356 if let Err(e) = sender.unbounded_send(events) {
357 metrics_logger.log_error(
358 InputPipelineErrorMetricDimensionEvent::ConsumerControlsSendEventFailed,
359 std::format!("Failed to send ConsumerControlsEvent with error: {:?}", e),
360 );
361 }
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367 use crate::testing_utilities;
368 use fuchsia_async as fasync;
369 use futures::StreamExt;
370
371 #[fasync::run_singlethreaded(test)]
374 async fn volume_up_only() {
375 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
376 let pressed_buttons = vec![ConsumerControlButton::VolumeUp];
377 let first_report = testing_utilities::create_consumer_control_input_report(
378 pressed_buttons.clone(),
379 event_time_i64,
380 );
381 let descriptor = testing_utilities::consumer_controls_device_descriptor();
382
383 let input_reports = vec![first_report];
384 let expected_events = vec![testing_utilities::create_consumer_controls_event(
385 pressed_buttons,
386 event_time_u64,
387 &descriptor,
388 )];
389
390 assert_input_report_sequence_generates_events!(
391 input_reports: input_reports,
392 expected_events: expected_events,
393 device_descriptor: descriptor,
394 device_type: ConsumerControlsBinding,
395 );
396 }
397
398 #[fasync::run_singlethreaded(test)]
401 async fn volume_up_and_down() {
402 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
403 let pressed_buttons =
404 vec![ConsumerControlButton::VolumeUp, ConsumerControlButton::VolumeDown];
405 let first_report = testing_utilities::create_consumer_control_input_report(
406 pressed_buttons.clone(),
407 event_time_i64,
408 );
409 let descriptor = testing_utilities::consumer_controls_device_descriptor();
410
411 let input_reports = vec![first_report];
412 let expected_events = vec![testing_utilities::create_consumer_controls_event(
413 pressed_buttons,
414 event_time_u64,
415 &descriptor,
416 )];
417
418 assert_input_report_sequence_generates_events!(
419 input_reports: input_reports,
420 expected_events: expected_events,
421 device_descriptor: descriptor,
422 device_type: ConsumerControlsBinding,
423 );
424 }
425
426 #[fasync::run_singlethreaded(test)]
429 async fn sequence_of_buttons() {
430 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
431 let first_report = testing_utilities::create_consumer_control_input_report(
432 vec![ConsumerControlButton::VolumeUp],
433 event_time_i64,
434 );
435 let second_report = testing_utilities::create_consumer_control_input_report(
436 vec![ConsumerControlButton::VolumeDown],
437 event_time_i64,
438 );
439 let third_report = testing_utilities::create_consumer_control_input_report(
440 vec![ConsumerControlButton::CameraDisable],
441 event_time_i64,
442 );
443 let descriptor = testing_utilities::consumer_controls_device_descriptor();
444
445 let input_reports = vec![first_report, second_report, third_report];
446 let expected_events = vec![
447 testing_utilities::create_consumer_controls_event(
448 vec![ConsumerControlButton::VolumeUp],
449 event_time_u64,
450 &descriptor,
451 ),
452 testing_utilities::create_consumer_controls_event(
453 vec![ConsumerControlButton::VolumeDown],
454 event_time_u64,
455 &descriptor,
456 ),
457 testing_utilities::create_consumer_controls_event(
458 vec![ConsumerControlButton::CameraDisable],
459 event_time_u64,
460 &descriptor,
461 ),
462 ];
463
464 assert_input_report_sequence_generates_events!(
465 input_reports: input_reports,
466 expected_events: expected_events,
467 device_descriptor: descriptor,
468 device_type: ConsumerControlsBinding,
469 );
470 }
471}