1use crate::input_device_configuration::InputConfiguration;
6use crate::input_fidl_handler::Publisher;
7use crate::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 && let Some(state) = modified_cam_state
467 {
468 self.push_cam_sw_state(state).await?;
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 fn get_cam_sw_state(&self) -> Result<DeviceState, InputError> {
481 self.input_device_state
482 .get_source_state(
483 InputDeviceType::CAMERA,
484 DEFAULT_CAMERA_NAME.to_string(),
485 DeviceStateSource::SOFTWARE,
486 )
487 .map_err(|e| {
488 InputError::UnexpectedError(
489 format!("Could not find camera software state: {e:?}").into(),
490 )
491 })
492 }
493
494 fn set_cam_err_state(&mut self, mut state: DeviceState) {
496 state.set(DeviceState::ERROR, true);
497 self.input_device_state.set_source_state(
498 InputDeviceType::CAMERA,
499 DEFAULT_CAMERA_NAME.to_string(),
500 DeviceStateSource::SOFTWARE,
501 state,
502 )
503 }
504
505 async fn push_cam_sw_state(&mut self, cam_state: DeviceState) -> Result<(), InputError> {
511 let is_muted = cam_state.has_state(DeviceState::MUTED);
512
513 let camera_proxy =
517 connect_to_camera(&self.service_context, self.external_publisher.clone())
518 .await
519 .map_err(|e| {
520 InputError::UnexpectedError(
521 format!("Could not connect to camera device: {e:?}").into(),
522 )
523 })?;
524
525 camera_proxy.set_software_mute_state(is_muted).await.map_err(|e| {
526 InputError::ExternalFailure(
527 "fuchsia.camera3.Device".into(),
528 "SetSoftwareMuteState".into(),
529 format!("{e:?}").into(),
530 )
531 })
532 }
533}
534
535#[cfg(test)]
536mod tests {
537 use super::*;
538 use crate::input_device_configuration::{InputDeviceConfiguration, SourceState};
539 use fuchsia_async as fasync;
540 use fuchsia_inspect::component;
541 use futures::channel::mpsc;
542 use settings_common::inspect::config_logger::InspectConfigLogger;
543 use settings_common::service_context::ServiceContext;
544 use settings_test_common::storage::InMemoryStorageFactory;
545
546 #[fuchsia::test]
547 fn test_input_migration_v1_to_current() {
548 const MUTED_MIC: Microphone = Microphone { muted: true };
549 let v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
550
551 let serialized_v1 = v1.serialize_to();
552 let current = InputInfoSources::try_deserialize_from(&serialized_v1)
553 .expect("deserialization should succeed");
554 let mut expected_input_state = InputState::new();
555 expected_input_state.set_source_state(
556 InputDeviceType::MICROPHONE,
557 DEFAULT_MIC_NAME.to_string(),
558 DeviceStateSource::SOFTWARE,
559 DeviceState::MUTED,
560 );
561 expected_input_state.set_source_state(
562 InputDeviceType::MICROPHONE,
563 DEFAULT_MIC_NAME.to_string(),
564 DeviceStateSource::HARDWARE,
565 DeviceState::AVAILABLE,
566 );
567 assert_eq!(current.input_device_state, expected_input_state);
568 }
569
570 #[fuchsia::test]
571 fn test_input_migration_v1_to_v2() {
572 const MUTED_MIC: Microphone = Microphone { muted: true };
573 let v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
574
575 let serialized_v1 = v1.serialize_to();
576 let v2 = InputInfoSourcesV2::try_deserialize_from(&serialized_v1)
577 .expect("deserialization should succeed");
578
579 assert_eq!(v2.hw_microphone, Microphone { muted: false });
580 assert_eq!(v2.sw_microphone, MUTED_MIC);
581 assert_eq!(v2.input_device_state, InputState::new());
582 }
583
584 #[fuchsia::test]
585 fn test_input_migration_v2_to_current() {
586 const DEFAULT_CAMERA_NAME: &str = "camera";
587 const MUTED_MIC: Microphone = Microphone { muted: true };
588 let mut v2 = InputInfoSourcesV2::default();
589 v2.input_device_state.set_source_state(
590 InputDeviceType::CAMERA,
591 DEFAULT_CAMERA_NAME.to_string(),
592 DeviceStateSource::SOFTWARE,
593 DeviceState::AVAILABLE,
594 );
595 v2.input_device_state.set_source_state(
596 InputDeviceType::CAMERA,
597 DEFAULT_CAMERA_NAME.to_string(),
598 DeviceStateSource::HARDWARE,
599 DeviceState::MUTED,
600 );
601 v2.sw_microphone = MUTED_MIC;
602
603 let serialized_v2 = v2.serialize_to();
604 let current = InputInfoSources::try_deserialize_from(&serialized_v2)
605 .expect("deserialization should succeed");
606 let mut expected_input_state = InputState::new();
607
608 expected_input_state.set_source_state(
609 InputDeviceType::MICROPHONE,
610 DEFAULT_MIC_NAME.to_string(),
611 DeviceStateSource::SOFTWARE,
612 DeviceState::MUTED,
613 );
614 expected_input_state.set_source_state(
615 InputDeviceType::MICROPHONE,
616 DEFAULT_MIC_NAME.to_string(),
617 DeviceStateSource::HARDWARE,
618 DeviceState::AVAILABLE,
619 );
620 expected_input_state.set_source_state(
621 InputDeviceType::CAMERA,
622 DEFAULT_CAMERA_NAME.to_string(),
623 DeviceStateSource::SOFTWARE,
624 DeviceState::AVAILABLE,
625 );
626 expected_input_state.set_source_state(
627 InputDeviceType::CAMERA,
628 DEFAULT_CAMERA_NAME.to_string(),
629 DeviceStateSource::HARDWARE,
630 DeviceState::MUTED,
631 );
632
633 assert_eq!(current.input_device_state, expected_input_state);
634 }
635
636 #[fuchsia::test]
637 async fn test_camera_error_on_restore() {
638 let (event_tx, _event_rx) = mpsc::unbounded();
639 let external_publisher = ExternalEventPublisher::new(event_tx);
640 let storage_factory = InMemoryStorageFactory::new();
641 storage_factory
642 .initialize::<InputController>()
643 .await
644 .expect("controller should have impls");
645 let (value_tx, _value_rx) = mpsc::unbounded();
646 let setting_value_publisher = SettingValuePublisher::new(value_tx);
647 let mut controller: InputController =
648 InputController::create_with_config::<InMemoryStorageFactory>(
649 Rc::new(ServiceContext::new(None)),
650 InputConfiguration {
651 devices: vec![InputDeviceConfiguration {
652 device_name: DEFAULT_CAMERA_NAME.to_string(),
653 device_type: InputDeviceType::CAMERA,
654 source_states: vec![SourceState {
655 source: DeviceStateSource::SOFTWARE,
656 state: 0,
657 }],
658 mutable_toggle_state: 0,
659 }],
660 },
661 &storage_factory,
662 setting_value_publisher,
663 external_publisher,
664 )
665 .await;
666
667 let result = controller.restore().await;
669 assert!(result.is_ok());
670
671 let camera_state = controller
673 .input_device_state
674 .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
675 .unwrap();
676 assert!(camera_state.has_state(DeviceState::ERROR));
677 }
678
679 #[fasync::run_until_stalled(test)]
680 async fn test_controller_creation_with_default_config() {
681 let config_logger = InspectConfigLogger::new(component::inspector().root());
682 let mut default_setting = DefaultSetting::new(
683 Some(InputConfiguration::default()),
684 "/config/data/input_device_config.json",
685 Rc::new(std::sync::Mutex::new(config_logger)),
686 );
687
688 let (event_tx, _) = mpsc::unbounded();
689 let external_publisher = ExternalEventPublisher::new(event_tx);
690
691 let storage_factory = InMemoryStorageFactory::new();
692 storage_factory
693 .initialize::<InputController>()
694 .await
695 .expect("controller should have impls");
696 let (value_tx, _value_rx) = mpsc::unbounded();
697 let setting_value_publisher = SettingValuePublisher::new(value_tx);
698 let _controller = InputController::new(
699 Rc::new(ServiceContext::new(None)),
700 &mut default_setting,
701 Rc::new(storage_factory),
702 setting_value_publisher,
703 external_publisher,
704 )
705 .await
706 .expect("Should have controller");
707 }
708}