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