1use super::input_fidl_handler::Publisher;
6use crate::input::input_device_configuration::InputConfiguration;
7use crate::input::types::{
8 DeviceState, DeviceStateSource, InputDevice, InputDeviceType, InputInfo, InputInfoSources,
9 InputState, Microphone,
10};
11use anyhow::{Context, Error};
12use fuchsia_async as fasync;
13use futures::StreamExt;
14use futures::channel::mpsc::UnboundedReceiver;
15use futures::channel::oneshot::Sender;
16use serde::{Deserialize, Serialize};
17use settings_camera::connect_to_camera;
18use settings_common::config::default_settings::DefaultSetting;
19use settings_common::inspect::event::{
20 ExternalEventPublisher, ResponseType, SettingValuePublisher,
21};
22use settings_common::service_context::ServiceContext;
23use settings_media_buttons::{Event, MediaButtons};
24use settings_storage::UpdateState;
25use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
26use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
27use std::borrow::Cow;
28use std::rc::Rc;
29
30pub(crate) const DEFAULT_CAMERA_NAME: &str = "camera";
31pub(crate) const DEFAULT_MIC_NAME: &str = "microphone";
32
33type UpdateInputResult = Result<Option<InputInfo>, InputError>;
34fn check_publish(
35 result: UpdateInputResult,
36 publish: impl Fn(InputInfo),
37) -> Result<Option<()>, InputError> {
38 result.map(|info| info.map(publish))
39}
40
41#[derive(thiserror::Error, Debug)]
42pub(crate) enum InputError {
43 #[error("Failed to initialize controller: {0:?}")]
44 InitFailure(Error),
45 #[error("Unsupported device type: {0:?}")]
46 Unsupported(InputDeviceType),
47 #[error("External failure for Input dependency: {0:?} request:{1:?} error:{2}")]
48 ExternalFailure(Cow<'static, str>, Cow<'static, str>, Cow<'static, str>),
49 #[error("Write failed for Input: {0:?}")]
50 WriteFailure(Error),
51 #[error("Unexpected error: {0}")]
52 UnexpectedError(Cow<'static, str>),
53}
54
55impl From<&InputError> for ResponseType {
56 fn from(error: &InputError) -> Self {
57 match error {
58 InputError::InitFailure(..) => ResponseType::InitFailure,
59 InputError::Unsupported(..) => ResponseType::UnsupportedError,
60 InputError::ExternalFailure(..) => ResponseType::ExternalFailure,
61 InputError::WriteFailure(..) => ResponseType::StorageFailure,
62 InputError::UnexpectedError(..) => ResponseType::UnexpectedError,
63 }
64 }
65}
66
67impl DeviceStorageCompatible for InputInfoSources {
68 type Loader = NoneT;
69 const KEY: &'static str = "input_info";
70
71 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
72 Self::extract(value).or_else(|e| {
73 log::info!("Failed to deserialize InputInfoSources. Falling back to V2: {e:?}");
74 InputInfoSourcesV2::try_deserialize_from(value).map(Self::from)
75 })
76 }
77}
78
79impl From<InputInfoSourcesV2> for InputInfoSources {
80 fn from(v2: InputInfoSourcesV2) -> Self {
81 let mut input_state = v2.input_device_state;
82
83 input_state.set_source_state(
85 InputDeviceType::MICROPHONE,
86 DEFAULT_MIC_NAME.to_string(),
87 DeviceStateSource::HARDWARE,
88 if v2.hw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
89 );
90 input_state.set_source_state(
91 InputDeviceType::MICROPHONE,
92 DEFAULT_MIC_NAME.to_string(),
93 DeviceStateSource::SOFTWARE,
94 if v2.sw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
95 );
96
97 InputInfoSources { input_device_state: input_state }
98 }
99}
100
101impl From<InputInfoSources> for InputInfo {
102 fn from(info: InputInfoSources) -> InputInfo {
103 InputInfo { input_device_state: info.input_device_state }
104 }
105}
106
107#[derive(PartialEq, Default, Debug, Clone, Serialize, Deserialize)]
108pub struct InputInfoSourcesV2 {
109 hw_microphone: Microphone,
110 sw_microphone: Microphone,
111 input_device_state: InputState,
112}
113
114impl DeviceStorageCompatible for InputInfoSourcesV2 {
115 type Loader = NoneT;
116 const KEY: &'static str = "input_info_sources_v2";
117
118 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
119 Self::extract(value).or_else(|e| {
120 log::info!("Failed to deserialize InputInfoSourcesV2. Falling back to V1: {e:?}");
121 InputInfoSourcesV1::try_deserialize_from(value).map(Self::from)
122 })
123 }
124}
125
126impl From<InputInfoSourcesV1> for InputInfoSourcesV2 {
127 fn from(v1: InputInfoSourcesV1) -> Self {
128 InputInfoSourcesV2 {
129 hw_microphone: v1.hw_microphone,
130 sw_microphone: v1.sw_microphone,
131 input_device_state: InputState::new(),
132 }
133 }
134}
135
136#[derive(PartialEq, Default, Debug, Clone, Copy, Serialize, Deserialize)]
137pub struct InputInfoSourcesV1 {
138 pub hw_microphone: Microphone,
139 pub sw_microphone: Microphone,
140}
141
142impl DeviceStorageCompatible for InputInfoSourcesV1 {
143 type Loader = NoneT;
144 const KEY: &'static str = "input_info_sources_v1";
145}
146
147pub(crate) enum Request {
148 Set(Vec<InputDevice>, Sender<Result<(), InputError>>),
149}
150
151pub struct InputController {
152 service_context: Rc<ServiceContext>,
153 store: Rc<DeviceStorage>,
155
156 input_device_state: InputState,
158
159 input_device_config: InputConfiguration,
161 publisher: Option<Publisher>,
162 setting_value_publisher: SettingValuePublisher<InputInfo>,
163 external_publisher: ExternalEventPublisher,
164}
165
166impl StorageAccess for InputController {
167 type Storage = DeviceStorage;
168 type Data = InputInfoSources;
169 const STORAGE_KEY: &'static str = InputInfoSources::KEY;
170}
171
172impl InputController {
173 pub(super) async fn new<F>(
174 service_context: Rc<ServiceContext>,
175 default_setting: &mut DefaultSetting<InputConfiguration, &'static str>,
176 storage_factory: Rc<F>,
177 setting_value_publisher: SettingValuePublisher<InputInfo>,
178 external_publisher: ExternalEventPublisher,
179 ) -> Result<Self, InputError>
180 where
181 F: StorageFactory<Storage = DeviceStorage>,
182 {
183 let input_device_config = default_setting
184 .load_default_value()
185 .context("Unable to load input device config")
186 .map_err(InputError::InitFailure)?
187 .expect("Input requires a configuration");
188 Ok(InputController::create_with_config(
189 service_context,
190 input_device_config,
191 &*storage_factory,
192 setting_value_publisher,
193 external_publisher,
194 )
195 .await)
196 }
197
198 pub(crate) async fn create_with_config<F>(
200 service_context: Rc<ServiceContext>,
201 input_device_config: InputConfiguration,
202 storage_factory: &F,
203 setting_value_publisher: SettingValuePublisher<InputInfo>,
204 external_publisher: ExternalEventPublisher,
205 ) -> Self
206 where
207 F: StorageFactory<Storage = DeviceStorage>,
208 {
209 Self {
210 service_context,
211 store: storage_factory.get_store().await,
212 input_device_state: InputState::new(),
213 input_device_config,
214 publisher: None,
215 setting_value_publisher,
216 external_publisher,
217 }
218 }
219
220 async fn has_input_device(&self, device_type: InputDeviceType) -> bool {
222 let input_device_config_state: InputState = self.input_device_config.clone().into();
223 input_device_config_state.device_types().contains(&device_type)
224 }
225
226 pub(super) fn register_publisher(&mut self, publisher: Publisher) {
227 self.publisher = Some(publisher);
228 }
229
230 fn publish(&self, info: InputInfo) {
231 let _ = self.setting_value_publisher.publish(&info);
232 if let Some(publisher) = self.publisher.as_ref() {
233 publisher.set(info);
234 }
235 }
236
237 pub(super) async fn handle(
238 mut self,
239 mut camera_event_rx: UnboundedReceiver<(bool, super::ResultSender)>,
240 mut media_buttons_event_rx: UnboundedReceiver<(Event, super::ResultSender)>,
241 mut request_rx: UnboundedReceiver<Request>,
242 ) -> fasync::Task<()> {
243 fasync::Task::local(async move {
244 let mut next_camera_event = camera_event_rx.next();
245 let mut next_media_buttons_event = media_buttons_event_rx.next();
246 let mut next_request = request_rx.next();
247 loop {
248 futures::select! {
249 event = next_camera_event => {
250 let Some((is_muted, response_tx)) = event else {
251 continue;
252 };
253 next_camera_event = camera_event_rx.next();
254 let res = self.handle_camera_event(is_muted).await;
255 let _ = response_tx.send(res);
256 }
257 event = next_media_buttons_event => {
258 let Some((Event::OnButton(buttons), response_tx)) = event else {
259 continue;
260 };
261 next_media_buttons_event = media_buttons_event_rx.next();
262 let res = self.handle_media_buttons_event(buttons).await;
263 let _ = response_tx.send(res);
264 }
265 request = next_request => {
266 let Some(request) = request else {
267 continue;
268 };
269 next_request = request_rx.next();
270 let Request::Set(input_devices, tx) = request;
271 let res = check_publish(
272 self.set_input_states(input_devices, DeviceStateSource::SOFTWARE).await,
273 |info| self.publish(info)).map(|_|{});
274 let _ = tx.send(res);
275 }
276 }
277 }
278 })
279 }
280
281 async fn handle_camera_event(&mut self, is_muted: bool) -> Result<Option<()>, InputError> {
282 let old_state = self
283 .get_stored_info()
284 .await
285 .input_device_state
286 .get_source_state(
287 InputDeviceType::CAMERA,
288 DEFAULT_CAMERA_NAME.to_string(),
289 DeviceStateSource::SOFTWARE,
290 )
291 .map_err(|e| {
292 InputError::UnexpectedError(
293 format!("Could not find camera software state: {e:?}").into(),
294 )
295 })?;
296 if old_state.has_state(DeviceState::MUTED) != is_muted {
297 check_publish(
298 self.set_sw_camera_mute(is_muted, DEFAULT_CAMERA_NAME.to_string()).await,
299 |info| self.publish(info),
300 )
301 } else {
302 Ok(None)
303 }
304 }
305
306 async fn handle_media_buttons_event(
307 &mut self,
308 mut buttons: MediaButtons,
309 ) -> Result<Option<()>, InputError> {
310 if buttons.mic_mute.is_some() && !self.has_input_device(InputDeviceType::MICROPHONE).await {
311 buttons.set_mic_mute(None);
312 }
313 if buttons.camera_disable.is_some() && !self.has_input_device(InputDeviceType::CAMERA).await
314 {
315 buttons.set_camera_disable(None);
316 }
317 check_publish(self.set_hw_media_buttons_state(buttons).await, |info| self.publish(info))
318 }
319
320 async fn get_stored_info(&self) -> InputInfo {
325 let mut input_info = InputInfo::from(self.store.get::<InputInfo>().await);
326 if input_info.input_device_state.is_empty() {
327 input_info.input_device_state = self.input_device_config.clone().into();
328 }
329 input_info
330 }
331
332 pub(super) async fn restore(&mut self) -> Result<InputInfo, InputError> {
334 let input_info = self.get_stored_info().await;
335 self.input_device_state = input_info.input_device_state.clone();
336
337 if self.input_device_config.devices.iter().any(|d| d.device_type == InputDeviceType::CAMERA)
338 {
339 match self.get_cam_sw_state() {
340 Ok(state) => {
341 if let Err(e) = self.push_cam_sw_state(state).await {
344 log::error!("Unable to restore camera state: {e:?}");
345 self.set_cam_err_state(state);
346 }
347 }
348 Err(e) => {
349 log::error!("Unable to load cam sw state: {e:?}");
350 self.set_cam_err_state(DeviceState::ERROR);
351 }
352 }
353 }
354 Ok(input_info)
355 }
356
357 async fn set_sw_camera_mute(&mut self, disabled: bool, name: String) -> UpdateInputResult {
358 let mut input_info = self.get_stored_info().await;
359 input_info.input_device_state.set_source_state(
360 InputDeviceType::CAMERA,
361 name.clone(),
362 DeviceStateSource::SOFTWARE,
363 if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
364 );
365
366 self.input_device_state.set_source_state(
367 InputDeviceType::CAMERA,
368 name.clone(),
369 DeviceStateSource::SOFTWARE,
370 if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
371 );
372 self.store
373 .write(&input_info)
374 .await
375 .map(|state| (UpdateState::Updated == state).then_some(input_info))
376 .context("writing sw camera info")
377 .map_err(InputError::WriteFailure)
378 }
379
380 async fn set_hw_media_buttons_state(
382 &mut self,
383 media_buttons: MediaButtons,
384 ) -> UpdateInputResult {
385 let mut states_to_process = Vec::new();
386 if let Some(mic_mute) = media_buttons.mic_mute {
387 states_to_process.push((InputDeviceType::MICROPHONE, mic_mute));
388 }
389 if let Some(camera_disable) = media_buttons.camera_disable {
390 states_to_process.push((InputDeviceType::CAMERA, camera_disable));
391 }
392
393 let mut input_info = self.get_stored_info().await;
394
395 for (device_type, muted) in states_to_process.into_iter() {
396 let hw_state_res = input_info.input_device_state.get_source_state(
398 device_type,
399 device_type.to_string(),
400 DeviceStateSource::HARDWARE,
401 );
402
403 let mut hw_state = hw_state_res.map_err(|err| {
404 InputError::UnexpectedError(
405 format!("Could not fetch current hw mute state: {err:?}").into(),
406 )
407 })?;
408
409 if muted {
410 hw_state &= !DeviceState::AVAILABLE;
412 hw_state |= DeviceState::MUTED;
413 } else {
414 hw_state |= DeviceState::AVAILABLE;
416 hw_state &= !DeviceState::MUTED;
417 }
418
419 input_info.input_device_state.set_source_state(
421 device_type,
422 device_type.to_string(),
423 DeviceStateSource::HARDWARE,
424 hw_state,
425 );
426 self.input_device_state.set_source_state(
427 device_type,
428 device_type.to_string(),
429 DeviceStateSource::HARDWARE,
430 hw_state,
431 );
432 }
433
434 self.store
435 .write(&input_info)
436 .await
437 .map(|state| (UpdateState::Updated == state).then_some(input_info))
438 .context("writing hw media buttons")
439 .map_err(InputError::WriteFailure)
440 }
441
442 async fn set_input_states(
444 &mut self,
445 input_devices: Vec<InputDevice>,
446 source: DeviceStateSource,
447 ) -> UpdateInputResult {
448 let mut input_info = self.get_stored_info().await;
449 let device_types = input_info.input_device_state.device_types();
450
451 let cam_state = self.get_cam_sw_state().ok();
452
453 for input_device in input_devices.iter() {
454 if !device_types.contains(&input_device.device_type) {
455 return Err(InputError::Unsupported(input_device.device_type));
456 }
457 input_info.input_device_state.insert_device(input_device.clone(), source);
458 self.input_device_state.insert_device(input_device.clone(), source);
459 }
460
461 let modified_cam_state = self.get_cam_sw_state().ok();
465 if cam_state != modified_cam_state {
466 if let Some(state) = modified_cam_state {
467 self.push_cam_sw_state(state).await?;
468 }
469 }
470
471 self.store
472 .write(&input_info)
473 .await
474 .map(|state| (UpdateState::Updated == state).then_some(input_info))
475 .context("writing input states")
476 .map_err(InputError::WriteFailure)
477 }
478
479 #[allow(clippy::result_large_err)] fn get_cam_sw_state(&self) -> Result<DeviceState, InputError> {
482 self.input_device_state
483 .get_source_state(
484 InputDeviceType::CAMERA,
485 DEFAULT_CAMERA_NAME.to_string(),
486 DeviceStateSource::SOFTWARE,
487 )
488 .map_err(|e| {
489 InputError::UnexpectedError(
490 format!("Could not find camera software state: {e:?}").into(),
491 )
492 })
493 }
494
495 fn set_cam_err_state(&mut self, mut state: DeviceState) {
497 state.set(DeviceState::ERROR, true);
498 self.input_device_state.set_source_state(
499 InputDeviceType::CAMERA,
500 DEFAULT_CAMERA_NAME.to_string(),
501 DeviceStateSource::SOFTWARE,
502 state,
503 )
504 }
505
506 async fn push_cam_sw_state(&mut self, cam_state: DeviceState) -> Result<(), InputError> {
512 let is_muted = cam_state.has_state(DeviceState::MUTED);
513
514 let camera_proxy =
518 connect_to_camera(&*self.service_context, self.external_publisher.clone())
519 .await
520 .map_err(|e| {
521 InputError::UnexpectedError(
522 format!("Could not connect to camera device: {e:?}").into(),
523 )
524 })?;
525
526 camera_proxy.set_software_mute_state(is_muted).await.map_err(|e| {
527 InputError::ExternalFailure(
528 "fuchsia.camera3.Device".into(),
529 "SetSoftwareMuteState".into(),
530 format!("{e:?}").into(),
531 )
532 })
533 }
534}
535
536#[cfg(test)]
537mod tests {
538 use super::*;
539 use crate::input::input_device_configuration::{InputDeviceConfiguration, SourceState};
540 use fuchsia_async as fasync;
541 use fuchsia_inspect::component;
542 use futures::channel::mpsc;
543 use settings_common::inspect::config_logger::InspectConfigLogger;
544 use settings_common::service_context::ServiceContext;
545 use settings_test_common::storage::InMemoryStorageFactory;
546
547 #[fuchsia::test]
548 fn test_input_migration_v1_to_current() {
549 const MUTED_MIC: Microphone = Microphone { muted: true };
550 let mut v1 = InputInfoSourcesV1::default();
551 v1.sw_microphone = MUTED_MIC;
552
553 let serialized_v1 = v1.serialize_to();
554 let current = InputInfoSources::try_deserialize_from(&serialized_v1)
555 .expect("deserialization should succeed");
556 let mut expected_input_state = InputState::new();
557 expected_input_state.set_source_state(
558 InputDeviceType::MICROPHONE,
559 DEFAULT_MIC_NAME.to_string(),
560 DeviceStateSource::SOFTWARE,
561 DeviceState::MUTED,
562 );
563 expected_input_state.set_source_state(
564 InputDeviceType::MICROPHONE,
565 DEFAULT_MIC_NAME.to_string(),
566 DeviceStateSource::HARDWARE,
567 DeviceState::AVAILABLE,
568 );
569 assert_eq!(current.input_device_state, expected_input_state);
570 }
571
572 #[fuchsia::test]
573 fn test_input_migration_v1_to_v2() {
574 const MUTED_MIC: Microphone = Microphone { muted: true };
575 let mut v1 = InputInfoSourcesV1::default();
576 v1.sw_microphone = MUTED_MIC;
577
578 let serialized_v1 = v1.serialize_to();
579 let v2 = InputInfoSourcesV2::try_deserialize_from(&serialized_v1)
580 .expect("deserialization should succeed");
581
582 assert_eq!(v2.hw_microphone, Microphone { muted: false });
583 assert_eq!(v2.sw_microphone, MUTED_MIC);
584 assert_eq!(v2.input_device_state, InputState::new());
585 }
586
587 #[fuchsia::test]
588 fn test_input_migration_v2_to_current() {
589 const DEFAULT_CAMERA_NAME: &str = "camera";
590 const MUTED_MIC: Microphone = Microphone { muted: true };
591 let mut v2 = InputInfoSourcesV2::default();
592 v2.input_device_state.set_source_state(
593 InputDeviceType::CAMERA,
594 DEFAULT_CAMERA_NAME.to_string(),
595 DeviceStateSource::SOFTWARE,
596 DeviceState::AVAILABLE,
597 );
598 v2.input_device_state.set_source_state(
599 InputDeviceType::CAMERA,
600 DEFAULT_CAMERA_NAME.to_string(),
601 DeviceStateSource::HARDWARE,
602 DeviceState::MUTED,
603 );
604 v2.sw_microphone = MUTED_MIC;
605
606 let serialized_v2 = v2.serialize_to();
607 let current = InputInfoSources::try_deserialize_from(&serialized_v2)
608 .expect("deserialization should succeed");
609 let mut expected_input_state = InputState::new();
610
611 expected_input_state.set_source_state(
612 InputDeviceType::MICROPHONE,
613 DEFAULT_MIC_NAME.to_string(),
614 DeviceStateSource::SOFTWARE,
615 DeviceState::MUTED,
616 );
617 expected_input_state.set_source_state(
618 InputDeviceType::MICROPHONE,
619 DEFAULT_MIC_NAME.to_string(),
620 DeviceStateSource::HARDWARE,
621 DeviceState::AVAILABLE,
622 );
623 expected_input_state.set_source_state(
624 InputDeviceType::CAMERA,
625 DEFAULT_CAMERA_NAME.to_string(),
626 DeviceStateSource::SOFTWARE,
627 DeviceState::AVAILABLE,
628 );
629 expected_input_state.set_source_state(
630 InputDeviceType::CAMERA,
631 DEFAULT_CAMERA_NAME.to_string(),
632 DeviceStateSource::HARDWARE,
633 DeviceState::MUTED,
634 );
635
636 assert_eq!(current.input_device_state, expected_input_state);
637 }
638
639 #[fuchsia::test]
640 async fn test_camera_error_on_restore() {
641 let (event_tx, _event_rx) = mpsc::unbounded();
642 let external_publisher = ExternalEventPublisher::new(event_tx);
643 let storage_factory = InMemoryStorageFactory::new();
644 storage_factory
645 .initialize::<InputController>()
646 .await
647 .expect("controller should have impls");
648 let (value_tx, _value_rx) = mpsc::unbounded();
649 let setting_value_publisher = SettingValuePublisher::new(value_tx);
650 let mut controller: InputController =
651 InputController::create_with_config::<InMemoryStorageFactory>(
652 Rc::new(ServiceContext::new(None)),
653 InputConfiguration {
654 devices: vec![InputDeviceConfiguration {
655 device_name: DEFAULT_CAMERA_NAME.to_string(),
656 device_type: InputDeviceType::CAMERA,
657 source_states: vec![SourceState {
658 source: DeviceStateSource::SOFTWARE,
659 state: 0,
660 }],
661 mutable_toggle_state: 0,
662 }],
663 },
664 &storage_factory,
665 setting_value_publisher,
666 external_publisher,
667 )
668 .await;
669
670 let result = controller.restore().await;
672 assert!(result.is_ok());
673
674 let camera_state = controller
676 .input_device_state
677 .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
678 .unwrap();
679 assert!(camera_state.has_state(DeviceState::ERROR));
680 }
681
682 #[fasync::run_until_stalled(test)]
683 async fn test_controller_creation_with_default_config() {
684 let config_logger = InspectConfigLogger::new(component::inspector().root());
685 let mut default_setting = DefaultSetting::new(
686 Some(InputConfiguration::default()),
687 "/config/data/input_device_config.json",
688 Rc::new(std::sync::Mutex::new(config_logger)),
689 );
690
691 let (event_tx, _) = mpsc::unbounded();
692 let external_publisher = ExternalEventPublisher::new(event_tx);
693
694 let storage_factory = InMemoryStorageFactory::new();
695 storage_factory
696 .initialize::<InputController>()
697 .await
698 .expect("controller should have impls");
699 let (value_tx, _value_rx) = mpsc::unbounded();
700 let setting_value_publisher = SettingValuePublisher::new(value_tx);
701 let _controller = InputController::new(
702 Rc::new(ServiceContext::new(None)),
703 &mut default_setting,
704 Rc::new(storage_factory),
705 setting_value_publisher,
706 external_publisher,
707 )
708 .await
709 .expect("Should have controller");
710 }
711}