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 pub is_injected: bool,
112}
113
114#[async_trait]
115impl input_device::InputDeviceBinding for ConsumerControlsBinding {
116 fn input_event_sender(&self) -> UnboundedSender<Vec<InputEvent>> {
117 self.event_sender.clone()
118 }
119
120 fn get_device_descriptor(&self) -> input_device::InputDeviceDescriptor {
121 input_device::InputDeviceDescriptor::ConsumerControls(self.device_descriptor.clone())
122 }
123}
124
125impl ConsumerControlsBinding {
126 pub async fn new(
141 device_proxy: fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
142 device_id: u32,
143 input_event_sender: UnboundedSender<Vec<InputEvent>>,
144 device_node: fuchsia_inspect::Node,
145 feature_flags: input_device::InputPipelineFeatureFlags,
146 metrics_logger: metrics::MetricsLogger,
147 is_injected: bool,
148 ) -> Result<Self, Error> {
149 let (device_binding, mut inspect_status) = Self::bind_device(
150 &device_proxy,
151 device_id,
152 input_event_sender,
153 device_node,
154 is_injected,
155 )
156 .await?;
157 inspect_status.health_node.set_ok();
158 input_device::initialize_report_stream(
159 device_proxy,
160 device_binding.get_device_descriptor(),
161 device_binding.input_event_sender(),
162 inspect_status,
163 metrics_logger,
164 feature_flags,
165 Self::process_reports,
166 );
167
168 Ok(device_binding)
169 }
170
171 async fn bind_device(
183 device: &fidl_next::Client<fidl_next_fuchsia_input_report::InputDevice, Transport>,
184 device_id: u32,
185 input_event_sender: UnboundedSender<Vec<InputEvent>>,
186 device_node: fuchsia_inspect::Node,
187 is_injected: bool,
188 ) -> Result<(Self, InputDeviceStatus), Error> {
189 let mut input_device_status = InputDeviceStatus::new(device_node);
190 let device_descriptor: fidl_next_fuchsia_input_report::DeviceDescriptor = match device
191 .get_descriptor()
192 .await
193 {
194 Ok(descriptor) => descriptor.descriptor,
195 Err(_) => {
196 input_device_status.health_node.set_unhealthy("Could not get device descriptor.");
197 return Err(format_err!("Could not get descriptor for device_id: {}", device_id));
198 }
199 };
200
201 let consumer_controls_descriptor = device_descriptor.consumer_control.ok_or_else(|| {
202 input_device_status
203 .health_node
204 .set_unhealthy("DeviceDescriptor does not have a ConsumerControlDescriptor.");
205 format_err!("DeviceDescriptor does not have a ConsumerControlDescriptor")
206 })?;
207
208 let consumer_controls_input_descriptor =
209 consumer_controls_descriptor.input.ok_or_else(|| {
210 input_device_status.health_node.set_unhealthy(
211 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor.",
212 );
213 format_err!(
214 "ConsumerControlDescriptor does not have a ConsumerControlInputDescriptor"
215 )
216 })?;
217
218 let device_descriptor: ConsumerControlsDeviceDescriptor =
219 ConsumerControlsDeviceDescriptor {
220 buttons: consumer_controls_input_descriptor
221 .buttons
222 .unwrap_or_default()
223 .into_iter()
224 .map(|b| utils::consumer_control_button_to_old(&b))
225 .collect(),
226 device_id,
227 is_injected,
228 };
229
230 Ok((
231 ConsumerControlsBinding { event_sender: input_event_sender, device_descriptor },
232 input_device_status,
233 ))
234 }
235
236 fn process_reports(
259 reports: &[fidl_next_fuchsia_input_report::wire::InputReport<'_>],
260 mut previous_state: Option<input_device::PreviousDeviceState>,
261 device_descriptor: &input_device::InputDeviceDescriptor,
262 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
263 inspect_status: &InputDeviceStatus,
264 metrics_logger: &metrics::MetricsLogger,
265 _feature_flags: &input_device::InputPipelineFeatureFlags,
266 ) -> (Option<input_device::PreviousDeviceState>, Option<UnboundedReceiver<InputEvent>>) {
267 fuchsia_trace::duration!("input", "consumer-controls-binding-process-report", "num_reports" => reports.len());
268 for report in reports {
269 previous_state = Self::process_report(
270 report,
271 previous_state,
272 device_descriptor,
273 input_event_sender,
274 inspect_status,
275 metrics_logger,
276 );
277 }
278 (previous_state, None)
279 }
280
281 fn process_report(
282 report: &fidl_next_fuchsia_input_report::wire::InputReport<'_>,
283 previous_state: Option<input_device::PreviousDeviceState>,
284 device_descriptor: &input_device::InputDeviceDescriptor,
285 input_event_sender: &mut UnboundedSender<Vec<InputEvent>>,
286 inspect_status: &InputDeviceStatus,
287 metrics_logger: &metrics::MetricsLogger,
288 ) -> Option<input_device::PreviousDeviceState> {
289 if let Some(trace_id) = report.trace_id() {
290 fuchsia_trace::flow_end!("input", "input_report", trace_id.0.into());
291 }
292
293 let wake_lease = utils::duplicate_wake_lease(report.wake_lease());
297
298 inspect_status.count_received_report_wire(report);
299 let pressed_buttons: Vec<ConsumerControlButton> = match report.consumer_control() {
301 Some(ref consumer_control_report) => consumer_control_report
302 .pressed_buttons()
303 .map(|buttons| {
304 buttons
305 .iter()
306 .map(|&b| {
307 let natural_button = fidl_next::FromWire::from_wire(b);
308 utils::consumer_control_button_to_old(&natural_button)
309 })
310 .collect()
311 })
312 .unwrap_or_default(),
313 None => {
314 inspect_status.count_filtered_report();
315 return previous_state;
316 }
317 };
318
319 let trace_id = fuchsia_trace::Id::new();
320 fuchsia_trace::flow_begin!("input", "event_in_input_pipeline", trace_id);
321
322 send_consumer_controls_event(
323 pressed_buttons.clone(),
324 wake_lease,
325 device_descriptor,
326 input_event_sender,
327 inspect_status,
328 metrics_logger,
329 trace_id,
330 );
331
332 Some(input_device::PreviousDeviceState::ConsumerControls { pressed_buttons })
333 }
334}
335
336fn send_consumer_controls_event(
346 pressed_buttons: Vec<ConsumerControlButton>,
347 wake_lease: Option<zx::EventPair>,
348 device_descriptor: &input_device::InputDeviceDescriptor,
349 sender: &mut UnboundedSender<Vec<input_device::InputEvent>>,
350 inspect_status: &InputDeviceStatus,
351 metrics_logger: &metrics::MetricsLogger,
352 trace_id: fuchsia_trace::Id,
353) {
354 let event = input_device::InputEvent {
355 device_event: input_device::InputDeviceEvent::ConsumerControls(ConsumerControlsEvent::new(
356 pressed_buttons,
357 wake_lease,
358 )),
359 device_descriptor: device_descriptor.clone(),
360 event_time: zx::MonotonicInstant::get(),
361 handled: Handled::No,
362 trace_id: Some(trace_id),
363 };
364 let events = vec![event];
365 inspect_status.count_generated_events(&events);
366
367 if let Err(e) = sender.unbounded_send(events) {
368 metrics_logger.log_error(
369 InputPipelineErrorMetricDimensionEvent::ConsumerControlsSendEventFailed,
370 std::format!("Failed to send ConsumerControlsEvent with error: {:?}", e),
371 );
372 }
373}
374
375#[cfg(test)]
376mod tests {
377 use super::*;
378 use crate::testing_utilities;
379 use fuchsia_async as fasync;
380 use futures::StreamExt;
381
382 #[fasync::run_singlethreaded(test)]
385 async fn volume_up_only() {
386 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
387 let pressed_buttons = vec![ConsumerControlButton::VolumeUp];
388 let first_report = testing_utilities::create_consumer_control_input_report(
389 pressed_buttons.clone(),
390 event_time_i64,
391 );
392 let descriptor = testing_utilities::consumer_controls_device_descriptor();
393
394 let input_reports = vec![first_report];
395 let expected_events = vec![testing_utilities::create_consumer_controls_event(
396 pressed_buttons,
397 event_time_u64,
398 &descriptor,
399 )];
400
401 assert_input_report_sequence_generates_events!(
402 input_reports: input_reports,
403 expected_events: expected_events,
404 device_descriptor: descriptor,
405 device_type: ConsumerControlsBinding,
406 );
407 }
408
409 #[fasync::run_singlethreaded(test)]
412 async fn volume_up_and_down() {
413 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
414 let pressed_buttons =
415 vec![ConsumerControlButton::VolumeUp, ConsumerControlButton::VolumeDown];
416 let first_report = testing_utilities::create_consumer_control_input_report(
417 pressed_buttons.clone(),
418 event_time_i64,
419 );
420 let descriptor = testing_utilities::consumer_controls_device_descriptor();
421
422 let input_reports = vec![first_report];
423 let expected_events = vec![testing_utilities::create_consumer_controls_event(
424 pressed_buttons,
425 event_time_u64,
426 &descriptor,
427 )];
428
429 assert_input_report_sequence_generates_events!(
430 input_reports: input_reports,
431 expected_events: expected_events,
432 device_descriptor: descriptor,
433 device_type: ConsumerControlsBinding,
434 );
435 }
436
437 #[fasync::run_singlethreaded(test)]
440 async fn sequence_of_buttons() {
441 let (event_time_i64, event_time_u64) = testing_utilities::event_times();
442 let first_report = testing_utilities::create_consumer_control_input_report(
443 vec![ConsumerControlButton::VolumeUp],
444 event_time_i64,
445 );
446 let second_report = testing_utilities::create_consumer_control_input_report(
447 vec![ConsumerControlButton::VolumeDown],
448 event_time_i64,
449 );
450 let third_report = testing_utilities::create_consumer_control_input_report(
451 vec![ConsumerControlButton::CameraDisable],
452 event_time_i64,
453 );
454 let descriptor = testing_utilities::consumer_controls_device_descriptor();
455
456 let input_reports = vec![first_report, second_report, third_report];
457 let expected_events = vec![
458 testing_utilities::create_consumer_controls_event(
459 vec![ConsumerControlButton::VolumeUp],
460 event_time_u64,
461 &descriptor,
462 ),
463 testing_utilities::create_consumer_controls_event(
464 vec![ConsumerControlButton::VolumeDown],
465 event_time_u64,
466 &descriptor,
467 ),
468 testing_utilities::create_consumer_controls_event(
469 vec![ConsumerControlButton::CameraDisable],
470 event_time_u64,
471 &descriptor,
472 ),
473 ];
474
475 assert_input_report_sequence_generates_events!(
476 input_reports: input_reports,
477 expected_events: expected_events,
478 device_descriptor: descriptor,
479 device_type: ConsumerControlsBinding,
480 );
481 }
482}