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::base::{SettingInfo, SettingType};
6use crate::handler::base::Request;
7use crate::handler::setting_handler::persist::{ClientProxy, controller as data_controller};
8use crate::handler::setting_handler::{
9    ControllerError, ControllerStateResult, IntoHandlerResult, SettingHandlerResult, State,
10    controller,
11};
12use crate::input::input_device_configuration::InputConfiguration;
13use crate::input::types::{
14    DeviceState, DeviceStateSource, InputDevice, InputDeviceType, InputInfo, InputInfoSources,
15    InputState, Microphone,
16};
17use settings_camera::connect_to_camera;
18use settings_common::config::default_settings::DefaultSetting;
19use settings_common::inspect::event::ExternalEventPublisher;
20use settings_media_buttons::MediaButtons;
21use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
22use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
23
24use anyhow::Error;
25use async_trait::async_trait;
26use fuchsia_trace as ftrace;
27use futures::lock::Mutex;
28use serde::{Deserialize, Serialize};
29use std::marker::PhantomData;
30use std::rc::Rc;
31
32pub(crate) const DEFAULT_CAMERA_NAME: &str = "camera";
33pub(crate) const DEFAULT_MIC_NAME: &str = "microphone";
34
35impl DeviceStorageCompatible for InputInfoSources {
36    type Loader = NoneT;
37    const KEY: &'static str = "input_info";
38
39    fn try_deserialize_from(value: &str) -> Result<Self, Error> {
40        Self::extract(value).or_else(|e| {
41            log::info!("Failed to deserialize InputInfoSources. Falling back to V2: {e:?}");
42            InputInfoSourcesV2::try_deserialize_from(value).map(Self::from)
43        })
44    }
45}
46
47impl From<InputInfoSourcesV2> for InputInfoSources {
48    fn from(v2: InputInfoSourcesV2) -> Self {
49        let mut input_state = v2.input_device_state;
50
51        // Convert the old states into an input device.
52        input_state.set_source_state(
53            InputDeviceType::MICROPHONE,
54            DEFAULT_MIC_NAME.to_string(),
55            DeviceStateSource::HARDWARE,
56            if v2.hw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
57        );
58        input_state.set_source_state(
59            InputDeviceType::MICROPHONE,
60            DEFAULT_MIC_NAME.to_string(),
61            DeviceStateSource::SOFTWARE,
62            if v2.sw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
63        );
64
65        InputInfoSources { input_device_state: input_state }
66    }
67}
68
69impl From<InputInfoSources> for SettingInfo {
70    fn from(info: InputInfoSources) -> SettingInfo {
71        SettingInfo::Input(info.into())
72    }
73}
74
75impl From<InputInfoSources> for InputInfo {
76    fn from(info: InputInfoSources) -> InputInfo {
77        InputInfo { input_device_state: info.input_device_state }
78    }
79}
80
81impl From<InputInfo> for SettingInfo {
82    fn from(info: InputInfo) -> SettingInfo {
83        SettingInfo::Input(info)
84    }
85}
86
87impl From<&InputInfo> for SettingType {
88    fn from(_: &InputInfo) -> SettingType {
89        SettingType::Input
90    }
91}
92
93#[derive(PartialEq, Default, Debug, Clone, Serialize, Deserialize)]
94pub struct InputInfoSourcesV2 {
95    hw_microphone: Microphone,
96    sw_microphone: Microphone,
97    input_device_state: InputState,
98}
99
100impl DeviceStorageCompatible for InputInfoSourcesV2 {
101    type Loader = NoneT;
102    const KEY: &'static str = "input_info_sources_v2";
103
104    fn try_deserialize_from(value: &str) -> Result<Self, Error> {
105        Self::extract(value).or_else(|e| {
106            log::info!("Failed to deserialize InputInfoSourcesV2. Falling back to V1: {e:?}");
107            InputInfoSourcesV1::try_deserialize_from(value).map(Self::from)
108        })
109    }
110}
111
112impl From<InputInfoSourcesV1> for InputInfoSourcesV2 {
113    fn from(v1: InputInfoSourcesV1) -> Self {
114        InputInfoSourcesV2 {
115            hw_microphone: v1.hw_microphone,
116            sw_microphone: v1.sw_microphone,
117            input_device_state: InputState::new(),
118        }
119    }
120}
121
122#[derive(PartialEq, Default, Debug, Clone, Copy, Serialize, Deserialize)]
123pub struct InputInfoSourcesV1 {
124    pub hw_microphone: Microphone,
125    pub sw_microphone: Microphone,
126}
127
128impl DeviceStorageCompatible for InputInfoSourcesV1 {
129    type Loader = NoneT;
130    const KEY: &'static str = "input_info_sources_v1";
131}
132
133type InputControllerInnerHandle = Rc<Mutex<InputControllerInner>>;
134
135/// Inner struct for the InputController.
136///
137/// Allows the controller to use a lock on its contents.
138struct InputControllerInner {
139    /// Client to communicate with persistent store and notify on.
140    client: ClientProxy,
141
142    /// Persistent storage.
143    store: Rc<DeviceStorage>,
144
145    /// Local tracking of the input device states.
146    input_device_state: InputState,
147
148    /// Configuration for this device.
149    input_device_config: InputConfiguration,
150
151    external_publisher: ExternalEventPublisher,
152}
153
154impl InputControllerInner {
155    // Wrapper around client.read() that fills in the config
156    // as the default value if the read value is empty. It may be empty
157    // after a migration from a previous InputInfoSources version
158    // or on pave.
159    async fn get_stored_info(&self) -> InputInfo {
160        let mut input_info = InputInfo::from(self.store.get::<InputInfo>().await);
161        if input_info.input_device_state.is_empty() {
162            input_info.input_device_state = self.input_device_config.clone().into();
163        }
164        input_info
165    }
166
167    /// Gets the input state.
168    async fn get_info(&mut self) -> Result<InputInfo, ControllerError> {
169        Ok(InputInfo { input_device_state: self.input_device_state.clone() })
170    }
171
172    /// Restores the input state.
173    async fn restore(&mut self) -> ControllerStateResult {
174        let input_info = self.get_stored_info().await;
175        self.input_device_state = input_info.input_device_state;
176
177        if self.input_device_config.devices.iter().any(|d| d.device_type == InputDeviceType::CAMERA)
178        {
179            match self.get_cam_sw_state() {
180                Ok(state) => {
181                    // Camera setup failure should not prevent start of service. This also allows
182                    // clients to see that the camera may not be usable.
183                    if let Err(e) = self.push_cam_sw_state(state).await {
184                        log::error!("Unable to restore camera state: {e:?}");
185                        self.set_cam_err_state(state);
186                    }
187                }
188                Err(e) => {
189                    log::error!("Unable to load cam sw state: {e:?}");
190                    self.set_cam_err_state(DeviceState::ERROR);
191                }
192            }
193        }
194        Ok(())
195    }
196
197    async fn set_sw_camera_mute(&mut self, disabled: bool, name: String) -> SettingHandlerResult {
198        let mut input_info = self.get_stored_info().await;
199        input_info.input_device_state.set_source_state(
200            InputDeviceType::CAMERA,
201            name.clone(),
202            DeviceStateSource::SOFTWARE,
203            if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
204        );
205
206        self.input_device_state.set_source_state(
207            InputDeviceType::CAMERA,
208            name.clone(),
209            DeviceStateSource::SOFTWARE,
210            if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
211        );
212        let id = ftrace::Id::new();
213        self.client.storage_write(&self.store, input_info, id).await.into_handler_result()
214    }
215
216    /// Sets the hardware mic/cam state from the muted states in `media_buttons`.
217    async fn set_hw_media_buttons_state(
218        &mut self,
219        media_buttons: MediaButtons,
220    ) -> SettingHandlerResult {
221        let mut states_to_process = Vec::new();
222        if let Some(mic_mute) = media_buttons.mic_mute {
223            states_to_process.push((InputDeviceType::MICROPHONE, mic_mute));
224        }
225        if let Some(camera_disable) = media_buttons.camera_disable {
226            states_to_process.push((InputDeviceType::CAMERA, camera_disable));
227        }
228
229        let mut input_info = self.get_stored_info().await;
230
231        for (device_type, muted) in states_to_process.into_iter() {
232            // Fetch current state.
233            let hw_state_res = input_info.input_device_state.get_source_state(
234                device_type,
235                device_type.to_string(),
236                DeviceStateSource::HARDWARE,
237            );
238
239            let mut hw_state = hw_state_res.map_err(|err| {
240                ControllerError::UnexpectedError(
241                    format!("Could not fetch current hw mute state: {err:?}").into(),
242                )
243            })?;
244
245            if muted {
246                // Unset available and set muted.
247                hw_state &= !DeviceState::AVAILABLE;
248                hw_state |= DeviceState::MUTED;
249            } else {
250                // Set available and unset muted.
251                hw_state |= DeviceState::AVAILABLE;
252                hw_state &= !DeviceState::MUTED;
253            }
254
255            // Set the updated state.
256            input_info.input_device_state.set_source_state(
257                device_type,
258                device_type.to_string(),
259                DeviceStateSource::HARDWARE,
260                hw_state,
261            );
262            self.input_device_state.set_source_state(
263                device_type,
264                device_type.to_string(),
265                DeviceStateSource::HARDWARE,
266                hw_state,
267            );
268        }
269
270        // Store the newly set value.
271        let id = ftrace::Id::new();
272        self.client.storage_write(&self.store, input_info, id).await.into_handler_result()
273    }
274
275    /// Sets state for the given input devices.
276    async fn set_input_states(
277        &mut self,
278        input_devices: Vec<InputDevice>,
279        source: DeviceStateSource,
280    ) -> SettingHandlerResult {
281        let mut input_info = self.get_stored_info().await;
282        let device_types = input_info.input_device_state.device_types();
283
284        let cam_state = self.get_cam_sw_state().ok();
285
286        for input_device in input_devices.iter() {
287            if !device_types.contains(&input_device.device_type) {
288                return Err(ControllerError::UnsupportedError(SettingType::Input));
289            }
290            input_info.input_device_state.insert_device(input_device.clone(), source);
291            self.input_device_state.insert_device(input_device.clone(), source);
292        }
293
294        // If the device has a camera, it should successfully get the sw state, and
295        // push the state if it has changed. If the device does not have a camera,
296        // it should be None both here and above, and thus not detect a change.
297        let modified_cam_state = self.get_cam_sw_state().ok();
298        if cam_state != modified_cam_state {
299            if let Some(state) = modified_cam_state {
300                self.push_cam_sw_state(state).await?;
301            }
302        }
303
304        // Store the newly set value.
305        let id = ftrace::Id::new();
306        self.client.storage_write(&self.store, input_info, id).await.into_handler_result()
307    }
308
309    #[allow(clippy::result_large_err)] // TODO(https://fxbug.dev/42069089)
310    /// Pulls the current software state of the camera from the device state.
311    fn get_cam_sw_state(&self) -> Result<DeviceState, ControllerError> {
312        self.input_device_state
313            .get_source_state(
314                InputDeviceType::CAMERA,
315                DEFAULT_CAMERA_NAME.to_string(),
316                DeviceStateSource::SOFTWARE,
317            )
318            .map_err(|_| {
319                ControllerError::UnexpectedError("Could not find camera software state".into())
320            })
321    }
322
323    /// Set the camera state into an error condition.
324    fn set_cam_err_state(&mut self, mut state: DeviceState) {
325        state.set(DeviceState::ERROR, true);
326        self.input_device_state.set_source_state(
327            InputDeviceType::CAMERA,
328            DEFAULT_CAMERA_NAME.to_string(),
329            DeviceStateSource::SOFTWARE,
330            state,
331        )
332    }
333
334    /// Forwards the given software state to the camera3 api. Will first establish
335    /// a connection to the camera3.DeviceWatcher api. This function should only be called
336    /// when there is a camera included in the config. The config is used to populate the
337    /// stored input_info, so the input_info's input_device_state can be checked whether its
338    /// device_types contains Camera prior to calling this function.
339    async fn push_cam_sw_state(&mut self, cam_state: DeviceState) -> Result<(), ControllerError> {
340        let is_muted = cam_state.has_state(DeviceState::MUTED);
341
342        // Start up a connection to the camera device watcher and connect to the
343        // camera proxy using the id that is returned. The connection will drop out
344        // of scope after the mute state is sent.
345        let camera_proxy = connect_to_camera(
346            &*self.client.get_service_context().common_context(),
347            self.external_publisher.clone(),
348        )
349        .await
350        .map_err(|e| {
351            ControllerError::UnexpectedError(
352                format!("Could not connect to camera device: {e:?}").into(),
353            )
354        })?;
355
356        camera_proxy.set_software_mute_state(is_muted).await.map_err(|e| {
357            ControllerError::ExternalFailure(
358                SettingType::Input,
359                "fuchsia.camera3.Device".into(),
360                "SetSoftwareMuteState".into(),
361                format!("{e:?}").into(),
362            )
363        })
364    }
365}
366
367pub struct InputController<F> {
368    /// Handle so that a lock can be used in the Handle trait implementation.
369    inner: InputControllerInnerHandle,
370    _phantom: PhantomData<F>,
371}
372
373impl<F> StorageAccess for InputController<F> {
374    type Storage = DeviceStorage;
375    type Data = InputInfoSources;
376    const STORAGE_KEY: &'static str = InputInfoSources::KEY;
377}
378
379impl<F> InputController<F> {
380    /// Alternate constructor that allows specifying a configuration.
381    pub(crate) fn create_with_config(
382        client: ClientProxy,
383        input_device_config: InputConfiguration,
384        store: Rc<DeviceStorage>,
385        external_publisher: ExternalEventPublisher,
386    ) -> Result<Self, ControllerError> {
387        Ok(Self {
388            inner: Rc::new(Mutex::new(InputControllerInner {
389                client,
390                store,
391                input_device_state: InputState::new(),
392                input_device_config,
393                external_publisher,
394            })),
395            _phantom: PhantomData,
396        })
397    }
398
399    // Whether the configuration for this device contains a specific |device_type|.
400    async fn has_input_device(&self, device_type: InputDeviceType) -> bool {
401        let input_device_config_state: InputState =
402            self.inner.lock().await.input_device_config.clone().into();
403        input_device_config_state.device_types().contains(&device_type)
404    }
405}
406
407#[async_trait(?Send)]
408impl<F> data_controller::CreateWithAsync for InputController<F>
409where
410    F: StorageFactory<Storage = DeviceStorage>,
411{
412    type Data = (
413        Rc<F>,
414        Rc<std::sync::Mutex<DefaultSetting<InputConfiguration, &'static str>>>,
415        ExternalEventPublisher,
416    );
417    async fn create_with(client: ClientProxy, data: Self::Data) -> Result<Self, ControllerError> {
418        if let Ok(Some(config)) = data.1.lock().unwrap().load_default_value() {
419            let store = data.0.get_store().await;
420            InputController::create_with_config(client, config, store, data.2)
421        } else {
422            Err(ControllerError::InitFailure("Invalid default input device config".into()))
423        }
424    }
425}
426
427#[async_trait(?Send)]
428impl<F> controller::Handle for InputController<F> {
429    async fn handle(&self, request: Request) -> Option<SettingHandlerResult> {
430        match request {
431            Request::Restore => Some(self.inner.lock().await.restore().await.map(|_| None)),
432            Request::Get => Some(
433                self.inner.lock().await.get_info().await.map(|info| Some(SettingInfo::Input(info))),
434            ),
435            Request::OnCameraSWState(is_muted) => {
436                let old_state = match self
437                    .inner
438                    .lock()
439                    .await
440                    .get_stored_info()
441                    .await
442                    .input_device_state
443                    .get_source_state(
444                        InputDeviceType::CAMERA,
445                        DEFAULT_CAMERA_NAME.to_string(),
446                        DeviceStateSource::SOFTWARE,
447                    )
448                    .map_err(|_| {
449                        ControllerError::UnexpectedError(
450                            "Could not find camera software state".into(),
451                        )
452                    }) {
453                    Ok(state) => state,
454                    Err(e) => return Some(Err(e)),
455                };
456                Some(if old_state.has_state(DeviceState::MUTED) != is_muted {
457                    self.inner
458                        .lock()
459                        .await
460                        .set_sw_camera_mute(is_muted, DEFAULT_CAMERA_NAME.to_string())
461                        .await
462                } else {
463                    Ok(None)
464                })
465            }
466            Request::OnButton(mut buttons) => {
467                if buttons.mic_mute.is_some()
468                    && !self.has_input_device(InputDeviceType::MICROPHONE).await
469                {
470                    buttons.set_mic_mute(None);
471                }
472                if buttons.camera_disable.is_some()
473                    && !self.has_input_device(InputDeviceType::CAMERA).await
474                {
475                    buttons.set_camera_disable(None);
476                }
477                Some(self.inner.lock().await.set_hw_media_buttons_state(buttons).await)
478            }
479            Request::SetInputStates(input_states) => Some(
480                self.inner
481                    .lock()
482                    .await
483                    .set_input_states(input_states, DeviceStateSource::SOFTWARE)
484                    .await,
485            ),
486            _ => None,
487        }
488    }
489
490    async fn change_state(&mut self, state: State) -> Option<ControllerStateResult> {
491        match state {
492            State::Startup => Some(self.inner.lock().await.restore().await),
493            _ => None,
494        }
495    }
496}
497
498#[cfg(test)]
499mod tests {
500    use super::*;
501    use crate::handler::setting_handler::ClientImpl;
502    use crate::handler::setting_handler::controller::Handle;
503    use crate::input::input_device_configuration::{InputDeviceConfiguration, SourceState};
504    use crate::service;
505    use crate::service_context::ServiceContext;
506    use fuchsia_async as fasync;
507    use fuchsia_inspect::component;
508    use futures::channel::mpsc;
509    use settings_common::inspect::config_logger::InspectConfigLogger;
510    use settings_test_common::fakes::service::ServiceRegistry;
511    use settings_test_common::storage::InMemoryStorageFactory;
512
513    #[fuchsia::test]
514    fn test_input_migration_v1_to_current() {
515        const MUTED_MIC: Microphone = Microphone { muted: true };
516        let mut v1 = InputInfoSourcesV1::default();
517        v1.sw_microphone = MUTED_MIC;
518
519        let serialized_v1 = v1.serialize_to();
520        let current = InputInfoSources::try_deserialize_from(&serialized_v1)
521            .expect("deserialization should succeed");
522        let mut expected_input_state = InputState::new();
523        expected_input_state.set_source_state(
524            InputDeviceType::MICROPHONE,
525            DEFAULT_MIC_NAME.to_string(),
526            DeviceStateSource::SOFTWARE,
527            DeviceState::MUTED,
528        );
529        expected_input_state.set_source_state(
530            InputDeviceType::MICROPHONE,
531            DEFAULT_MIC_NAME.to_string(),
532            DeviceStateSource::HARDWARE,
533            DeviceState::AVAILABLE,
534        );
535        assert_eq!(current.input_device_state, expected_input_state);
536    }
537
538    #[fuchsia::test]
539    fn test_input_migration_v1_to_v2() {
540        const MUTED_MIC: Microphone = Microphone { muted: true };
541        let mut v1 = InputInfoSourcesV1::default();
542        v1.sw_microphone = MUTED_MIC;
543
544        let serialized_v1 = v1.serialize_to();
545        let v2 = InputInfoSourcesV2::try_deserialize_from(&serialized_v1)
546            .expect("deserialization should succeed");
547
548        assert_eq!(v2.hw_microphone, Microphone { muted: false });
549        assert_eq!(v2.sw_microphone, MUTED_MIC);
550        assert_eq!(v2.input_device_state, InputState::new());
551    }
552
553    #[fuchsia::test]
554    fn test_input_migration_v2_to_current() {
555        const DEFAULT_CAMERA_NAME: &str = "camera";
556        const MUTED_MIC: Microphone = Microphone { muted: true };
557        let mut v2 = InputInfoSourcesV2::default();
558        v2.input_device_state.set_source_state(
559            InputDeviceType::CAMERA,
560            DEFAULT_CAMERA_NAME.to_string(),
561            DeviceStateSource::SOFTWARE,
562            DeviceState::AVAILABLE,
563        );
564        v2.input_device_state.set_source_state(
565            InputDeviceType::CAMERA,
566            DEFAULT_CAMERA_NAME.to_string(),
567            DeviceStateSource::HARDWARE,
568            DeviceState::MUTED,
569        );
570        v2.sw_microphone = MUTED_MIC;
571
572        let serialized_v2 = v2.serialize_to();
573        let current = InputInfoSources::try_deserialize_from(&serialized_v2)
574            .expect("deserialization should succeed");
575        let mut expected_input_state = InputState::new();
576
577        expected_input_state.set_source_state(
578            InputDeviceType::MICROPHONE,
579            DEFAULT_MIC_NAME.to_string(),
580            DeviceStateSource::SOFTWARE,
581            DeviceState::MUTED,
582        );
583        expected_input_state.set_source_state(
584            InputDeviceType::MICROPHONE,
585            DEFAULT_MIC_NAME.to_string(),
586            DeviceStateSource::HARDWARE,
587            DeviceState::AVAILABLE,
588        );
589        expected_input_state.set_source_state(
590            InputDeviceType::CAMERA,
591            DEFAULT_CAMERA_NAME.to_string(),
592            DeviceStateSource::SOFTWARE,
593            DeviceState::AVAILABLE,
594        );
595        expected_input_state.set_source_state(
596            InputDeviceType::CAMERA,
597            DEFAULT_CAMERA_NAME.to_string(),
598            DeviceStateSource::HARDWARE,
599            DeviceState::MUTED,
600        );
601
602        assert_eq!(current.input_device_state, expected_input_state);
603    }
604
605    #[fasync::run_until_stalled(test)]
606    async fn test_camera_error_on_restore() {
607        let message_hub = service::MessageHub::create_hub();
608        let (event_tx, _event_rx) = mpsc::unbounded();
609        let external_publisher = ExternalEventPublisher::new(event_tx);
610
611        let storage_factory = InMemoryStorageFactory::new();
612        storage_factory
613            .initialize::<InputController<InMemoryStorageFactory>>()
614            .await
615            .expect("controller should have impls");
616        let store = storage_factory.get_store().await;
617        let client_proxy = create_proxy(message_hub).await;
618        let controller = InputController::<InMemoryStorageFactory>::create_with_config(
619            client_proxy,
620            InputConfiguration {
621                devices: vec![InputDeviceConfiguration {
622                    device_name: DEFAULT_CAMERA_NAME.to_string(),
623                    device_type: InputDeviceType::CAMERA,
624                    source_states: vec![SourceState {
625                        source: DeviceStateSource::SOFTWARE,
626                        state: 0,
627                    }],
628                    mutable_toggle_state: 0,
629                }],
630            },
631            store,
632            external_publisher,
633        )
634        .expect("Should have controller");
635
636        // Restore should pass.
637        let result = controller.handle(Request::Restore).await;
638        assert_eq!(result, Some(Ok(None)));
639
640        // But the camera state should show an error.
641        let result = controller.handle(Request::Get).await;
642        let Some(Ok(Some(SettingInfo::Input(input_info)))) = result else {
643            panic!("Expected Input response. Got {result:?}");
644        };
645        let camera_state = input_info
646            .input_device_state
647            .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
648            .unwrap();
649        assert!(camera_state.has_state(DeviceState::ERROR));
650    }
651
652    #[fasync::run_until_stalled(test)]
653    async fn test_controller_creation_with_default_config() {
654        use crate::handler::setting_handler::persist::controller::CreateWithAsync;
655
656        let message_hub = service::MessageHub::create_hub();
657        let client_proxy = create_proxy(message_hub).await;
658        let config_logger = InspectConfigLogger::new(component::inspector().root());
659        let default_setting = DefaultSetting::new(
660            Some(InputConfiguration::default()),
661            "/config/data/input_device_config.json",
662            Rc::new(std::sync::Mutex::new(config_logger)),
663        );
664
665        let (event_tx, _) = mpsc::unbounded();
666        let external_publisher = ExternalEventPublisher::new(event_tx);
667
668        let storage_factory = InMemoryStorageFactory::new();
669        storage_factory
670            .initialize::<InputController<InMemoryStorageFactory>>()
671            .await
672            .expect("controller should have impls");
673        let _controller = InputController::create_with(
674            client_proxy,
675            (
676                Rc::new(storage_factory),
677                Rc::new(std::sync::Mutex::new(default_setting)),
678                external_publisher,
679            ),
680        )
681        .await
682        .expect("Should have controller");
683    }
684
685    async fn create_proxy(message_hub: service::message::Delegate) -> ClientProxy {
686        // Create the messenger that the client proxy uses to send messages.
687        let (controller_messenger, _) = message_hub
688            .create(service::message::MessengerType::Unbound)
689            .await
690            .expect("Unable to create agent messenger");
691
692        // Note that no camera service is registered, to mimic scenarios where devices do not
693        // have a functioning camera service.
694        let service_registry = ServiceRegistry::create();
695
696        let service_context =
697            ServiceContext::new(Some(ServiceRegistry::serve(service_registry)), None);
698
699        // This isn't actually the signature for the notifier, but it's unused in this test, so just
700        // provide the signature of its own messenger to the client proxy.
701        let signature = controller_messenger.get_signature();
702
703        ClientProxy::new(
704            Rc::new(ClientImpl::for_test(
705                Default::default(),
706                controller_messenger,
707                signature,
708                Rc::new(service_context),
709                SettingType::Input,
710            )),
711            SettingType::Input,
712        )
713        .await
714    }
715}