| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| use crate::agent::storage::storage_factory::testing::InMemoryStorageFactory; |
| use crate::base::SettingType; |
| use crate::handler::base::{Payload as HandlerPayload, Request}; |
| use crate::ingress::fidl::Interface; |
| use crate::input::common::MediaButtonsEventBuilder; |
| use crate::input::input_device_configuration::{ |
| InputConfiguration, InputDeviceConfiguration, SourceState, |
| }; |
| use crate::input::monitor_media_buttons; |
| use crate::input::types::{ |
| DeviceState, DeviceStateSource, InputCategory, InputDeviceType, InputInfoSources, InputState, |
| }; |
| use crate::message::base::{filter, Attribution, Message, MessageType, MessengerType}; |
| use crate::message::receptor::Receptor; |
| use crate::service::message::Delegate; |
| use crate::service::{Address, Payload, Role}; |
| use crate::service_context::ServiceContext; |
| use crate::tests::fakes::input_device_registry_service::InputDeviceRegistryService; |
| use crate::tests::fakes::service_registry::ServiceRegistry; |
| use crate::tests::helpers::move_executor_forward; |
| use crate::tests::input_test_environment::{TestInputEnvironment, TestInputEnvironmentBuilder}; |
| use crate::tests::test_failure_utils::create_test_env_with_failures; |
| use assert_matches::assert_matches; |
| use fidl::Error::ClientChannelClosed; |
| use fidl_fuchsia_settings::{ |
| DeviceState as FidlDeviceState, DeviceType, InputMarker, InputProxy, InputSettings, |
| InputState as FidlInputState, ToggleStateFlags, |
| }; |
| use fidl_fuchsia_ui_input::MediaButtonsEvent; |
| use fuchsia_async::TestExecutor; |
| use fuchsia_zircon::Status; |
| use futures::lock::Mutex; |
| use futures::pin_mut; |
| use futures::stream::StreamExt; |
| use futures::task::Poll; |
| use std::collections::HashMap; |
| use std::sync::Arc; |
| |
| const DEFAULT_MIC_STATE: bool = false; |
| const DEFAULT_CAMERA_STATE: bool = false; |
| const MUTED_BITS: u64 = 4; |
| const AVAILABLE_BITS: u64 = 1; |
| const MUTED_DISABLED_BITS: u64 = 12; |
| const DEFAULT_MIC_NAME: &str = "microphone"; |
| const DEFAULT_CAMERA_NAME: &str = "camera"; |
| const ENV_NAME: &str = "settings_service_input_test_environment"; |
| |
| fn create_default_input_info() -> InputInfoSources { |
| InputInfoSources { |
| input_device_state: InputState { |
| input_categories: HashMap::<InputDeviceType, InputCategory>::new(), |
| }, |
| } |
| } |
| |
| // An InputConfiguration with an available microphone. |
| fn default_mic_config() -> InputConfiguration { |
| InputConfiguration { |
| devices: vec![InputDeviceConfiguration { |
| device_name: DEFAULT_MIC_NAME.to_string(), |
| device_type: InputDeviceType::MICROPHONE, |
| source_states: vec![ |
| SourceState { source: DeviceStateSource::HARDWARE, state: AVAILABLE_BITS }, |
| SourceState { source: DeviceStateSource::SOFTWARE, state: AVAILABLE_BITS }, |
| ], |
| mutable_toggle_state: MUTED_DISABLED_BITS, |
| }], |
| } |
| } |
| |
| // An InputConfiguration with a muted microphone. |
| fn default_mic_config_muted() -> InputConfiguration { |
| InputConfiguration { |
| devices: vec![InputDeviceConfiguration { |
| device_name: DEFAULT_MIC_NAME.to_string(), |
| device_type: InputDeviceType::MICROPHONE, |
| source_states: vec![ |
| SourceState { source: DeviceStateSource::HARDWARE, state: AVAILABLE_BITS }, |
| SourceState { source: DeviceStateSource::SOFTWARE, state: MUTED_BITS }, |
| ], |
| mutable_toggle_state: MUTED_DISABLED_BITS, |
| }], |
| } |
| } |
| |
| // An InputConfiguration with an available microphone and camera. |
| fn default_mic_cam_config() -> InputConfiguration { |
| InputConfiguration { |
| devices: vec![ |
| InputDeviceConfiguration { |
| device_name: DEFAULT_MIC_NAME.to_string(), |
| device_type: InputDeviceType::MICROPHONE, |
| source_states: vec![ |
| SourceState { source: DeviceStateSource::HARDWARE, state: AVAILABLE_BITS }, |
| SourceState { source: DeviceStateSource::SOFTWARE, state: AVAILABLE_BITS }, |
| ], |
| mutable_toggle_state: MUTED_DISABLED_BITS, |
| }, |
| InputDeviceConfiguration { |
| device_name: DEFAULT_CAMERA_NAME.to_string(), |
| device_type: InputDeviceType::CAMERA, |
| source_states: vec![ |
| SourceState { source: DeviceStateSource::HARDWARE, state: AVAILABLE_BITS }, |
| SourceState { source: DeviceStateSource::SOFTWARE, state: AVAILABLE_BITS }, |
| ], |
| mutable_toggle_state: MUTED_DISABLED_BITS, |
| }, |
| ], |
| } |
| } |
| |
| // An InputConfiguration with a microphone and sw disabled camera. |
| fn default_mic_cam_config_cam_sw_disabled() -> InputConfiguration { |
| InputConfiguration { |
| devices: vec![ |
| InputDeviceConfiguration { |
| device_name: DEFAULT_MIC_NAME.to_string(), |
| device_type: InputDeviceType::MICROPHONE, |
| source_states: vec![ |
| SourceState { source: DeviceStateSource::HARDWARE, state: AVAILABLE_BITS }, |
| SourceState { source: DeviceStateSource::SOFTWARE, state: AVAILABLE_BITS }, |
| ], |
| mutable_toggle_state: MUTED_DISABLED_BITS, |
| }, |
| InputDeviceConfiguration { |
| device_name: DEFAULT_CAMERA_NAME.to_string(), |
| device_type: InputDeviceType::CAMERA, |
| source_states: vec![ |
| SourceState { source: DeviceStateSource::HARDWARE, state: AVAILABLE_BITS }, |
| SourceState { source: DeviceStateSource::SOFTWARE, state: MUTED_BITS }, |
| ], |
| mutable_toggle_state: MUTED_DISABLED_BITS, |
| }, |
| ], |
| } |
| } |
| |
| // Creates an environment that will fail on a get request. |
| async fn create_input_test_env_with_failures( |
| storage_factory: Arc<InMemoryStorageFactory>, |
| ) -> InputProxy { |
| create_test_env_with_failures(storage_factory, ENV_NAME, Interface::Input, SettingType::Input) |
| .await |
| .connect_to_protocol::<InputMarker>() |
| .unwrap() |
| } |
| |
| // Creates an environment with an executor for moving forward execution and |
| // a configuration for the input devices. |
| fn create_env_and_executor_with_config( |
| config: InputConfiguration, |
| // The pre-populated data to insert into the store before spawning |
| // the environment. |
| initial_input_info: Option<InputInfoSources>, |
| ) -> (TestExecutor, TestInputEnvironment) { |
| let mut executor = TestExecutor::new_with_fake_time().expect("Failed to create executor"); |
| let env_future = if let Some(initial_info) = initial_input_info { |
| TestInputEnvironmentBuilder::new() |
| .set_input_device_config(config) |
| .set_starting_input_info_sources(initial_info) |
| .build() |
| } else { |
| TestInputEnvironmentBuilder::new().set_input_device_config(config).build() |
| }; |
| pin_mut!(env_future); |
| let env = match executor.run_until_stalled(&mut env_future) { |
| Poll::Ready(env) => env, |
| _ => panic!("Failed to create environment"), |
| }; |
| |
| // Return order matters here. Executor must be in first position to avoid |
| // it being torn down before env. |
| (executor, env) |
| } |
| |
| // Set the software mic mute state to muted = [mic_muted] for input. |
| async fn set_mic_mute(proxy: &InputProxy, mic_muted: bool) { |
| set_device_muted(proxy, mic_muted, DEFAULT_MIC_NAME, DeviceType::Microphone).await; |
| } |
| |
| // Set the software camera disabled state to disabled = [disabled]. |
| async fn set_camera_disable(proxy: &InputProxy, disabled: bool) { |
| set_device_muted(proxy, disabled, DEFAULT_CAMERA_NAME, DeviceType::Camera).await; |
| } |
| |
| // Helper to set a device's muted state via the input proxy. |
| async fn set_device_muted( |
| proxy: &InputProxy, |
| muted: bool, |
| device_name: &str, |
| device_type: DeviceType, |
| ) { |
| let mut input_state = FidlInputState::EMPTY; |
| let mut states = Vec::new(); |
| |
| input_state.name = Some(device_name.to_string()); |
| input_state.device_type = Some(device_type); |
| input_state.state = Some(FidlDeviceState { |
| toggle_flags: ToggleStateFlags::from_bits(if muted { MUTED_BITS } else { AVAILABLE_BITS }), |
| ..FidlDeviceState::EMPTY |
| }); |
| |
| states.push(input_state); |
| proxy |
| .set_states(&mut states.into_iter()) |
| .await |
| .expect("set completed") |
| .expect("set successful"); |
| } |
| |
| // Switch the hardware mic state to muted = [muted] for input. |
| async fn switch_hardware_mic_mute(env: &TestInputEnvironment, muted: bool) { |
| let buttons_event = MediaButtonsEventBuilder::new().set_volume(1).set_mic_mute(muted).build(); |
| env.input_button_service.lock().await.send_media_button_event(buttons_event.clone()).await; |
| } |
| |
| // Switch the hardware camera disable to disabled = [disabled]. |
| async fn switch_hardware_camera_disable(env: &TestInputEnvironment, disabled: bool) { |
| let buttons_event = |
| MediaButtonsEventBuilder::new().set_volume(1).set_camera_disable(disabled).build(); |
| env.input_button_service.lock().await.send_media_button_event(buttons_event.clone()).await; |
| } |
| |
| // Perform a watch and check that the mic mute state matches [expected_muted_state]. |
| async fn get_and_check_mic_mute(input_proxy: &InputProxy, expected_muted_state: bool) { |
| let settings = input_proxy.watch().await.expect("watch completed"); |
| verify_muted_state(&settings, expected_muted_state, DeviceType::Microphone); |
| } |
| |
| // Perform a watch and check that the camera disabled state matches [expected_camera_disabled_state]. |
| async fn get_and_check_camera_disable( |
| input_proxy: &InputProxy, |
| expected_camera_disabled_state: bool, |
| ) { |
| let settings = input_proxy.watch().await.expect("watch completed"); |
| verify_muted_state(&settings, expected_camera_disabled_state, DeviceType::Camera); |
| } |
| |
| // Creates a broker to listen in on media buttons events. |
| fn create_broker( |
| executor: &mut TestExecutor, |
| delegate: Delegate, |
| ) -> Receptor<Payload, Address, Role> { |
| let message_hub_future = delegate.create(MessengerType::Broker(Some(filter::Builder::single( |
| filter::Condition::Custom(Arc::new(move |message| { |
| // The first condition indicates that it is a response to a set request. |
| if let Payload::Setting(HandlerPayload::Response(Ok(None))) = message.payload() { |
| is_attr_onbutton(message) |
| } else { |
| false |
| } |
| })), |
| )))); |
| pin_mut!(message_hub_future); |
| match executor.run_until_stalled(&mut message_hub_future) { |
| Poll::Ready(Ok((_, receptor))) => receptor, |
| _ => panic!("Could not create broker on service message hub"), |
| } |
| } |
| |
| // Waits for the media buttons receptor to receive an update, so that |
| // following code can be sure that the media buttons event was handled |
| // before continuing. |
| async fn wait_for_media_button_event( |
| media_buttons_receptor: &mut Receptor<Payload, Address, Role>, |
| ) { |
| let _ = media_buttons_receptor.next_payload().await.expect("payload should exist"); |
| } |
| |
| // Returns true if the given attribution `message`'s payload is an OnButton event. |
| fn is_attr_onbutton(message: &Message<Payload, Address, Role>) -> bool { |
| // Find the corresponding message from the message's attribution. |
| let attr_msg = |
| if let Attribution::Source(MessageType::Reply(message)) = message.get_attribution() { |
| message |
| } else { |
| return false; |
| }; |
| |
| // Filter by the attribution message's payload. It should be an OnButton request. |
| matches!(attr_msg.payload(), Payload::Setting(HandlerPayload::Request(Request::OnButton(_)))) |
| } |
| |
| // Perform a watch and check that the mic mute state matches [expected_mic_mute_state] |
| // and the camera disabled state matches [expected_camera_disabled_state]. |
| async fn get_and_check_state( |
| input_proxy: &InputProxy, |
| expected_mic_mute_state: bool, |
| expected_camera_disabled_state: bool, |
| ) { |
| let settings = input_proxy.watch().await.expect("watch completed"); |
| verify_muted_state(&settings, expected_camera_disabled_state, DeviceType::Camera); |
| verify_muted_state(&settings, expected_mic_mute_state, DeviceType::Microphone); |
| } |
| |
| // Helper for checking the returned muted state for a given |
| // device type in the watch results. |
| fn verify_muted_state( |
| settings: &InputSettings, |
| expected_muted_state: bool, |
| device_type: DeviceType, |
| ) { |
| assert_eq!( |
| settings |
| .devices |
| .as_ref() |
| .unwrap() |
| .iter() |
| .find(|x| x.device_type == Some(device_type)) |
| .expect("Device not found in results") |
| .state, |
| if expected_muted_state { |
| Some(FidlDeviceState { |
| toggle_flags: ToggleStateFlags::from_bits(MUTED_BITS), |
| ..FidlDeviceState::EMPTY |
| }) |
| } else { |
| Some(FidlDeviceState { |
| toggle_flags: ToggleStateFlags::from_bits(AVAILABLE_BITS), |
| ..FidlDeviceState::EMPTY |
| }) |
| }, |
| ); |
| } |
| |
| // Test that a watch is executed correctly. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_watch() { |
| let env = TestInputEnvironmentBuilder::new() |
| .set_input_device_config(default_mic_config()) |
| .build() |
| .await; |
| let input_proxy = env.input_service.clone(); |
| |
| get_and_check_mic_mute(&input_proxy, false).await; |
| } |
| |
| // Test that a set then watch for the mic is executed correctly. |
| #[test] |
| fn test_set_watch_mic_mute() { |
| let (mut executor, env) = create_env_and_executor_with_config(default_mic_config_muted(), None); |
| let input_proxy = env.input_service.clone(); |
| let mut media_buttons_receptor = create_broker(&mut executor, env.delegate.clone()); |
| |
| // SW muted, HW unmuted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| set_mic_mute(&input_proxy, true).await; |
| }, |
| "Failed to set mic mute", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_mic_mute(&input_proxy, true).await; |
| }, |
| "Failed to watch mic mute", |
| ); |
| |
| // SW unmuted, HW muted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_mic_mute(&env, true).await; |
| set_mic_mute(&input_proxy, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch mic mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_mic_mute(&input_proxy, true).await; |
| }, |
| "Failed to watch mic mute", |
| ); |
| |
| // SW unmuted, HW unmuted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_mic_mute(&env, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch hardware mic mute", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_mic_mute(&input_proxy, false).await; |
| }, |
| "Failed to watch mic mute", |
| ); |
| } |
| |
| // Test that a set then watch for the camera is executed correctly. |
| #[test] |
| fn test_set_watch_camera_disable() { |
| let (mut executor, env) = create_env_and_executor_with_config(default_mic_cam_config(), None); |
| let input_proxy = env.input_service.clone(); |
| let mut media_buttons_receptor = create_broker(&mut executor, env.delegate.clone()); |
| |
| // SW muted, HW unmuted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| set_camera_disable(&input_proxy, true).await; |
| get_and_check_camera_disable(&input_proxy, true).await; |
| }, |
| "Failed to switch camera state", |
| ); |
| |
| // SW unmuted, HW muted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_camera_disable(&env, true).await; |
| set_camera_disable(&input_proxy, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch camera state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_camera_disable(&input_proxy, true).await; |
| }, |
| "Failed to get camera mute state", |
| ); |
| |
| // SW unmuted, HW unmuted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_camera_disable(&env, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch camera mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_camera_disable(&input_proxy, false).await; |
| }, |
| "Failed to get camera mute state", |
| ); |
| } |
| |
| // Test to ensure mic input change events are received. |
| #[test] |
| fn test_mic_input() { |
| let (mut executor, env) = create_env_and_executor_with_config(default_mic_config(), None); |
| let input_proxy = env.input_service.clone(); |
| let mut media_buttons_receptor = create_broker(&mut executor, env.delegate.clone()); |
| |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_mic_mute(&env, true).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch hardware mic mute", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_mic_mute(&input_proxy, true).await; |
| }, |
| "Failed to watch mic mute", |
| ); |
| } |
| |
| // Test to ensure camera input change events are received. |
| #[test] |
| fn test_camera_input() { |
| let (mut executor, env) = create_env_and_executor_with_config(default_mic_cam_config(), None); |
| let input_proxy = env.input_service.clone(); |
| let mut media_buttons_receptor = create_broker(&mut executor, env.delegate.clone()); |
| |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_camera_disable(&input_proxy, false).await; |
| switch_hardware_camera_disable(&env, true).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to get and switch hardware camera mute state", |
| ); |
| |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_camera_disable(&input_proxy, true).await; |
| }, |
| "Failed to get camera mute state", |
| ); |
| } |
| |
| // Test to ensure camera sw state is not changed on camera3 api |
| // when the hw state is changed. |
| #[test] |
| fn test_camera3_hw_change() { |
| let (mut executor, env) = create_env_and_executor_with_config(default_mic_cam_config(), None); |
| let mut media_buttons_receptor = create_broker(&mut executor, env.delegate.clone()); |
| |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_camera_disable(&env, true).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch camera hw state", |
| ); |
| |
| let camera3_service_future = env.camera3_service.lock(); |
| pin_mut!(camera3_service_future); |
| let camera3_proxy = match executor.run_until_stalled(&mut camera3_service_future) { |
| Poll::Ready(service) => service, |
| _ => panic!("Could not acquire camera3 service lock"), |
| }; |
| |
| #[allow(clippy::bool_assert_comparison)] |
| { |
| assert_eq!(camera3_proxy.camera_sw_muted(), false); |
| } |
| } |
| |
| // Test to ensure camera sw state is changed on camera3 api |
| // when the sw state is changed. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_camera3_sw_change() { |
| let env = TestInputEnvironmentBuilder::new() |
| .set_input_device_config(default_mic_cam_config()) |
| .build() |
| .await; |
| let input_proxy = env.input_service.clone(); |
| |
| set_camera_disable(&input_proxy, true).await; |
| assert!(env.camera3_service.lock().await.camera_sw_muted()); |
| } |
| |
| // Test that when either hardware or software is muted, the service |
| // reports the microphone as muted. |
| #[test] |
| fn test_mic_mute_combinations() { |
| let (mut executor, env) = create_env_and_executor_with_config(default_mic_config(), None); |
| let input_proxy = env.input_service.clone(); |
| let mut media_buttons_receptor = create_broker(&mut executor, env.delegate.clone()); |
| |
| // Hardware muted, software unmuted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_mic_mute(&env, true).await; |
| set_mic_mute(&input_proxy, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch mic mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_mic_mute(&input_proxy, true).await; |
| }, |
| "Failed to get mic mute state", |
| ); |
| |
| // Hardware muted, software muted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| set_mic_mute(&input_proxy, true).await; |
| get_and_check_mic_mute(&input_proxy, true).await; |
| }, |
| "Failed to switch and check mic mute state", |
| ); |
| |
| // Hardware unmuted, software muted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_mic_mute(&env, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch hardware mic mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_mic_mute(&input_proxy, true).await; |
| }, |
| "Failed to watch mic mute state", |
| ); |
| |
| // Hardware unmuted, software unmuted. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_mic_mute(&env, false).await; |
| set_mic_mute(&input_proxy, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch mic mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_mic_mute(&input_proxy, false).await; |
| }, |
| "Failed to watch mic mute state", |
| ); |
| } |
| |
| // Test that when either hardware or software is disabled, the service |
| // reports the camera as disabled. |
| #[test] |
| fn test_camera_disable_combinations() { |
| let (mut executor, env) = create_env_and_executor_with_config(default_mic_cam_config(), None); |
| let input_proxy = env.input_service.clone(); |
| let mut media_buttons_receptor = create_broker(&mut executor, env.delegate.clone()); |
| |
| // Hardware disabled, software enabled. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_camera_disable(&env, true).await; |
| set_camera_disable(&input_proxy, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch camera mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_camera_disable(&input_proxy, true).await; |
| }, |
| "Failed to get camera mute state", |
| ); |
| |
| // Hardware disabled, software disabled |
| move_executor_forward( |
| &mut executor, |
| async { |
| set_camera_disable(&input_proxy, true).await; |
| get_and_check_camera_disable(&input_proxy, true).await; |
| }, |
| "Failed to switch camera mute state", |
| ); |
| |
| // Hardware enabled, software disabled. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_camera_disable(&env, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch hardware camera mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_camera_disable(&input_proxy, true).await; |
| }, |
| "Failed to watch camera mute state", |
| ); |
| |
| // Hardware enabled, software enabled. |
| move_executor_forward( |
| &mut executor, |
| async { |
| switch_hardware_camera_disable(&env, false).await; |
| set_camera_disable(&input_proxy, false).await; |
| wait_for_media_button_event(&mut media_buttons_receptor).await; |
| }, |
| "Failed to switch camera mute state", |
| ); |
| move_executor_forward( |
| &mut executor, |
| async { |
| get_and_check_camera_disable(&input_proxy, false).await; |
| }, |
| "Failed to watch camera mute state", |
| ); |
| } |
| |
| // Test that the input settings are restored correctly. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_restore() { |
| let mut stored_info = create_default_input_info().clone(); |
| stored_info.input_device_state = default_mic_cam_config_cam_sw_disabled().into(); |
| let env = TestInputEnvironmentBuilder::new() |
| .set_starting_input_info_sources(stored_info) |
| .set_input_device_config(default_mic_config_muted()) |
| .build() |
| .await; |
| |
| get_and_check_state(&env.input_service, false, true).await; |
| assert!(env.camera3_service.lock().await.camera_sw_muted()); |
| } |
| |
| // Test to ensure mic input change events are received. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_bringup_without_input_registry() { |
| let env = TestInputEnvironmentBuilder::new() |
| .set_input_device_config(default_mic_cam_config()) |
| .build() |
| .await; |
| let input_proxy = env.input_service.clone(); |
| |
| get_and_check_state(&input_proxy, DEFAULT_MIC_STATE, DEFAULT_CAMERA_STATE).await; |
| } |
| |
| // Test that cloning works. |
| #[test] |
| fn test_input_info_copy() { |
| let input_info = create_default_input_info(); |
| let copy_input_info = input_info.clone(); |
| assert_eq!(input_info, copy_input_info); |
| } |
| |
| // Test that the values in the persistent store are restored at the start. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_persisted_values_applied_at_start() { |
| let mut test_input_info = InputInfoSources { |
| input_device_state: InputState { |
| input_categories: HashMap::<InputDeviceType, InputCategory>::new(), |
| }, |
| }; |
| |
| test_input_info.input_device_state.set_source_state( |
| InputDeviceType::MICROPHONE, |
| DEFAULT_MIC_NAME.to_string(), |
| DeviceStateSource::SOFTWARE, |
| DeviceState::from_bits(MUTED_BITS).unwrap(), |
| ); |
| test_input_info.input_device_state.set_source_state( |
| InputDeviceType::MICROPHONE, |
| DEFAULT_MIC_NAME.to_string(), |
| DeviceStateSource::HARDWARE, |
| DeviceState::from_bits(AVAILABLE_BITS).unwrap(), |
| ); |
| test_input_info.input_device_state.set_source_state( |
| InputDeviceType::CAMERA, |
| DEFAULT_CAMERA_NAME.to_string(), |
| DeviceStateSource::SOFTWARE, |
| DeviceState::from_bits(AVAILABLE_BITS).unwrap(), |
| ); |
| test_input_info.input_device_state.set_source_state( |
| InputDeviceType::CAMERA, |
| DEFAULT_CAMERA_NAME.to_string(), |
| DeviceStateSource::HARDWARE, |
| DeviceState::from_bits(MUTED_BITS).unwrap(), |
| ); |
| let env = TestInputEnvironmentBuilder::new() |
| .set_starting_input_info_sources(test_input_info) |
| .set_input_device_config(default_mic_cam_config()) |
| .build() |
| .await; |
| |
| get_and_check_state(&env.input_service, true, true).await; |
| } |
| |
| // Test that a failure results in the correct epitaph. |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_channel_failure_watch() { |
| let input_proxy = |
| create_input_test_env_with_failures(Arc::new(InMemoryStorageFactory::new())).await; |
| let result = input_proxy.watch().await; |
| assert_matches!(result, Err(ClientChannelClosed { status: Status::UNAVAILABLE, .. })); |
| } |
| |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_media_buttons() { |
| let service_registry = ServiceRegistry::create(); |
| let input_device_registry_service = Arc::new(Mutex::new(InputDeviceRegistryService::new())); |
| |
| let initial_event = MediaButtonsEventBuilder::new().set_volume(1).set_mic_mute(true).build(); |
| input_device_registry_service.lock().await.send_media_button_event(initial_event.clone()).await; |
| |
| service_registry.lock().await.register_service(input_device_registry_service.clone()); |
| |
| let service_context = |
| Arc::new(ServiceContext::new(Some(ServiceRegistry::serve(service_registry.clone())), None)); |
| |
| let (input_tx, mut input_rx) = futures::channel::mpsc::unbounded::<MediaButtonsEvent>(); |
| assert!(monitor_media_buttons(service_context, input_tx).await.is_ok()); |
| |
| // Listener receives an event immediately upon listening. |
| if let Some(event) = input_rx.next().await { |
| assert_eq!(initial_event, event); |
| } |
| |
| // Disable the camera. |
| let second_event = |
| MediaButtonsEventBuilder::new().set_volume(1).set_camera_disable(true).build(); |
| input_device_registry_service.lock().await.send_media_button_event(second_event.clone()).await; |
| |
| // Listener receives the camera disable event. |
| if let Some(event) = input_rx.next().await { |
| assert_eq!(second_event, event); |
| } |
| } |
| |
| #[fuchsia_async::run_until_stalled(test)] |
| async fn test_device_listener_failure() { |
| let service_registry = ServiceRegistry::create(); |
| let input_device_registry_service = Arc::new(Mutex::new(InputDeviceRegistryService::new())); |
| input_device_registry_service.lock().await.set_fail(true); |
| |
| let initial_event = MediaButtonsEventBuilder::new().set_volume(1).set_mic_mute(true).build(); |
| |
| input_device_registry_service.lock().await.send_media_button_event(initial_event.clone()).await; |
| |
| service_registry.lock().await.register_service(input_device_registry_service.clone()); |
| |
| let service_context = |
| Arc::new(ServiceContext::new(Some(ServiceRegistry::serve(service_registry.clone())), None)); |
| |
| let (input_tx, _input_rx) = futures::channel::mpsc::unbounded::<MediaButtonsEvent>(); |
| #[allow(clippy::bool_assert_comparison)] |
| { |
| assert_eq!(monitor_media_buttons(service_context, input_tx).await.is_ok(), false); |
| } |
| } |