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
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        // Convert the old states into an input device.
84        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    /// Persistent storage.
154    store: Rc<DeviceStorage>,
155
156    /// Local tracking of the input device states.
157    input_device_state: InputState,
158
159    /// Configuration for this device.
160    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    /// Alternate constructor that allows specifying a configuration.
199    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    // Whether the configuration for this device contains a specific |device_type|.
221    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    // Wrapper around client.read() that fills in the config
321    // as the default value if the read value is empty. It may be empty
322    // after a migration from a previous InputInfoSources version
323    // or on pave.
324    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    /// Restores the input state.
333    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                    // Camera setup failure should not prevent start of service. This also allows
342                    // clients to see that the camera may not be usable.
343                    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    /// Sets the hardware mic/cam state from the muted states in `media_buttons`.
381    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            // Fetch current state.
397            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                // Unset available and set muted.
411                hw_state &= !DeviceState::AVAILABLE;
412                hw_state |= DeviceState::MUTED;
413            } else {
414                // Set available and unset muted.
415                hw_state |= DeviceState::AVAILABLE;
416                hw_state &= !DeviceState::MUTED;
417            }
418
419            // Set the updated state.
420            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    /// Sets state for the given input devices.
443    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        // If the device has a camera, it should successfully get the sw state, and
462        // push the state if it has changed. If the device does not have a camera,
463        // it should be None both here and above, and thus not detect a change.
464        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)] // TODO(https://fxbug.dev/42069089)
480    /// Pulls the current software state of the camera from the device state.
481    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    /// Set the camera state into an error condition.
496    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    /// Forwards the given software state to the camera3 api. Will first establish
507    /// a connection to the camera3.DeviceWatcher api. This function should only be called
508    /// when there is a camera included in the config. The config is used to populate the
509    /// stored input_info, so the input_info's input_device_state can be checked whether its
510    /// device_types contains Camera prior to calling this function.
511    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        // Start up a connection to the camera device watcher and connect to the
515        // camera proxy using the id that is returned. The connection will drop out
516        // of scope after the mute state is sent.
517        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_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 v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
551
552        let serialized_v1 = v1.serialize_to();
553        let current = InputInfoSources::try_deserialize_from(&serialized_v1)
554            .expect("deserialization should succeed");
555        let mut expected_input_state = InputState::new();
556        expected_input_state.set_source_state(
557            InputDeviceType::MICROPHONE,
558            DEFAULT_MIC_NAME.to_string(),
559            DeviceStateSource::SOFTWARE,
560            DeviceState::MUTED,
561        );
562        expected_input_state.set_source_state(
563            InputDeviceType::MICROPHONE,
564            DEFAULT_MIC_NAME.to_string(),
565            DeviceStateSource::HARDWARE,
566            DeviceState::AVAILABLE,
567        );
568        assert_eq!(current.input_device_state, expected_input_state);
569    }
570
571    #[fuchsia::test]
572    fn test_input_migration_v1_to_v2() {
573        const MUTED_MIC: Microphone = Microphone { muted: true };
574        let v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
575
576        let serialized_v1 = v1.serialize_to();
577        let v2 = InputInfoSourcesV2::try_deserialize_from(&serialized_v1)
578            .expect("deserialization should succeed");
579
580        assert_eq!(v2.hw_microphone, Microphone { muted: false });
581        assert_eq!(v2.sw_microphone, MUTED_MIC);
582        assert_eq!(v2.input_device_state, InputState::new());
583    }
584
585    #[fuchsia::test]
586    fn test_input_migration_v2_to_current() {
587        const DEFAULT_CAMERA_NAME: &str = "camera";
588        const MUTED_MIC: Microphone = Microphone { muted: true };
589        let mut v2 = InputInfoSourcesV2::default();
590        v2.input_device_state.set_source_state(
591            InputDeviceType::CAMERA,
592            DEFAULT_CAMERA_NAME.to_string(),
593            DeviceStateSource::SOFTWARE,
594            DeviceState::AVAILABLE,
595        );
596        v2.input_device_state.set_source_state(
597            InputDeviceType::CAMERA,
598            DEFAULT_CAMERA_NAME.to_string(),
599            DeviceStateSource::HARDWARE,
600            DeviceState::MUTED,
601        );
602        v2.sw_microphone = MUTED_MIC;
603
604        let serialized_v2 = v2.serialize_to();
605        let current = InputInfoSources::try_deserialize_from(&serialized_v2)
606            .expect("deserialization should succeed");
607        let mut expected_input_state = InputState::new();
608
609        expected_input_state.set_source_state(
610            InputDeviceType::MICROPHONE,
611            DEFAULT_MIC_NAME.to_string(),
612            DeviceStateSource::SOFTWARE,
613            DeviceState::MUTED,
614        );
615        expected_input_state.set_source_state(
616            InputDeviceType::MICROPHONE,
617            DEFAULT_MIC_NAME.to_string(),
618            DeviceStateSource::HARDWARE,
619            DeviceState::AVAILABLE,
620        );
621        expected_input_state.set_source_state(
622            InputDeviceType::CAMERA,
623            DEFAULT_CAMERA_NAME.to_string(),
624            DeviceStateSource::SOFTWARE,
625            DeviceState::AVAILABLE,
626        );
627        expected_input_state.set_source_state(
628            InputDeviceType::CAMERA,
629            DEFAULT_CAMERA_NAME.to_string(),
630            DeviceStateSource::HARDWARE,
631            DeviceState::MUTED,
632        );
633
634        assert_eq!(current.input_device_state, expected_input_state);
635    }
636
637    #[fuchsia::test]
638    async fn test_camera_error_on_restore() {
639        let (event_tx, _event_rx) = mpsc::unbounded();
640        let external_publisher = ExternalEventPublisher::new(event_tx);
641        let storage_factory = InMemoryStorageFactory::new();
642        storage_factory
643            .initialize::<InputController>()
644            .await
645            .expect("controller should have impls");
646        let (value_tx, _value_rx) = mpsc::unbounded();
647        let setting_value_publisher = SettingValuePublisher::new(value_tx);
648        let mut controller: InputController =
649            InputController::create_with_config::<InMemoryStorageFactory>(
650                Rc::new(ServiceContext::new(None)),
651                InputConfiguration {
652                    devices: vec![InputDeviceConfiguration {
653                        device_name: DEFAULT_CAMERA_NAME.to_string(),
654                        device_type: InputDeviceType::CAMERA,
655                        source_states: vec![SourceState {
656                            source: DeviceStateSource::SOFTWARE,
657                            state: 0,
658                        }],
659                        mutable_toggle_state: 0,
660                    }],
661                },
662                &storage_factory,
663                setting_value_publisher,
664                external_publisher,
665            )
666            .await;
667
668        // Restore should pass.
669        let result = controller.restore().await;
670        assert!(result.is_ok());
671
672        // But the camera state should show an error.
673        let camera_state = controller
674            .input_device_state
675            .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
676            .unwrap();
677        assert!(camera_state.has_state(DeviceState::ERROR));
678    }
679
680    #[fasync::run_until_stalled(test)]
681    async fn test_controller_creation_with_default_config() {
682        let config_logger = InspectConfigLogger::new(component::inspector().root());
683        let mut default_setting = DefaultSetting::new(
684            Some(InputConfiguration::default()),
685            "/config/data/input_device_config.json",
686            Rc::new(std::sync::Mutex::new(config_logger)),
687        );
688
689        let (event_tx, _) = mpsc::unbounded();
690        let external_publisher = ExternalEventPublisher::new(event_tx);
691
692        let storage_factory = InMemoryStorageFactory::new();
693        storage_factory
694            .initialize::<InputController>()
695            .await
696            .expect("controller should have impls");
697        let (value_tx, _value_rx) = mpsc::unbounded();
698        let setting_value_publisher = SettingValuePublisher::new(value_tx);
699        let _controller = InputController::new(
700            Rc::new(ServiceContext::new(None)),
701            &mut default_setting,
702            Rc::new(storage_factory),
703            setting_value_publisher,
704            external_publisher,
705        )
706        .await
707        .expect("Should have controller");
708    }
709}