Skip to main content

settings_input/
input_controller.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use 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
33// The MAX_INPUT_DEVICES, in conjunction with the FIDL API's constraint of 128-byte names, ensures
34// that we don't exceed the 64 KiB default transport limit for the API (with some padding). It also
35// lessens the chance that we OOM while loading the device list from disk to memory.
36pub(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        // Convert the old states into an input device.
94        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    /// Persistent storage.
164    store: Rc<DeviceStorage>,
165
166    /// Local tracking of the input device states.
167    input_device_state: InputState,
168
169    /// Configuration for this device.
170    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    /// Alternate constructor that allows specifying a configuration.
209    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    // Whether the configuration for this device contains a specific |device_type|.
231    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    // Wrapper around client.read() that fills in the config
331    // as the default value if the read value is empty. It may be empty
332    // after a migration from a previous InputInfoSources version
333    // or on pave.
334    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    /// Restores the input state.
343    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                    // Camera setup failure should not prevent start of service. This also allows
352                    // clients to see that the camera may not be usable.
353                    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    /// Sets the hardware mic/cam state from the muted states in `media_buttons`.
391    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            // Fetch current state.
407            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                // Unset available and set muted.
421                hw_state &= !DeviceState::AVAILABLE;
422                hw_state |= DeviceState::MUTED;
423            } else {
424                // Set available and unset muted.
425                hw_state |= DeviceState::AVAILABLE;
426                hw_state &= !DeviceState::MUTED;
427            }
428
429            // Set the updated state.
430            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    /// Sets state for the given input devices.
453    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        // Firstly, do a validation pass to make sure the input_devices contain only valid devices,
463        // and any newly added devices are not going to exceed our maximum device limit.
464        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        // Abort if applying these new devices would exceed the limit.
484        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        // Commit the new input_devices to storage.
495        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        // If the device has a camera, it should successfully get the sw state, and
501        // push the state if it has changed. If the device does not have a camera,
502        // it should be None both here and above, and thus not detect a change.
503        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    /// Pulls the current software state of the camera from the device state.
519    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    /// Set the camera state into an error condition.
534    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    /// Forwards the given software state to the camera3 api. Will first establish
545    /// a connection to the camera3.DeviceWatcher api. This function should only be called
546    /// when there is a camera included in the config. The config is used to populate the
547    /// stored input_info, so the input_info's input_device_state can be checked whether its
548    /// device_types contains Camera prior to calling this function.
549    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        // Start up a connection to the camera device watcher and connect to the
553        // camera proxy using the id that is returned. The connection will drop out
554        // of scope after the mute state is sent.
555        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        // Restore should pass.
707        let result = controller.restore().await;
708        assert!(result.is_ok());
709
710        // But the camera state should show an error.
711        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}