1use crate::input_device_configuration::InputConfiguration;
6use crate::input_fidl_handler::Publisher;
7use crate::types::{
8 DeviceState, DeviceStateSource, InputDevice, InputDeviceType, InputInfo, InputInfoSources,
9 InputState, Microphone,
10};
11use anyhow::{Context, Error};
12use fuchsia_async as fasync;
13use futures::StreamExt;
14use futures::channel::mpsc::UnboundedReceiver;
15use futures::channel::oneshot::Sender;
16use serde::{Deserialize, Serialize};
17use settings_camera::{CameraWatcherEvent, connect_to_cameras};
18use settings_common::config::default_settings::DefaultSetting;
19use settings_common::inspect::event::{
20 ExternalEventPublisher, ResponseType, SettingValuePublisher,
21};
22use settings_common::service_context::ServiceContext;
23use settings_media_buttons::{Event, MediaButtons};
24use settings_storage::UpdateState;
25use settings_storage::device_storage::{DeviceStorage, DeviceStorageCompatible};
26use settings_storage::storage_factory::{NoneT, StorageAccess, StorageFactory};
27use std::borrow::Cow;
28use std::rc::Rc;
29
30pub(crate) const DEFAULT_CAMERA_NAME: &str = "camera";
31pub(crate) const DEFAULT_MIC_NAME: &str = "microphone";
32
33pub(crate) const MAX_INPUT_DEVICES: usize = fidl_fuchsia_settings::MAX_INPUT_DEVICES as usize;
37
38type UpdateInputResult = Result<Option<InputInfo>, InputError>;
39fn check_publish(
40 result: UpdateInputResult,
41 publish: impl Fn(InputInfo),
42) -> Result<Option<()>, InputError> {
43 result.map(|info| info.map(publish))
44}
45
46#[derive(thiserror::Error, Debug)]
47pub(crate) enum InputError {
48 #[error("Failed to initialize controller: {0:?}")]
49 InitFailure(Error),
50 #[error("Unsupported device type: {0:?}")]
51 Unsupported(InputDeviceType),
52 #[error("External failure for Input dependency: {0:?} request:{1:?} error:{2}")]
53 ExternalFailure(Cow<'static, str>, Cow<'static, str>, Cow<'static, str>),
54 #[error("Write failed for Input: {0:?}")]
55 WriteFailure(Error),
56 #[error("The maximum number of input devices has been reached.")]
57 MaximumInputDeviceLimitReached(Cow<'static, str>),
58 #[error("Unexpected error: {0}")]
59 UnexpectedError(Cow<'static, str>),
60}
61
62impl From<&InputError> for ResponseType {
63 fn from(error: &InputError) -> Self {
64 match error {
65 InputError::InitFailure(..) => ResponseType::InitFailure,
66 InputError::Unsupported(..) => ResponseType::UnsupportedError,
67 InputError::ExternalFailure(..) => ResponseType::ExternalFailure,
68 InputError::WriteFailure(..) => ResponseType::StorageFailure,
69 InputError::MaximumInputDeviceLimitReached(..) => {
70 ResponseType::MaximumInputDevicesReached
71 }
72 InputError::UnexpectedError(..) => ResponseType::UnexpectedError,
73 }
74 }
75}
76
77impl DeviceStorageCompatible for InputInfoSources {
78 type Loader = NoneT;
79 const KEY: &'static str = "input_info";
80
81 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
82 Self::extract(value).or_else(|e| {
83 log::info!("Failed to deserialize InputInfoSources. Falling back to V2: {e:?}");
84 InputInfoSourcesV2::try_deserialize_from(value).map(Self::from)
85 })
86 }
87}
88
89impl From<InputInfoSourcesV2> for InputInfoSources {
90 fn from(v2: InputInfoSourcesV2) -> Self {
91 let mut input_state = v2.input_device_state;
92
93 input_state.set_source_state(
95 InputDeviceType::MICROPHONE,
96 DEFAULT_MIC_NAME.to_string(),
97 DeviceStateSource::HARDWARE,
98 if v2.hw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
99 );
100 input_state.set_source_state(
101 InputDeviceType::MICROPHONE,
102 DEFAULT_MIC_NAME.to_string(),
103 DeviceStateSource::SOFTWARE,
104 if v2.sw_microphone.muted { DeviceState::MUTED } else { DeviceState::AVAILABLE },
105 );
106
107 InputInfoSources { input_device_state: input_state }
108 }
109}
110
111impl From<InputInfoSources> for InputInfo {
112 fn from(info: InputInfoSources) -> InputInfo {
113 InputInfo { input_device_state: info.input_device_state }
114 }
115}
116
117#[derive(PartialEq, Default, Debug, Clone, Serialize, Deserialize)]
118pub struct InputInfoSourcesV2 {
119 hw_microphone: Microphone,
120 sw_microphone: Microphone,
121 input_device_state: InputState,
122}
123
124impl DeviceStorageCompatible for InputInfoSourcesV2 {
125 type Loader = NoneT;
126 const KEY: &'static str = "input_info_sources_v2";
127
128 fn try_deserialize_from(value: &str) -> Result<Self, Error> {
129 Self::extract(value).or_else(|e| {
130 log::info!("Failed to deserialize InputInfoSourcesV2. Falling back to V1: {e:?}");
131 InputInfoSourcesV1::try_deserialize_from(value).map(Self::from)
132 })
133 }
134}
135
136impl From<InputInfoSourcesV1> for InputInfoSourcesV2 {
137 fn from(v1: InputInfoSourcesV1) -> Self {
138 InputInfoSourcesV2 {
139 hw_microphone: v1.hw_microphone,
140 sw_microphone: v1.sw_microphone,
141 input_device_state: InputState::new(),
142 }
143 }
144}
145
146#[derive(PartialEq, Default, Debug, Clone, Copy, Serialize, Deserialize)]
147pub struct InputInfoSourcesV1 {
148 pub hw_microphone: Microphone,
149 pub sw_microphone: Microphone,
150}
151
152impl DeviceStorageCompatible for InputInfoSourcesV1 {
153 type Loader = NoneT;
154 const KEY: &'static str = "input_info_sources_v1";
155}
156
157pub(crate) enum Request {
158 Set(Vec<InputDevice>, Sender<Result<(), InputError>>),
159}
160
161pub struct InputController {
162 service_context: Rc<ServiceContext>,
163 store: Rc<DeviceStorage>,
165
166 input_device_state: InputState,
168
169 input_device_config: InputConfiguration,
171 publisher: Option<Publisher>,
172 setting_value_publisher: SettingValuePublisher<InputInfo>,
173 external_publisher: ExternalEventPublisher,
174 cam_sw_sync: CamSwSync,
179}
180
181#[derive(Clone, Copy, Debug, PartialEq, Eq)]
197enum CamSwSync {
198 Synced,
200 Pending,
204 Adopted,
211}
212
213impl StorageAccess for InputController {
214 type Storage = DeviceStorage;
215 type Data = InputInfoSources;
216 const STORAGE_KEY: &'static str = InputInfoSources::KEY;
217}
218
219impl InputController {
220 pub(super) async fn new<F>(
221 service_context: Rc<ServiceContext>,
222 default_setting: &mut DefaultSetting<InputConfiguration, &'static str>,
223 storage_factory: Rc<F>,
224 setting_value_publisher: SettingValuePublisher<InputInfo>,
225 external_publisher: ExternalEventPublisher,
226 ) -> Result<Self, InputError>
227 where
228 F: StorageFactory<Storage = DeviceStorage>,
229 {
230 let input_device_config = default_setting
231 .load_default_value()
232 .context("Unable to load input device config")
233 .map_err(InputError::InitFailure)?
234 .expect("Input requires a configuration");
235 Ok(InputController::create_with_config(
236 service_context,
237 input_device_config,
238 &*storage_factory,
239 setting_value_publisher,
240 external_publisher,
241 )
242 .await)
243 }
244
245 pub(crate) async fn create_with_config<F>(
247 service_context: Rc<ServiceContext>,
248 input_device_config: InputConfiguration,
249 storage_factory: &F,
250 setting_value_publisher: SettingValuePublisher<InputInfo>,
251 external_publisher: ExternalEventPublisher,
252 ) -> Self
253 where
254 F: StorageFactory<Storage = DeviceStorage>,
255 {
256 Self {
257 service_context,
258 store: storage_factory.get_store().await,
259 input_device_state: InputState::new(),
260 input_device_config,
261 publisher: None,
262 setting_value_publisher,
263 external_publisher,
264 cam_sw_sync: CamSwSync::Synced,
265 }
266 }
267
268 async fn has_input_device(&self, device_type: InputDeviceType) -> bool {
270 let input_device_config_state: InputState = self.input_device_config.clone().into();
271 input_device_config_state.device_types().contains(&device_type)
272 }
273
274 pub(super) fn register_publisher(&mut self, publisher: Publisher) {
275 self.publisher = Some(publisher);
276 }
277
278 fn publish(&self, info: InputInfo) {
279 let _ = self.setting_value_publisher.publish(&info);
280 if let Some(publisher) = self.publisher.as_ref() {
281 publisher.set(info);
282 }
283 }
284
285 pub(super) async fn handle(
286 mut self,
287 mut camera_event_rx: UnboundedReceiver<(CameraWatcherEvent, super::ResultSender)>,
288 mut media_buttons_event_rx: UnboundedReceiver<(Event, super::ResultSender)>,
289 mut request_rx: UnboundedReceiver<Request>,
290 ) -> fasync::Task<()> {
291 fasync::Task::local(async move {
292 let mut next_camera_event = camera_event_rx.next();
293 let mut next_media_buttons_event = media_buttons_event_rx.next();
294 let mut next_request = request_rx.next();
295 loop {
296 futures::select! {
297 event = next_camera_event => {
298 let Some((event, response_tx)) = event else {
299 continue;
300 };
301 next_camera_event = camera_event_rx.next();
302 let res = match event {
303 CameraWatcherEvent::SoftwareMuted(is_muted) => {
304 self.handle_camera_event(is_muted).await
305 }
306 CameraWatcherEvent::DeviceAdded => Ok(self.handle_camera_added()),
307 };
308 let _ = response_tx.send(res);
309 }
310 event = next_media_buttons_event => {
311 let Some((Event::OnButton(buttons), response_tx)) = event else {
312 continue;
313 };
314 next_media_buttons_event = media_buttons_event_rx.next();
315 let res = self.handle_media_buttons_event(buttons).await;
316 let _ = response_tx.send(res);
317 }
318 request = next_request => {
319 let Some(request) = request else {
320 continue;
321 };
322 next_request = request_rx.next();
323 let Request::Set(input_devices, tx) = request;
324 let res = check_publish(
325 self.set_input_states(input_devices, DeviceStateSource::SOFTWARE).await,
326 |info| self.publish(info)).map(|_|{});
327 let _ = tx.send(res);
328 }
329 }
330 }
331 })
332 }
333
334 fn handle_camera_added(&mut self) -> Option<()> {
339 if self.cam_sw_sync != CamSwSync::Pending {
340 log::info!("Camera added, re-applying stored camera state on the next camera event");
341 self.cam_sw_sync = CamSwSync::Pending;
342 }
343 None
344 }
345
346 async fn handle_camera_event(&mut self, is_muted: bool) -> Result<Option<()>, InputError> {
347 let stored_info = self.get_stored_info().await;
348 let stored_state = Self::get_cam_sw_state_from(&stored_info.input_device_state)?;
349 let stored_muted = stored_state.has_state(DeviceState::MUTED);
350 match self.cam_sw_sync {
351 CamSwSync::Pending if stored_muted && !is_muted => {
352 self.reconcile_cam_sw_state(stored_state, is_muted).await
353 }
354 CamSwSync::Adopted => {
355 if self.show_cam_sw_state(is_muted) {
356 self.publish(InputInfo { input_device_state: self.input_device_state.clone() });
357 Ok(Some(()))
358 } else {
359 Ok(None)
360 }
361 }
362 CamSwSync::Synced | CamSwSync::Pending => {
363 if stored_muted != is_muted {
364 let res =
365 self.set_sw_camera_mute(is_muted, DEFAULT_CAMERA_NAME.to_string()).await;
366 if res.is_ok() && is_muted {
367 self.cam_sw_sync = CamSwSync::Synced;
368 }
369 if res.is_err() {
370 self.publish(InputInfo {
373 input_device_state: self.input_device_state.clone(),
374 });
375 }
376 check_publish(res, |info| self.publish(info))
377 } else {
378 if is_muted {
379 self.cam_sw_sync = CamSwSync::Synced;
380 }
381 if self.show_cam_sw_state(is_muted) {
382 self.publish(InputInfo {
384 input_device_state: self.input_device_state.clone(),
385 });
386 Ok(Some(()))
387 } else {
388 Ok(None)
389 }
390 }
391 }
392 }
393 }
394
395 async fn reconcile_cam_sw_state(
402 &mut self,
403 mut stored_state: DeviceState,
404 is_muted: bool,
405 ) -> Result<Option<()>, InputError> {
406 stored_state.remove(DeviceState::ERROR);
407 match self.push_cam_sw_state(stored_state).await {
408 Ok(()) => {
409 self.input_device_state.set_source_state(
410 InputDeviceType::CAMERA,
411 DEFAULT_CAMERA_NAME.to_string(),
412 DeviceStateSource::SOFTWARE,
413 stored_state,
414 );
415 }
416 Err(e) => {
417 log::warn!(
418 "Unable to apply stored camera state, reporting camera state \
419 (muted: {is_muted}): {e:?}"
420 );
421 self.cam_sw_sync = CamSwSync::Adopted;
422 let _ = self.show_cam_sw_state(is_muted);
423 }
424 }
425 self.publish(InputInfo { input_device_state: self.input_device_state.clone() });
426 Ok(Some(()))
427 }
428
429 fn show_cam_sw_state(&mut self, is_muted: bool) -> bool {
432 if self.get_cam_sw_state().is_ok_and(|current| {
433 !current.has_state(DeviceState::ERROR)
434 && current.has_state(DeviceState::MUTED) == is_muted
435 }) {
436 return false;
437 }
438 let state = if is_muted { DeviceState::MUTED } else { DeviceState::AVAILABLE };
439 self.input_device_state.set_source_state(
440 InputDeviceType::CAMERA,
441 DEFAULT_CAMERA_NAME.to_string(),
442 DeviceStateSource::SOFTWARE,
443 state,
444 );
445 true
446 }
447
448 async fn handle_media_buttons_event(
449 &mut self,
450 mut buttons: MediaButtons,
451 ) -> Result<Option<()>, InputError> {
452 if buttons.mic_mute.is_some() && !self.has_input_device(InputDeviceType::MICROPHONE).await {
453 buttons.set_mic_mute(None);
454 }
455 if buttons.camera_disable.is_some() && !self.has_input_device(InputDeviceType::CAMERA).await
456 {
457 buttons.set_camera_disable(None);
458 }
459 check_publish(self.set_hw_media_buttons_state(buttons).await, |info| self.publish(info))
460 }
461
462 async fn get_stored_info(&self) -> InputInfo {
467 let mut input_info = InputInfo::from(self.store.get::<InputInfo>().await);
468 if input_info.input_device_state.is_empty() {
469 input_info.input_device_state = self.input_device_config.clone().into();
470 }
471 input_info
472 }
473
474 pub(super) async fn restore(&mut self) -> Result<InputInfo, InputError> {
477 self.input_device_state = self.get_stored_info().await.input_device_state;
478
479 if self.input_device_config.devices.iter().any(|d| d.device_type == InputDeviceType::CAMERA)
480 {
481 match self.get_cam_sw_state() {
482 Ok(state) => {
483 if let Err(e) = self.push_cam_sw_state(state).await {
486 log::error!("Unable to restore camera state: {e:?}");
487 self.set_cam_err_state(state);
488 }
489 }
490 Err(e) => {
491 log::error!("Unable to load cam sw state: {e:?}");
492 self.set_cam_err_state(DeviceState::ERROR);
493 }
494 }
495 }
496 Ok(InputInfo { input_device_state: self.input_device_state.clone() })
497 }
498
499 async fn set_sw_camera_mute(&mut self, disabled: bool, name: String) -> UpdateInputResult {
500 let mut input_info = self.get_stored_info().await;
501 input_info.input_device_state.set_source_state(
502 InputDeviceType::CAMERA,
503 name.clone(),
504 DeviceStateSource::SOFTWARE,
505 if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
506 );
507
508 self.input_device_state.set_source_state(
509 InputDeviceType::CAMERA,
510 name.clone(),
511 DeviceStateSource::SOFTWARE,
512 if disabled { DeviceState::MUTED } else { DeviceState::AVAILABLE },
513 );
514 self.store
515 .write(&input_info)
516 .await
517 .map(|state| (UpdateState::Updated == state).then_some(input_info))
518 .context("writing sw camera info")
519 .map_err(InputError::WriteFailure)
520 }
521
522 async fn set_hw_media_buttons_state(
524 &mut self,
525 media_buttons: MediaButtons,
526 ) -> UpdateInputResult {
527 let mut states_to_process = Vec::new();
528 if let Some(mic_mute) = media_buttons.mic_mute {
529 states_to_process.push((InputDeviceType::MICROPHONE, mic_mute));
530 }
531 if let Some(camera_disable) = media_buttons.camera_disable {
532 states_to_process.push((InputDeviceType::CAMERA, camera_disable));
533 }
534
535 let mut input_info = self.get_stored_info().await;
536
537 for (device_type, muted) in states_to_process.into_iter() {
538 let hw_state_res = input_info.input_device_state.get_source_state(
540 device_type,
541 device_type.to_string(),
542 DeviceStateSource::HARDWARE,
543 );
544
545 let mut hw_state = hw_state_res.map_err(|err| {
546 InputError::UnexpectedError(
547 format!("Could not fetch current hw mute state: {err:?}").into(),
548 )
549 })?;
550
551 if muted {
552 hw_state &= !DeviceState::AVAILABLE;
554 hw_state |= DeviceState::MUTED;
555 } else {
556 hw_state |= DeviceState::AVAILABLE;
558 hw_state &= !DeviceState::MUTED;
559 }
560
561 input_info.input_device_state.set_source_state(
563 device_type,
564 device_type.to_string(),
565 DeviceStateSource::HARDWARE,
566 hw_state,
567 );
568 self.input_device_state.set_source_state(
569 device_type,
570 device_type.to_string(),
571 DeviceStateSource::HARDWARE,
572 hw_state,
573 );
574 }
575
576 self.store
578 .write(&input_info)
579 .await
580 .map(|state| {
581 (UpdateState::Updated == state)
582 .then(|| InputInfo { input_device_state: self.input_device_state.clone() })
583 })
584 .context("writing hw media buttons")
585 .map_err(InputError::WriteFailure)
586 }
587
588 async fn set_input_states(
590 &mut self,
591 input_devices: Vec<InputDevice>,
592 source: DeviceStateSource,
593 ) -> UpdateInputResult {
594 let mut input_info = self.get_stored_info().await;
595 let device_types = input_info.input_device_state.device_types();
596 let cam_state = self.get_cam_sw_state().ok();
597
598 let mut new_devices = Vec::new();
601 for input_device in input_devices.iter() {
602 if !device_types.contains(&input_device.device_type) {
603 return Err(InputError::Unsupported(input_device.device_type));
604 }
605
606 let already_exists = input_info
607 .input_device_state
608 .contains_device(input_device.device_type, &input_device.name);
609
610 let already_counted = new_devices
611 .iter()
612 .any(|(dt, name)| *dt == input_device.device_type && *name == &input_device.name);
613
614 if !already_exists && !already_counted {
615 new_devices.push((input_device.device_type, &input_device.name));
616 }
617 }
618
619 if input_info.input_device_state.total_devices() + new_devices.len() > MAX_INPUT_DEVICES {
621 log::error!(
622 "Maximum number of supported input devices ({MAX_INPUT_DEVICES}) has been reached."
623 );
624 return Err(InputError::MaximumInputDeviceLimitReached(
625 format!("Maximum limit of {MAX_INPUT_DEVICES} input devices has been reached.")
626 .into(),
627 ));
628 }
629
630 for input_device in &input_devices {
633 input_info.input_device_state.insert_device(input_device.clone(), source);
634 }
635
636 let modified_cam_state = Self::get_cam_sw_state_from(&input_info.input_device_state).ok();
649 let camera_requested =
650 input_devices.iter().any(|device| device.device_type == InputDeviceType::CAMERA);
651 let push_cam_state = if camera_requested {
652 cam_state != modified_cam_state || self.cam_sw_sync != CamSwSync::Synced
653 } else {
654 self.cam_sw_sync != CamSwSync::Synced
655 && modified_cam_state.is_some_and(|state| state.has_state(DeviceState::MUTED))
656 };
657 let mut reported_cam_state_changed = false;
658 if push_cam_state && let Some(state) = modified_cam_state {
659 let pushed = match self.push_cam_sw_state(state).await {
660 Ok(()) => true,
661 Err(e) if !camera_requested => {
662 log::warn!("Unable to re-apply stored camera state: {e:?}");
663 false
664 }
665 Err(e) => return Err(e),
666 };
667 if pushed && cam_state != Some(state) {
668 self.input_device_state.set_source_state(
669 InputDeviceType::CAMERA,
670 DEFAULT_CAMERA_NAME.to_string(),
671 DeviceStateSource::SOFTWARE,
672 state,
673 );
674 reported_cam_state_changed = true;
675 }
676 }
677
678 for input_device in input_devices {
681 self.input_device_state.insert_device(input_device, source);
682 }
683
684 let published_info = InputInfo { input_device_state: self.input_device_state.clone() };
685 self.store
686 .write(&input_info)
687 .await
688 .map(|state| {
689 (UpdateState::Updated == state || reported_cam_state_changed)
690 .then_some(published_info)
691 })
692 .context("writing input states")
693 .map_err(InputError::WriteFailure)
694 }
695
696 fn get_cam_sw_state_from(input_state: &InputState) -> Result<DeviceState, InputError> {
698 input_state
699 .get_source_state(
700 InputDeviceType::CAMERA,
701 DEFAULT_CAMERA_NAME.to_string(),
702 DeviceStateSource::SOFTWARE,
703 )
704 .map_err(|e| {
705 InputError::UnexpectedError(
706 format!("Could not find camera software state: {e:?}").into(),
707 )
708 })
709 }
710
711 fn get_cam_sw_state(&self) -> Result<DeviceState, InputError> {
713 Self::get_cam_sw_state_from(&self.input_device_state)
714 }
715
716 fn set_cam_err_state(&mut self, mut state: DeviceState) {
718 state.set(DeviceState::ERROR, true);
719 self.input_device_state.set_source_state(
720 InputDeviceType::CAMERA,
721 DEFAULT_CAMERA_NAME.to_string(),
722 DeviceStateSource::SOFTWARE,
723 state,
724 )
725 }
726
727 async fn push_cam_sw_state(&mut self, cam_state: DeviceState) -> Result<(), InputError> {
736 let result = self.try_push_cam_sw_state(cam_state).await;
737 self.cam_sw_sync = match (&result, self.cam_sw_sync) {
738 (Ok(()), _) => CamSwSync::Synced,
739 (Err(_), CamSwSync::Synced) => CamSwSync::Pending,
740 (Err(_), sync) => sync,
741 };
742 result
743 }
744
745 async fn try_push_cam_sw_state(&self, cam_state: DeviceState) -> Result<(), InputError> {
748 let is_muted = cam_state.has_state(DeviceState::MUTED);
749
750 let camera_proxies =
754 connect_to_cameras(&self.service_context, self.external_publisher.clone())
755 .await
756 .map_err(|e| {
757 InputError::UnexpectedError(
758 format!("Could not connect to camera device: {e:?}").into(),
759 )
760 })?;
761
762 let results = futures::future::join_all(
763 camera_proxies.iter().map(|proxy| proxy.set_software_mute_state(is_muted)),
764 )
765 .await;
766
767 let mut mute_error = None;
768 for result in results {
769 if let Err(e) = result {
770 log::warn!("Failed to set software mute state on camera: {e:?}");
771 mute_error = Some(InputError::ExternalFailure(
772 "fuchsia.camera3.Device".into(),
773 "SetSoftwareMuteState".into(),
774 format!("{e:?}").into(),
775 ));
776 }
777 }
778 if let Some(err) = mute_error {
779 return Err(err);
780 }
781 Ok(())
782 }
783}
784
785#[cfg(test)]
786mod tests {
787 use super::*;
788 use crate::input_device_configuration::{InputDeviceConfiguration, SourceState};
789 use fuchsia_async as fasync;
790 use fuchsia_inspect::component;
791 use futures::channel::mpsc;
792 use settings_common::inspect::config_logger::InspectConfigLogger;
793 use settings_common::service_context::ServiceContext;
794 use settings_test_common::storage::InMemoryStorageFactory;
795
796 #[fuchsia::test]
797 fn test_input_migration_v1_to_current() {
798 const MUTED_MIC: Microphone = Microphone { muted: true };
799 let v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
800
801 let serialized_v1 = v1.serialize_to();
802 let current = InputInfoSources::try_deserialize_from(&serialized_v1)
803 .expect("deserialization should succeed");
804 let mut expected_input_state = InputState::new();
805 expected_input_state.set_source_state(
806 InputDeviceType::MICROPHONE,
807 DEFAULT_MIC_NAME.to_string(),
808 DeviceStateSource::SOFTWARE,
809 DeviceState::MUTED,
810 );
811 expected_input_state.set_source_state(
812 InputDeviceType::MICROPHONE,
813 DEFAULT_MIC_NAME.to_string(),
814 DeviceStateSource::HARDWARE,
815 DeviceState::AVAILABLE,
816 );
817 assert_eq!(current.input_device_state, expected_input_state);
818 }
819
820 #[fuchsia::test]
821 fn test_input_migration_v1_to_v2() {
822 const MUTED_MIC: Microphone = Microphone { muted: true };
823 let v1 = InputInfoSourcesV1 { sw_microphone: MUTED_MIC, ..Default::default() };
824
825 let serialized_v1 = v1.serialize_to();
826 let v2 = InputInfoSourcesV2::try_deserialize_from(&serialized_v1)
827 .expect("deserialization should succeed");
828
829 assert_eq!(v2.hw_microphone, Microphone { muted: false });
830 assert_eq!(v2.sw_microphone, MUTED_MIC);
831 assert_eq!(v2.input_device_state, InputState::new());
832 }
833
834 #[fuchsia::test]
835 fn test_input_migration_v2_to_current() {
836 const DEFAULT_CAMERA_NAME: &str = "camera";
837 const MUTED_MIC: Microphone = Microphone { muted: true };
838 let mut v2 = InputInfoSourcesV2::default();
839 v2.input_device_state.set_source_state(
840 InputDeviceType::CAMERA,
841 DEFAULT_CAMERA_NAME.to_string(),
842 DeviceStateSource::SOFTWARE,
843 DeviceState::AVAILABLE,
844 );
845 v2.input_device_state.set_source_state(
846 InputDeviceType::CAMERA,
847 DEFAULT_CAMERA_NAME.to_string(),
848 DeviceStateSource::HARDWARE,
849 DeviceState::MUTED,
850 );
851 v2.sw_microphone = MUTED_MIC;
852
853 let serialized_v2 = v2.serialize_to();
854 let current = InputInfoSources::try_deserialize_from(&serialized_v2)
855 .expect("deserialization should succeed");
856 let mut expected_input_state = InputState::new();
857
858 expected_input_state.set_source_state(
859 InputDeviceType::MICROPHONE,
860 DEFAULT_MIC_NAME.to_string(),
861 DeviceStateSource::SOFTWARE,
862 DeviceState::MUTED,
863 );
864 expected_input_state.set_source_state(
865 InputDeviceType::MICROPHONE,
866 DEFAULT_MIC_NAME.to_string(),
867 DeviceStateSource::HARDWARE,
868 DeviceState::AVAILABLE,
869 );
870 expected_input_state.set_source_state(
871 InputDeviceType::CAMERA,
872 DEFAULT_CAMERA_NAME.to_string(),
873 DeviceStateSource::SOFTWARE,
874 DeviceState::AVAILABLE,
875 );
876 expected_input_state.set_source_state(
877 InputDeviceType::CAMERA,
878 DEFAULT_CAMERA_NAME.to_string(),
879 DeviceStateSource::HARDWARE,
880 DeviceState::MUTED,
881 );
882
883 assert_eq!(current.input_device_state, expected_input_state);
884 }
885
886 #[fuchsia::test]
887 async fn test_camera_error_on_restore() {
888 let (event_tx, _event_rx) = mpsc::unbounded();
889 let external_publisher = ExternalEventPublisher::new(event_tx);
890 let storage_factory = InMemoryStorageFactory::new();
891 storage_factory
892 .initialize::<InputController>()
893 .await
894 .expect("controller should have impls");
895 let (value_tx, _value_rx) = mpsc::unbounded();
896 let setting_value_publisher = SettingValuePublisher::new(value_tx);
897 let mut controller: InputController =
898 InputController::create_with_config::<InMemoryStorageFactory>(
899 Rc::new(ServiceContext::new(None)),
900 InputConfiguration {
901 devices: vec![InputDeviceConfiguration {
902 device_name: DEFAULT_CAMERA_NAME.to_string(),
903 device_type: InputDeviceType::CAMERA,
904 source_states: vec![SourceState {
905 source: DeviceStateSource::SOFTWARE,
906 state: 0,
907 }],
908 mutable_toggle_state: 0,
909 }],
910 },
911 &storage_factory,
912 setting_value_publisher,
913 external_publisher,
914 )
915 .await;
916
917 let result = controller.restore().await;
919 assert!(result.is_ok());
920
921 let camera_state = controller
923 .input_device_state
924 .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
925 .unwrap();
926 assert!(camera_state.has_state(DeviceState::ERROR));
927 }
928
929 #[fuchsia::test(allow_stalls = false)]
930 async fn test_controller_creation_with_default_config() {
931 let config_logger = InspectConfigLogger::new(component::inspector().root());
932 let mut default_setting = DefaultSetting::new(
933 Some(InputConfiguration::default()),
934 "/config/data/input_device_config.json",
935 Rc::new(std::sync::Mutex::new(config_logger)),
936 );
937
938 let (event_tx, _) = mpsc::unbounded();
939 let external_publisher = ExternalEventPublisher::new(event_tx);
940
941 let storage_factory = InMemoryStorageFactory::new();
942 storage_factory
943 .initialize::<InputController>()
944 .await
945 .expect("controller should have impls");
946 let (value_tx, _value_rx) = mpsc::unbounded();
947 let setting_value_publisher = SettingValuePublisher::new(value_tx);
948 let _controller = InputController::new(
949 Rc::new(ServiceContext::new(None)),
950 &mut default_setting,
951 Rc::new(storage_factory),
952 setting_value_publisher,
953 external_publisher,
954 )
955 .await
956 .expect("Should have controller");
957 }
958
959 #[fuchsia::test]
960 async fn test_set_input_states_limit() {
961 let (event_tx, _event_rx) = mpsc::unbounded();
962 let external_publisher = ExternalEventPublisher::new(event_tx);
963 let storage_factory = InMemoryStorageFactory::new();
964 storage_factory
965 .initialize::<InputController>()
966 .await
967 .expect("controller should have impls");
968 let (value_tx, _value_rx) = mpsc::unbounded();
969 let setting_value_publisher = SettingValuePublisher::new(value_tx);
970
971 let mut device_configs = Vec::new();
972 for i in 0..MAX_INPUT_DEVICES {
973 device_configs.push(InputDeviceConfiguration {
974 device_name: format!("mic{i}"),
975 device_type: InputDeviceType::MICROPHONE,
976 source_states: vec![SourceState { source: DeviceStateSource::SOFTWARE, state: 0 }],
977 mutable_toggle_state: 0,
978 });
979 }
980
981 let mut controller: InputController =
982 InputController::create_with_config::<InMemoryStorageFactory>(
983 Rc::new(ServiceContext::new(None)),
984 InputConfiguration { devices: device_configs },
985 &storage_factory,
986 setting_value_publisher,
987 external_publisher,
988 )
989 .await;
990
991 let _ = controller.restore().await;
992
993 let overflow_dev = InputDevice {
994 name: "mic_max_exceeded".to_string(),
995 device_type: InputDeviceType::MICROPHONE,
996 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::AVAILABLE)].into(),
997 state: DeviceState::AVAILABLE,
998 };
999 let res =
1000 controller.set_input_states(vec![overflow_dev], DeviceStateSource::SOFTWARE).await;
1001 match res {
1002 Err(InputError::MaximumInputDeviceLimitReached(msg)) => {
1003 assert_eq!(
1004 msg,
1005 format!("Maximum limit of {MAX_INPUT_DEVICES} input devices has been reached.")
1006 );
1007 }
1008 _ => panic!("Expected MaximumInputDeviceLimitReached, got {res:?}"),
1009 }
1010 }
1011
1012 async fn handle_camera3_device(
1013 mut stream: fidl_fuchsia_camera3::DeviceRequestStream,
1014 camera_muted: std::sync::Arc<std::sync::atomic::AtomicBool>,
1015 ) {
1016 use futures::StreamExt;
1017 use std::sync::atomic::Ordering;
1018 while let Some(Ok(req)) = stream.next().await {
1019 if let fidl_fuchsia_camera3::DeviceRequest::SetSoftwareMuteState { muted, responder } =
1020 req
1021 {
1022 camera_muted.store(muted, Ordering::Relaxed);
1023 let _ = responder.send();
1024 }
1025 }
1026 }
1027
1028 async fn handle_camera3_device_watcher(
1029 mut stream: fidl_fuchsia_camera3::DeviceWatcherRequestStream,
1030 camera_muted: std::sync::Arc<std::sync::atomic::AtomicBool>,
1031 ) {
1032 use futures::StreamExt;
1033 while let Some(Ok(req)) = stream.next().await {
1034 #[allow(unreachable_patterns)]
1035 match req {
1036 fidl_fuchsia_camera3::DeviceWatcherRequest::WatchDevices { responder } => {
1037 let _ = responder.send(&[fidl_fuchsia_camera3::WatchDevicesEvent::Added(1)]);
1038 }
1039 fidl_fuchsia_camera3::DeviceWatcherRequest::ConnectToDevice {
1040 id: _,
1041 request,
1042 control_handle: _,
1043 } => {
1044 let camera_muted = camera_muted.clone();
1045 fasync::Task::local(handle_camera3_device(request.into_stream(), camera_muted))
1046 .detach();
1047 }
1048 _ => {}
1049 }
1050 }
1051 }
1052
1053 #[fuchsia::test]
1054 async fn test_set_input_states_retry_on_failure() {
1060 use fidl::endpoints::DiscoverableProtocolMarker;
1061 use std::sync::Arc;
1062 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
1063
1064 let call_count = Arc::new(AtomicUsize::new(0));
1065 let call_count_clone = call_count.clone();
1066
1067 let camera_muted = Arc::new(AtomicBool::new(false));
1068 let camera_muted_clone = camera_muted.clone();
1069
1070 let service_context = Rc::new(ServiceContext::new(Some(Box::new(
1072 move |service_name: &str, channel: zx::Channel| {
1073 let count = call_count_clone.fetch_add(1, Ordering::Relaxed);
1074 let camera_muted_clone = camera_muted_clone.clone();
1075 let service_name = service_name.to_string();
1076 Box::pin(async move {
1077 if count == 1 {
1078 return Err(anyhow::Error::msg("injected failure"));
1079 }
1080 if service_name != fidl_fuchsia_camera3::DeviceWatcherMarker::PROTOCOL_NAME {
1081 return Err(anyhow::Error::msg("unsupported service"));
1082 }
1083 let stream = fidl::endpoints::ServerEnd::<
1084 fidl_fuchsia_camera3::DeviceWatcherMarker,
1085 >::new(channel)
1086 .into_stream();
1087 fasync::Task::local(handle_camera3_device_watcher(stream, camera_muted_clone))
1088 .detach();
1089 Ok(())
1090 })
1091 },
1092 ))));
1093
1094 let storage_factory = InMemoryStorageFactory::new();
1096 storage_factory
1097 .initialize::<InputController>()
1098 .await
1099 .expect("controller should have impls");
1100 let (value_tx, _value_rx) = mpsc::unbounded();
1101 let setting_value_publisher = SettingValuePublisher::new(value_tx);
1102 let (event_tx, _event_rx) = mpsc::unbounded();
1103 let external_publisher = ExternalEventPublisher::new(event_tx);
1104
1105 let mut controller = InputController::create_with_config::<InMemoryStorageFactory>(
1106 service_context,
1107 InputConfiguration {
1108 devices: vec![InputDeviceConfiguration {
1109 device_name: DEFAULT_CAMERA_NAME.to_string(),
1110 device_type: InputDeviceType::CAMERA,
1111 source_states: vec![SourceState {
1112 source: DeviceStateSource::SOFTWARE,
1113 state: 0, }],
1115 mutable_toggle_state: 0,
1116 }],
1117 },
1118 &storage_factory,
1119 setting_value_publisher,
1120 external_publisher,
1121 )
1122 .await;
1123
1124 let _ = controller.restore().await;
1125
1126 let camera_state = controller
1128 .input_device_state
1129 .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
1130 .unwrap();
1131 assert!(!camera_state.has_state(DeviceState::MUTED));
1132
1133 let mute_device = InputDevice {
1136 name: DEFAULT_CAMERA_NAME.to_string(),
1137 device_type: InputDeviceType::CAMERA,
1138 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1139 state: DeviceState::MUTED,
1140 };
1141
1142 let res = controller
1143 .set_input_states(vec![mute_device.clone()], DeviceStateSource::SOFTWARE)
1144 .await;
1145 assert!(res.is_err());
1146 assert_eq!(call_count.load(Ordering::Relaxed), 2);
1147 assert!(!camera_muted.load(Ordering::Relaxed));
1148
1149 let res2 =
1153 controller.set_input_states(vec![mute_device], DeviceStateSource::SOFTWARE).await;
1154
1155 assert_eq!(call_count.load(Ordering::Relaxed), 3);
1158 assert!(res2.is_ok());
1159 assert!(camera_muted.load(Ordering::Relaxed));
1160 }
1161
1162 async fn setup_multi_camera_test(
1163 initial_muted: bool,
1164 fail_camera_1_on_attempt: Option<usize>,
1165 ) -> (
1166 InputController,
1167 std::sync::Arc<std::sync::atomic::AtomicBool>,
1168 std::sync::Arc<std::sync::atomic::AtomicBool>,
1169 ) {
1170 let (controller, camera1_muted, camera2_muted, _value_rx) =
1171 setup_multi_camera_test_with_failures(
1172 initial_muted,
1173 fail_camera_1_on_attempt.into_iter().collect(),
1174 )
1175 .await;
1176 (controller, camera1_muted, camera2_muted)
1177 }
1178
1179 async fn setup_multi_camera_test_with_failures(
1183 initial_muted: bool,
1184 fail_camera_1_on_attempts: Vec<usize>,
1185 ) -> (
1186 InputController,
1187 std::sync::Arc<std::sync::atomic::AtomicBool>,
1188 std::sync::Arc<std::sync::atomic::AtomicBool>,
1189 mpsc::UnboundedReceiver<(&'static str, String)>,
1190 ) {
1191 use fidl::endpoints::DiscoverableProtocolMarker;
1192 use std::sync::Arc;
1193 use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering};
1194
1195 let camera1_muted = Arc::new(AtomicBool::new(initial_muted));
1196 let camera2_muted = Arc::new(AtomicBool::new(initial_muted));
1197 let camera1_clone = camera1_muted.clone();
1198 let camera2_clone = camera2_muted.clone();
1199 let camera1_attempts = Arc::new(AtomicUsize::new(0));
1200
1201 let service_context = Rc::new(ServiceContext::new(Some(Box::new(
1202 move |service_name: &str, channel: zx::Channel| {
1203 let camera1 = camera1_clone.clone();
1204 let camera2 = camera2_clone.clone();
1205 let camera1_attempts = camera1_attempts.clone();
1206 let fail_camera_1_on_attempts = fail_camera_1_on_attempts.clone();
1207 let service_name = service_name.to_string();
1208 Box::pin(async move {
1209 if service_name != fidl_fuchsia_camera3::DeviceWatcherMarker::PROTOCOL_NAME {
1210 return Err(anyhow::Error::msg("unsupported service"));
1211 }
1212 let mut stream = fidl::endpoints::ServerEnd::<
1213 fidl_fuchsia_camera3::DeviceWatcherMarker,
1214 >::new(channel)
1215 .into_stream();
1216 fasync::Task::local(async move {
1217 while let Some(Ok(req)) = stream.next().await {
1218 #[allow(unreachable_patterns)]
1219 match req {
1220 fidl_fuchsia_camera3::DeviceWatcherRequest::WatchDevices {
1221 responder,
1222 } => {
1223 let _ = responder.send(&[
1224 fidl_fuchsia_camera3::WatchDevicesEvent::Existing(1),
1225 fidl_fuchsia_camera3::WatchDevicesEvent::Added(2),
1226 ]);
1227 }
1228 fidl_fuchsia_camera3::DeviceWatcherRequest::ConnectToDevice {
1229 id,
1230 request,
1231 control_handle: _,
1232 } => {
1233 let target = match id {
1234 1 => {
1235 let attempt =
1236 camera1_attempts.fetch_add(1, Ordering::Relaxed);
1237 if fail_camera_1_on_attempts.contains(&attempt) {
1238 drop(request);
1239 continue;
1240 }
1241 camera1.clone()
1242 }
1243 2 => camera2.clone(),
1244 _ => panic!("unexpected camera id {id}"),
1245 };
1246 fasync::Task::local(handle_camera3_device(
1247 request.into_stream(),
1248 target,
1249 ))
1250 .detach();
1251 }
1252 _ => {}
1253 }
1254 }
1255 })
1256 .detach();
1257 Ok(())
1258 })
1259 },
1260 ))));
1261
1262 let storage_factory = InMemoryStorageFactory::new();
1263 storage_factory
1264 .initialize::<InputController>()
1265 .await
1266 .expect("controller should have impls");
1267 let (value_tx, value_rx) = mpsc::unbounded();
1268 let setting_value_publisher = SettingValuePublisher::new(value_tx);
1269 let (event_tx, _event_rx) = mpsc::unbounded();
1270 let external_publisher = ExternalEventPublisher::new(event_tx);
1271
1272 let initial_state = if initial_muted {
1273 DeviceState::MUTED.bits()
1274 } else {
1275 0 };
1277
1278 let mut controller = InputController::create_with_config::<InMemoryStorageFactory>(
1279 service_context,
1280 InputConfiguration {
1281 devices: vec![
1282 InputDeviceConfiguration {
1283 device_name: DEFAULT_CAMERA_NAME.to_string(),
1284 device_type: InputDeviceType::CAMERA,
1285 source_states: vec![SourceState {
1286 source: DeviceStateSource::SOFTWARE,
1287 state: initial_state,
1288 }],
1289 mutable_toggle_state: 0,
1290 },
1291 InputDeviceConfiguration {
1292 device_name: DEFAULT_MIC_NAME.to_string(),
1293 device_type: InputDeviceType::MICROPHONE,
1294 source_states: vec![SourceState {
1295 source: DeviceStateSource::SOFTWARE,
1296 state: 0, }],
1298 mutable_toggle_state: 0,
1299 },
1300 ],
1301 },
1302 &storage_factory,
1303 setting_value_publisher,
1304 external_publisher,
1305 )
1306 .await;
1307
1308 let _ = controller.restore().await;
1309 (controller, camera1_muted, camera2_muted, value_rx)
1310 }
1311
1312 #[fuchsia::test]
1313 async fn test_set_input_states_multiple_cameras() {
1314 use std::sync::atomic::Ordering;
1315
1316 let (mut controller, camera1_muted, camera2_muted) =
1317 setup_multi_camera_test(false, None).await;
1318 assert!(!camera1_muted.load(Ordering::Relaxed));
1319 assert!(!camera2_muted.load(Ordering::Relaxed));
1320
1321 let mute_device = InputDevice {
1322 name: DEFAULT_CAMERA_NAME.to_string(),
1323 device_type: InputDeviceType::CAMERA,
1324 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1325 state: DeviceState::MUTED,
1326 };
1327
1328 let res = controller.set_input_states(vec![mute_device], DeviceStateSource::SOFTWARE).await;
1329 assert!(res.is_ok());
1330 assert!(camera1_muted.load(Ordering::Relaxed));
1331 assert!(camera2_muted.load(Ordering::Relaxed));
1332 }
1333
1334 #[fuchsia::test]
1335 async fn test_set_input_states_multiple_cameras_partial_failure() {
1336 use std::sync::atomic::Ordering;
1337
1338 let (mut controller, camera1_muted, camera2_muted) =
1340 setup_multi_camera_test(false, Some(1)).await;
1341
1342 let mute_device = InputDevice {
1343 name: DEFAULT_CAMERA_NAME.to_string(),
1344 device_type: InputDeviceType::CAMERA,
1345 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1346 state: DeviceState::MUTED,
1347 };
1348
1349 let res = controller.set_input_states(vec![mute_device], DeviceStateSource::SOFTWARE).await;
1350 assert!(res.is_err());
1351 assert!(!camera1_muted.load(Ordering::Relaxed));
1352 assert!(camera2_muted.load(Ordering::Relaxed));
1354 }
1355
1356 #[fuchsia::test]
1357 async fn test_set_input_states_multiple_cameras_partial_unmute_retry() {
1358 use std::sync::atomic::Ordering;
1359
1360 let (mut controller, camera1_muted, camera2_muted) =
1362 setup_multi_camera_test(true, Some(1)).await;
1363 assert!(camera1_muted.load(Ordering::Relaxed));
1364 assert!(camera2_muted.load(Ordering::Relaxed));
1365
1366 let unmute_device = InputDevice {
1367 name: DEFAULT_CAMERA_NAME.to_string(),
1368 device_type: InputDeviceType::CAMERA,
1369 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::AVAILABLE)].into(),
1370 state: DeviceState::AVAILABLE,
1371 };
1372
1373 let res = controller
1375 .set_input_states(vec![unmute_device.clone()], DeviceStateSource::SOFTWARE)
1376 .await;
1377 assert!(res.is_err());
1378 assert!(camera1_muted.load(Ordering::Relaxed));
1379 assert!(!camera2_muted.load(Ordering::Relaxed));
1380
1381 let watcher_res = controller.handle_camera_event(false).await;
1385 assert!(watcher_res.is_ok());
1386 assert!(camera1_muted.load(Ordering::Relaxed));
1387 assert!(camera2_muted.load(Ordering::Relaxed));
1388
1389 let retry_res =
1391 controller.set_input_states(vec![unmute_device], DeviceStateSource::SOFTWARE).await;
1392 assert!(retry_res.is_ok());
1393 assert!(!camera1_muted.load(Ordering::Relaxed));
1394 assert!(!camera2_muted.load(Ordering::Relaxed));
1395 }
1396
1397 async fn create_camera_controller_without_camera_service(
1398 source_states: Vec<SourceState>,
1399 ) -> InputController {
1400 let (event_tx, _event_rx) = mpsc::unbounded();
1401 let external_publisher = ExternalEventPublisher::new(event_tx);
1402 let storage_factory = InMemoryStorageFactory::new();
1403 storage_factory
1404 .initialize::<InputController>()
1405 .await
1406 .expect("controller should have impls");
1407 let (value_tx, _value_rx) = mpsc::unbounded();
1408 let setting_value_publisher = SettingValuePublisher::new(value_tx);
1409 InputController::create_with_config::<InMemoryStorageFactory>(
1410 Rc::new(ServiceContext::new(None)),
1411 InputConfiguration {
1412 devices: vec![InputDeviceConfiguration {
1413 device_name: DEFAULT_CAMERA_NAME.to_string(),
1414 device_type: InputDeviceType::CAMERA,
1415 source_states,
1416 mutable_toggle_state: 0,
1417 }],
1418 },
1419 &storage_factory,
1420 setting_value_publisher,
1421 external_publisher,
1422 )
1423 .await
1424 }
1425
1426 #[fuchsia::test]
1427 async fn test_restore_returns_camera_error_on_push_failure() {
1428 let mut controller = create_camera_controller_without_camera_service(vec![SourceState {
1429 source: DeviceStateSource::SOFTWARE,
1430 state: DeviceState::MUTED.bits(),
1431 }])
1432 .await;
1433
1434 let info = controller.restore().await.expect("restore should succeed");
1435
1436 let camera_state = info
1437 .input_device_state
1438 .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
1439 .unwrap();
1440 assert!(camera_state.has_state(DeviceState::ERROR));
1441 let sw_state = InputController::get_cam_sw_state_from(&info.input_device_state).unwrap();
1442 assert_eq!(sw_state, DeviceState::MUTED | DeviceState::ERROR);
1443 assert_eq!(info.input_device_state, controller.input_device_state);
1444 }
1445
1446 #[fuchsia::test]
1447 async fn test_restore_returns_camera_error_on_missing_sw_state() {
1448 let mut controller = create_camera_controller_without_camera_service(vec![SourceState {
1449 source: DeviceStateSource::HARDWARE,
1450 state: DeviceState::AVAILABLE.bits(),
1451 }])
1452 .await;
1453
1454 let info = controller.restore().await.expect("restore should succeed");
1455
1456 let sw_state = InputController::get_cam_sw_state_from(&info.input_device_state).unwrap();
1457 assert_eq!(sw_state, DeviceState::ERROR);
1458 assert_eq!(info.input_device_state, controller.input_device_state);
1459 }
1460
1461 #[fuchsia::test]
1462 async fn test_media_buttons_keep_camera_error() {
1463 let mut controller = create_camera_controller_without_camera_service(vec![
1464 SourceState {
1465 source: DeviceStateSource::HARDWARE,
1466 state: DeviceState::AVAILABLE.bits(),
1467 },
1468 SourceState { source: DeviceStateSource::SOFTWARE, state: DeviceState::MUTED.bits() },
1469 ])
1470 .await;
1471 let _ = controller.restore().await.expect("restore should succeed");
1472
1473 let info = controller
1476 .set_hw_media_buttons_state(MediaButtons { mic_mute: None, camera_disable: Some(true) })
1477 .await
1478 .expect("media buttons should succeed")
1479 .expect("hardware state should be published");
1480 assert_eq!(
1481 InputController::get_cam_sw_state_from(&info.input_device_state).unwrap(),
1482 DeviceState::MUTED | DeviceState::ERROR
1483 );
1484 assert_eq!(
1485 info.input_device_state
1486 .get_source_state(
1487 InputDeviceType::CAMERA,
1488 DEFAULT_CAMERA_NAME.to_string(),
1489 DeviceStateSource::HARDWARE
1490 )
1491 .unwrap(),
1492 DeviceState::MUTED
1493 );
1494 assert_eq!(info.input_device_state, controller.input_device_state);
1495 }
1496
1497 fn expected_published_value(controller: &InputController) -> String {
1498 format!("{:?}", InputInfo { input_device_state: controller.input_device_state.clone() })
1499 }
1500
1501 #[fuchsia::test]
1502 async fn test_camera_event_while_pending_repush_succeeds() {
1503 use std::sync::atomic::Ordering;
1504
1505 let (mut controller, camera1_muted, camera2_muted, mut value_rx) =
1508 setup_multi_camera_test_with_failures(true, vec![0]).await;
1509 camera1_muted.store(false, Ordering::Relaxed);
1510 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1511 assert!(
1512 InputController::get_cam_sw_state_from(&controller.input_device_state)
1513 .unwrap()
1514 .has_state(DeviceState::ERROR)
1515 );
1516
1517 let res = controller.handle_camera_event(false).await;
1519 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1520
1521 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1523 assert!(camera1_muted.load(Ordering::Relaxed));
1524 assert!(camera2_muted.load(Ordering::Relaxed));
1525 assert_eq!(
1526 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1527 DeviceState::MUTED
1528 );
1529 assert_eq!(
1530 InputController::get_cam_sw_state_from(
1531 &controller.get_stored_info().await.input_device_state
1532 )
1533 .unwrap(),
1534 DeviceState::MUTED
1535 );
1536
1537 let (_, published) = value_rx.try_recv().expect("reconciled state should be published");
1539 assert_eq!(published, expected_published_value(&controller));
1540 assert!(value_rx.try_recv().is_err());
1541 }
1542
1543 #[fuchsia::test]
1544 async fn test_camera_event_while_pending_repush_fails() {
1545 use std::sync::atomic::Ordering;
1546
1547 let (mut controller, camera1_muted, camera2_muted, mut value_rx) =
1550 setup_multi_camera_test_with_failures(true, vec![0, 1]).await;
1551 camera1_muted.store(false, Ordering::Relaxed);
1552 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1553
1554 let res = controller.handle_camera_event(false).await;
1556 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1557 assert!(!camera1_muted.load(Ordering::Relaxed));
1558 assert!(camera2_muted.load(Ordering::Relaxed));
1559 assert_eq!(controller.cam_sw_sync, CamSwSync::Adopted);
1560
1561 assert_eq!(
1564 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1565 DeviceState::AVAILABLE
1566 );
1567 assert_eq!(
1568 InputController::get_cam_sw_state_from(
1569 &controller.get_stored_info().await.input_device_state
1570 )
1571 .unwrap(),
1572 DeviceState::MUTED
1573 );
1574
1575 let (_, published) = value_rx.try_recv().expect("reported state should be published");
1576 assert_eq!(published, expected_published_value(&controller));
1577 assert!(value_rx.try_recv().is_err());
1578
1579 camera1_muted.store(true, Ordering::Relaxed);
1582 let res = controller.handle_camera_event(true).await;
1583 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1584 assert_eq!(
1585 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1586 DeviceState::MUTED
1587 );
1588 let res = controller.handle_camera_event(true).await;
1589 assert!(matches!(res, Ok(None)), "unexpected result {res:?}");
1590
1591 camera1_muted.store(false, Ordering::Relaxed);
1593 let res = controller.handle_camera_event(false).await;
1594 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1595 assert!(!camera1_muted.load(Ordering::Relaxed));
1596 assert_eq!(controller.cam_sw_sync, CamSwSync::Adopted);
1597 assert_eq!(
1598 InputController::get_cam_sw_state_from(
1599 &controller.get_stored_info().await.input_device_state
1600 )
1601 .unwrap(),
1602 DeviceState::MUTED
1603 );
1604 }
1605
1606 #[fuchsia::test]
1607 async fn test_camera_event_while_pending_never_unmutes() {
1608 use std::sync::atomic::Ordering;
1609
1610 let (mut controller, camera1_muted, camera2_muted, mut value_rx) =
1612 setup_multi_camera_test_with_failures(false, vec![0]).await;
1613 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1614
1615 camera1_muted.store(true, Ordering::Relaxed);
1617 camera2_muted.store(true, Ordering::Relaxed);
1618 let res = controller.handle_camera_event(true).await;
1619 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1620
1621 assert!(camera1_muted.load(Ordering::Relaxed));
1623 assert!(camera2_muted.load(Ordering::Relaxed));
1624 assert_eq!(
1625 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1626 DeviceState::MUTED
1627 );
1628 assert_eq!(
1629 InputController::get_cam_sw_state_from(
1630 &controller.get_stored_info().await.input_device_state
1631 )
1632 .unwrap(),
1633 DeviceState::MUTED
1634 );
1635 assert!(value_rx.try_recv().is_ok());
1636 }
1637
1638 #[fuchsia::test]
1639 async fn test_camera_event_while_pending_matching_storage_clears_error() {
1640 let (mut controller, _camera1_muted, _camera2_muted, mut value_rx) =
1642 setup_multi_camera_test_with_failures(true, vec![0]).await;
1643 let stored_info = controller.get_stored_info().await;
1644 let _ = controller.store.write(&stored_info).await.expect("write should succeed");
1645
1646 let res = controller.handle_camera_event(true).await;
1649 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1650 assert_eq!(controller.get_stored_info().await, stored_info);
1651 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1652 assert_eq!(
1653 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1654 DeviceState::MUTED
1655 );
1656
1657 let (_, published) = value_rx.try_recv().expect("cleared error should be published");
1658 assert_eq!(published, expected_published_value(&controller));
1659 }
1660
1661 #[fuchsia::test]
1662 async fn test_camera_event_while_synced() {
1663 let (mut controller, _camera1_muted, _camera2_muted, mut value_rx) =
1664 setup_multi_camera_test_with_failures(false, vec![]).await;
1665 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1666
1667 let res = controller.handle_camera_event(false).await;
1669 assert!(matches!(res, Ok(None)), "unexpected result {res:?}");
1670 assert!(value_rx.try_recv().is_err());
1671
1672 let res = controller.handle_camera_event(true).await;
1674 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1675 assert_eq!(
1676 InputController::get_cam_sw_state_from(
1677 &controller.get_stored_info().await.input_device_state
1678 )
1679 .unwrap(),
1680 DeviceState::MUTED
1681 );
1682 assert!(value_rx.try_recv().is_ok());
1683 }
1684
1685 #[fuchsia::test]
1686 async fn test_set_input_states_clears_camera_error_with_unchanged_storage() {
1687 use std::sync::atomic::Ordering;
1688
1689 let (mut controller, camera1_muted, camera2_muted, _value_rx) =
1691 setup_multi_camera_test_with_failures(true, vec![0]).await;
1692 let stored_info = controller.get_stored_info().await;
1693 let _ = controller.store.write(&stored_info).await.expect("write should succeed");
1694 assert!(
1695 InputController::get_cam_sw_state_from(&controller.input_device_state)
1696 .unwrap()
1697 .has_state(DeviceState::ERROR)
1698 );
1699
1700 let mute_device = InputDevice {
1703 name: DEFAULT_CAMERA_NAME.to_string(),
1704 device_type: InputDeviceType::CAMERA,
1705 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1706 state: DeviceState::MUTED,
1707 };
1708 let res = controller.set_input_states(vec![mute_device], DeviceStateSource::SOFTWARE).await;
1709 let info = res.expect("set should succeed").expect("cleared error should be published");
1710 assert_eq!(controller.get_stored_info().await, stored_info);
1711 assert!(camera1_muted.load(Ordering::Relaxed));
1712 assert!(camera2_muted.load(Ordering::Relaxed));
1713 assert_eq!(
1714 InputController::get_cam_sw_state_from(&info.input_device_state).unwrap(),
1715 DeviceState::MUTED
1716 );
1717 assert_eq!(
1718 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1719 DeviceState::MUTED
1720 );
1721 }
1722 #[fuchsia::test]
1723 async fn test_set_mic_clears_camera_error() {
1724 use std::sync::atomic::Ordering;
1725
1726 let (mut controller, camera1_muted, camera2_muted, _value_rx) =
1728 setup_multi_camera_test_with_failures(true, vec![0]).await;
1729 assert!(
1730 InputController::get_cam_sw_state_from(&controller.input_device_state)
1731 .unwrap()
1732 .has_state(DeviceState::ERROR)
1733 );
1734
1735 let mute_mic = InputDevice {
1738 name: DEFAULT_MIC_NAME.to_string(),
1739 device_type: InputDeviceType::MICROPHONE,
1740 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1741 state: DeviceState::MUTED,
1742 };
1743 let res = controller.set_input_states(vec![mute_mic], DeviceStateSource::SOFTWARE).await;
1744 let info = res.expect("set should succeed").expect("updated mic should be published");
1745 assert!(camera1_muted.load(Ordering::Relaxed));
1746 assert!(camera2_muted.load(Ordering::Relaxed));
1747 assert_eq!(
1748 InputController::get_cam_sw_state_from(&info.input_device_state).unwrap(),
1749 DeviceState::MUTED
1750 );
1751 assert_eq!(
1752 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1753 DeviceState::MUTED
1754 );
1755 }
1756
1757 #[fuchsia::test]
1758 async fn test_set_input_states_retry_after_adopting_camera_state() {
1759 use std::sync::atomic::Ordering;
1760
1761 let (mut controller, camera1_muted, camera2_muted, _value_rx) =
1764 setup_multi_camera_test_with_failures(true, vec![1, 2]).await;
1765
1766 let unmute_device = InputDevice {
1767 name: DEFAULT_CAMERA_NAME.to_string(),
1768 device_type: InputDeviceType::CAMERA,
1769 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::AVAILABLE)].into(),
1770 state: DeviceState::AVAILABLE,
1771 };
1772 let res = controller
1773 .set_input_states(vec![unmute_device.clone()], DeviceStateSource::SOFTWARE)
1774 .await;
1775 assert!(res.is_err());
1776 assert!(camera1_muted.load(Ordering::Relaxed));
1777 assert!(!camera2_muted.load(Ordering::Relaxed));
1778
1779 let watcher_res = controller.handle_camera_event(false).await;
1783 assert!(matches!(watcher_res, Ok(Some(()))), "unexpected result {watcher_res:?}");
1784 assert_eq!(controller.cam_sw_sync, CamSwSync::Adopted);
1785 assert_eq!(
1786 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1787 DeviceState::AVAILABLE
1788 );
1789 assert_eq!(
1790 InputController::get_cam_sw_state_from(
1791 &controller.get_stored_info().await.input_device_state
1792 )
1793 .unwrap(),
1794 DeviceState::MUTED
1795 );
1796
1797 let retry_res =
1800 controller.set_input_states(vec![unmute_device], DeviceStateSource::SOFTWARE).await;
1801 assert!(retry_res.is_ok());
1802 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1803 assert!(!camera1_muted.load(Ordering::Relaxed));
1804 assert!(!camera2_muted.load(Ordering::Relaxed));
1805 }
1806
1807 #[fuchsia::test]
1808 async fn test_set_input_states_camera_resync_does_not_block_other_devices() {
1809 use std::sync::atomic::Ordering;
1810
1811 let (mut controller, camera1_muted, camera2_muted, _value_rx) =
1813 setup_multi_camera_test_with_failures(true, (0..100).collect()).await;
1814 camera1_muted.store(false, Ordering::Relaxed);
1815 camera2_muted.store(false, Ordering::Relaxed);
1816 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1817 assert_eq!(
1818 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1819 DeviceState::MUTED | DeviceState::ERROR
1820 );
1821
1822 let mute_mic = InputDevice {
1826 name: DEFAULT_MIC_NAME.to_string(),
1827 device_type: InputDeviceType::MICROPHONE,
1828 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1829 state: DeviceState::MUTED,
1830 };
1831 let info = controller
1832 .set_input_states(vec![mute_mic], DeviceStateSource::SOFTWARE)
1833 .await
1834 .expect("mic mute should succeed")
1835 .expect("mic mute should be published");
1836 assert!(!camera1_muted.load(Ordering::Relaxed));
1837 assert!(camera2_muted.load(Ordering::Relaxed));
1838 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1839 assert_eq!(
1840 InputController::get_cam_sw_state_from(&info.input_device_state).unwrap(),
1841 DeviceState::MUTED | DeviceState::ERROR
1842 );
1843 assert_eq!(
1844 InputController::get_cam_sw_state_from(
1845 &controller.get_stored_info().await.input_device_state
1846 )
1847 .unwrap(),
1848 DeviceState::MUTED
1849 );
1850
1851 let watcher_res = controller.handle_camera_event(false).await;
1854 assert!(matches!(watcher_res, Ok(Some(()))), "unexpected result {watcher_res:?}");
1855 assert_eq!(controller.cam_sw_sync, CamSwSync::Adopted);
1856 assert_eq!(
1857 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1858 DeviceState::AVAILABLE
1859 );
1860
1861 let unmute_mic = InputDevice {
1865 name: DEFAULT_MIC_NAME.to_string(),
1866 device_type: InputDeviceType::MICROPHONE,
1867 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::AVAILABLE)].into(),
1868 state: DeviceState::AVAILABLE,
1869 };
1870 let info = controller
1871 .set_input_states(vec![unmute_mic], DeviceStateSource::SOFTWARE)
1872 .await
1873 .expect("mic unmute should succeed")
1874 .expect("mic unmute should be published");
1875 assert_eq!(controller.cam_sw_sync, CamSwSync::Adopted);
1876 assert_eq!(
1877 InputController::get_cam_sw_state_from(&info.input_device_state).unwrap(),
1878 DeviceState::AVAILABLE
1879 );
1880 assert_eq!(
1881 InputController::get_cam_sw_state_from(
1882 &controller.get_stored_info().await.input_device_state
1883 )
1884 .unwrap(),
1885 DeviceState::MUTED
1886 );
1887 }
1888
1889 #[fuchsia::test]
1890 async fn test_set_input_states_other_device_does_not_unmute_camera() {
1891 use std::sync::atomic::Ordering;
1892
1893 let (mut controller, camera1_muted, camera2_muted, _value_rx) =
1896 setup_multi_camera_test_with_failures(false, vec![1]).await;
1897 let mute_camera = InputDevice {
1898 name: DEFAULT_CAMERA_NAME.to_string(),
1899 device_type: InputDeviceType::CAMERA,
1900 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1901 state: DeviceState::MUTED,
1902 };
1903 let res = controller.set_input_states(vec![mute_camera], DeviceStateSource::SOFTWARE).await;
1904 assert!(res.is_err());
1905 assert!(camera2_muted.load(Ordering::Relaxed));
1906 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1907
1908 camera1_muted.store(true, Ordering::Relaxed);
1911 let mute_mic = InputDevice {
1912 name: DEFAULT_MIC_NAME.to_string(),
1913 device_type: InputDeviceType::MICROPHONE,
1914 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::MUTED)].into(),
1915 state: DeviceState::MUTED,
1916 };
1917 let res = controller.set_input_states(vec![mute_mic], DeviceStateSource::SOFTWARE).await;
1918 assert!(res.is_ok(), "unexpected result {res:?}");
1919 assert!(camera1_muted.load(Ordering::Relaxed));
1920 assert!(camera2_muted.load(Ordering::Relaxed));
1921 }
1922
1923 #[fuchsia::test]
1924 async fn test_camera_added_reapplies_stored_mute() {
1925 use std::sync::atomic::Ordering;
1926
1927 let (mut controller, camera1_muted, camera2_muted, mut value_rx) =
1929 setup_multi_camera_test_with_failures(true, vec![]).await;
1930 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1931 assert!(camera1_muted.load(Ordering::Relaxed));
1932
1933 camera1_muted.store(false, Ordering::Relaxed);
1936 assert_eq!(controller.handle_camera_added(), None);
1937 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1938 let res = controller.handle_camera_event(false).await;
1939 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1940
1941 assert!(camera1_muted.load(Ordering::Relaxed));
1943 assert!(camera2_muted.load(Ordering::Relaxed));
1944 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1945 assert_eq!(
1946 InputController::get_cam_sw_state_from(
1947 &controller.get_stored_info().await.input_device_state
1948 )
1949 .unwrap(),
1950 DeviceState::MUTED
1951 );
1952 assert_eq!(
1953 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap(),
1954 DeviceState::MUTED
1955 );
1956 assert!(value_rx.try_recv().is_ok());
1957 }
1958
1959 #[fuchsia::test]
1960 async fn test_camera_added_while_unmuted_does_not_revert_later_external_unmute() {
1961 use std::sync::atomic::Ordering;
1962
1963 let (mut controller, camera1_muted, camera2_muted, _value_rx) =
1965 setup_multi_camera_test_with_failures(false, vec![]).await;
1966 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1967
1968 assert_eq!(controller.handle_camera_added(), None);
1970 assert_eq!(controller.cam_sw_sync, CamSwSync::Pending);
1971 let res = controller.handle_camera_event(false).await;
1972 assert!(matches!(res, Ok(None)), "unexpected result {res:?}");
1973
1974 camera1_muted.store(true, Ordering::Relaxed);
1977 camera2_muted.store(true, Ordering::Relaxed);
1978 let res = controller.handle_camera_event(true).await;
1979 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1980 assert_eq!(controller.cam_sw_sync, CamSwSync::Synced);
1981
1982 camera1_muted.store(false, Ordering::Relaxed);
1983 let res = controller.handle_camera_event(false).await;
1984 assert!(matches!(res, Ok(Some(()))), "unexpected result {res:?}");
1985 assert!(!camera1_muted.load(Ordering::Relaxed));
1986 assert_eq!(
1987 InputController::get_cam_sw_state_from(
1988 &controller.get_stored_info().await.input_device_state
1989 )
1990 .unwrap(),
1991 DeviceState::AVAILABLE
1992 );
1993 }
1994
1995 #[fuchsia::test]
1996 async fn test_camera_events_converge_when_one_camera_keeps_failing() {
1997 use std::sync::atomic::Ordering;
1998
1999 let (mut controller, camera1_muted, camera2_muted, _value_rx) =
2001 setup_multi_camera_test_with_failures(true, (1..100).collect()).await;
2002
2003 let unmute_device = InputDevice {
2004 name: DEFAULT_CAMERA_NAME.to_string(),
2005 device_type: InputDeviceType::CAMERA,
2006 source_states: [(DeviceStateSource::SOFTWARE, DeviceState::AVAILABLE)].into(),
2007 state: DeviceState::AVAILABLE,
2008 };
2009 let res =
2010 controller.set_input_states(vec![unmute_device], DeviceStateSource::SOFTWARE).await;
2011 assert!(res.is_err());
2012
2013 let mut last_reported = true;
2016 let mut events = 0;
2017 loop {
2018 let aggregate =
2019 camera1_muted.load(Ordering::Relaxed) && camera2_muted.load(Ordering::Relaxed);
2020 if aggregate == last_reported {
2021 break;
2022 }
2023 assert!(events < 10, "camera events did not converge");
2024 last_reported = aggregate;
2025 events += 1;
2026 let res = controller.handle_camera_event(aggregate).await;
2027 assert!(res.is_ok(), "unexpected result {res:?}");
2028 }
2029
2030 assert_eq!(controller.cam_sw_sync, CamSwSync::Adopted);
2033 let reported_state =
2034 InputController::get_cam_sw_state_from(&controller.input_device_state).unwrap();
2035 assert_eq!(reported_state.has_state(DeviceState::MUTED), last_reported);
2036 assert_eq!(
2037 InputController::get_cam_sw_state_from(
2038 &controller.get_stored_info().await.input_device_state
2039 )
2040 .unwrap(),
2041 DeviceState::MUTED
2042 );
2043 }
2044}