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 super::input_fidl_handler::Publisher;
6use crate::input::input_device_configuration::InputConfiguration;
7use crate::input::types::{
8    DeviceState, DeviceStateSource, InputDevice, InputDeviceType, InputInfo, InputInfoSources,
9    InputState, Microphone,
10};
11use anyhow::{Context, Error};
12use fuchsia_async as fasync;
13use futures::StreamExt;
14use futures::channel::mpsc::UnboundedReceiver;
15use futures::channel::oneshot::Sender;
16use serde::{Deserialize, Serialize};
17use settings_camera::connect_to_camera;
18use settings_common::config::default_settings::DefaultSetting;
19use settings_common::inspect::event::{
20    ExternalEventPublisher, ResponseType, SettingValuePublisher,
21};
22use settings_common::service_context::ServiceContext;
23use settings_media_buttons::{Event, MediaButtons};
24use settings_storage::UpdateState;
25use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
26use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
27use std::borrow::Cow;
28use std::rc::Rc;
29
30pub(crate) const DEFAULT_CAMERA_NAME: &str = "camera";
31pub(crate) const DEFAULT_MIC_NAME: &str = "microphone";
32
33type UpdateInputResult = Result<Option<InputInfo>, InputError>;
34fn check_publish(
35    result: UpdateInputResult,
36    publish: impl Fn(InputInfo),
37) -> Result<Option<()>, InputError> {
38    result.map(|info| info.map(publish))
39}
40
41#[derive(thiserror::Error, Debug)]
42pub(crate) enum InputError {
43    #[error("Failed to initialize controller: {0:?}")]
44    InitFailure(Error),
45    #[error("Unsupported device type: {0:?}")]
46    Unsupported(InputDeviceType),
47    #[error("External failure for Input dependency: {0:?} request:{1:?} error:{2}")]
48    ExternalFailure(Cow<'static, str>, Cow<'static, str>, Cow<'static, str>),
49    #[error("Write failed for Input: {0:?}")]
50    WriteFailure(Error),
51    #[error("Unexpected error: {0}")]
52    UnexpectedError(Cow<'static, str>),
53}
54
55impl From<&InputError> for ResponseType {
56    fn from(error: &InputError) -> Self {
57        match error {
58            InputError::InitFailure(..) => ResponseType::InitFailure,
59            InputError::Unsupported(..) => ResponseType::UnsupportedError,
60            InputError::ExternalFailure(..) => ResponseType::ExternalFailure,
61            InputError::WriteFailure(..) => ResponseType::StorageFailure,
62            InputError::UnexpectedError(..) => ResponseType::UnexpectedError,
63        }
64    }
65}
66
67impl DeviceStorageCompatible for InputInfoSources {
68    type Loader = NoneT;
69    const KEY: &'static str = "input_info";
70
71    fn try_deserialize_from(value: &str) -> Result<Self, Error> {
72        Self::extract(value).or_else(|e| {
73            log::info!("Failed to deserialize InputInfoSources. Falling back to V2: {e:?}");
74            InputInfoSourcesV2::try_deserialize_from(value).map(Self::from)
75        })
76    }
77}
78
79impl From<InputInfoSourcesV2> for InputInfoSources {
80    fn from(v2: InputInfoSourcesV2) -> Self {
81        let mut input_state = v2.input_device_state;
82
83        // 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::input_device_configuration::{InputDeviceConfiguration, SourceState};
540    use fuchsia_async as fasync;
541    use fuchsia_inspect::component;
542    use futures::channel::mpsc;
543    use settings_common::inspect::config_logger::InspectConfigLogger;
544    use settings_common::service_context::ServiceContext;
545    use settings_test_common::storage::InMemoryStorageFactory;
546
547    #[fuchsia::test]
548    fn test_input_migration_v1_to_current() {
549        const MUTED_MIC: Microphone = Microphone { muted: true };
550        let mut v1 = InputInfoSourcesV1::default();
551        v1.sw_microphone = MUTED_MIC;
552
553        let serialized_v1 = v1.serialize_to();
554        let current = InputInfoSources::try_deserialize_from(&serialized_v1)
555            .expect("deserialization should succeed");
556        let mut expected_input_state = InputState::new();
557        expected_input_state.set_source_state(
558            InputDeviceType::MICROPHONE,
559            DEFAULT_MIC_NAME.to_string(),
560            DeviceStateSource::SOFTWARE,
561            DeviceState::MUTED,
562        );
563        expected_input_state.set_source_state(
564            InputDeviceType::MICROPHONE,
565            DEFAULT_MIC_NAME.to_string(),
566            DeviceStateSource::HARDWARE,
567            DeviceState::AVAILABLE,
568        );
569        assert_eq!(current.input_device_state, expected_input_state);
570    }
571
572    #[fuchsia::test]
573    fn test_input_migration_v1_to_v2() {
574        const MUTED_MIC: Microphone = Microphone { muted: true };
575        let mut v1 = InputInfoSourcesV1::default();
576        v1.sw_microphone = MUTED_MIC;
577
578        let serialized_v1 = v1.serialize_to();
579        let v2 = InputInfoSourcesV2::try_deserialize_from(&serialized_v1)
580            .expect("deserialization should succeed");
581
582        assert_eq!(v2.hw_microphone, Microphone { muted: false });
583        assert_eq!(v2.sw_microphone, MUTED_MIC);
584        assert_eq!(v2.input_device_state, InputState::new());
585    }
586
587    #[fuchsia::test]
588    fn test_input_migration_v2_to_current() {
589        const DEFAULT_CAMERA_NAME: &str = "camera";
590        const MUTED_MIC: Microphone = Microphone { muted: true };
591        let mut v2 = InputInfoSourcesV2::default();
592        v2.input_device_state.set_source_state(
593            InputDeviceType::CAMERA,
594            DEFAULT_CAMERA_NAME.to_string(),
595            DeviceStateSource::SOFTWARE,
596            DeviceState::AVAILABLE,
597        );
598        v2.input_device_state.set_source_state(
599            InputDeviceType::CAMERA,
600            DEFAULT_CAMERA_NAME.to_string(),
601            DeviceStateSource::HARDWARE,
602            DeviceState::MUTED,
603        );
604        v2.sw_microphone = MUTED_MIC;
605
606        let serialized_v2 = v2.serialize_to();
607        let current = InputInfoSources::try_deserialize_from(&serialized_v2)
608            .expect("deserialization should succeed");
609        let mut expected_input_state = InputState::new();
610
611        expected_input_state.set_source_state(
612            InputDeviceType::MICROPHONE,
613            DEFAULT_MIC_NAME.to_string(),
614            DeviceStateSource::SOFTWARE,
615            DeviceState::MUTED,
616        );
617        expected_input_state.set_source_state(
618            InputDeviceType::MICROPHONE,
619            DEFAULT_MIC_NAME.to_string(),
620            DeviceStateSource::HARDWARE,
621            DeviceState::AVAILABLE,
622        );
623        expected_input_state.set_source_state(
624            InputDeviceType::CAMERA,
625            DEFAULT_CAMERA_NAME.to_string(),
626            DeviceStateSource::SOFTWARE,
627            DeviceState::AVAILABLE,
628        );
629        expected_input_state.set_source_state(
630            InputDeviceType::CAMERA,
631            DEFAULT_CAMERA_NAME.to_string(),
632            DeviceStateSource::HARDWARE,
633            DeviceState::MUTED,
634        );
635
636        assert_eq!(current.input_device_state, expected_input_state);
637    }
638
639    #[fuchsia::test]
640    async fn test_camera_error_on_restore() {
641        let (event_tx, _event_rx) = mpsc::unbounded();
642        let external_publisher = ExternalEventPublisher::new(event_tx);
643        let storage_factory = InMemoryStorageFactory::new();
644        storage_factory
645            .initialize::<InputController>()
646            .await
647            .expect("controller should have impls");
648        let (value_tx, _value_rx) = mpsc::unbounded();
649        let setting_value_publisher = SettingValuePublisher::new(value_tx);
650        let mut controller: InputController =
651            InputController::create_with_config::<InMemoryStorageFactory>(
652                Rc::new(ServiceContext::new(None)),
653                InputConfiguration {
654                    devices: vec![InputDeviceConfiguration {
655                        device_name: DEFAULT_CAMERA_NAME.to_string(),
656                        device_type: InputDeviceType::CAMERA,
657                        source_states: vec![SourceState {
658                            source: DeviceStateSource::SOFTWARE,
659                            state: 0,
660                        }],
661                        mutable_toggle_state: 0,
662                    }],
663                },
664                &storage_factory,
665                setting_value_publisher,
666                external_publisher,
667            )
668            .await;
669
670        // Restore should pass.
671        let result = controller.restore().await;
672        assert!(result.is_ok());
673
674        // But the camera state should show an error.
675        let camera_state = controller
676            .input_device_state
677            .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
678            .unwrap();
679        assert!(camera_state.has_state(DeviceState::ERROR));
680    }
681
682    #[fasync::run_until_stalled(test)]
683    async fn test_controller_creation_with_default_config() {
684        let config_logger = InspectConfigLogger::new(component::inspector().root());
685        let mut default_setting = DefaultSetting::new(
686            Some(InputConfiguration::default()),
687            "/config/data/input_device_config.json",
688            Rc::new(std::sync::Mutex::new(config_logger)),
689        );
690
691        let (event_tx, _) = mpsc::unbounded();
692        let external_publisher = ExternalEventPublisher::new(event_tx);
693
694        let storage_factory = InMemoryStorageFactory::new();
695        storage_factory
696            .initialize::<InputController>()
697            .await
698            .expect("controller should have impls");
699        let (value_tx, _value_rx) = mpsc::unbounded();
700        let setting_value_publisher = SettingValuePublisher::new(value_tx);
701        let _controller = InputController::new(
702            Rc::new(ServiceContext::new(None)),
703            &mut default_setting,
704            Rc::new(storage_factory),
705            setting_value_publisher,
706            external_publisher,
707        )
708        .await
709        .expect("Should have controller");
710    }
711}