| // Copyright 2020 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 anyhow::{Context as _, Error}; |
| use argh::FromArgs; |
| use fidl_fuchsia_settings::{ConfigurationInterfaces, LightState, LightValue, Theme}; |
| use fuchsia_component::client::connect_to_protocol; |
| |
| pub mod accessibility; |
| pub mod audio; |
| pub mod display; |
| pub mod do_not_disturb; |
| pub mod factory_reset; |
| pub mod input; |
| pub mod intl; |
| pub mod light; |
| pub mod night_mode; |
| pub mod privacy; |
| pub mod setup; |
| pub mod utils; |
| pub mod volume_policy; |
| |
| // SettingClient exercises the functionality found in SetUI service. Currently, |
| // action parameters are specified at as individual arguments, but the goal is |
| // to eventually parse details from a JSON file input. |
| #[derive(FromArgs, Debug)] |
| /// Get or set setting values. Pass --help to each subcommand for additional info. Calling the |
| /// subcommands without any parameters treats it as a get. |
| pub struct SettingClient { |
| #[argh(subcommand)] |
| pub nested: SettingClientSubcommands, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand)] |
| pub enum SettingClientSubcommands { |
| // Operations that use the new interfaces. |
| Accessibility(Accessibility), |
| Audio(Audio), |
| Display(Display), |
| DoNotDisturb(DoNotDisturb), |
| FactoryReset(FactoryReset), |
| Input(Input), |
| // TODO(fxbug.dev/65686): Move back into input when the clients are migrated over. |
| // TODO(fxbug.dev/66186): Support multiple input devices to be set. |
| // For simplicity, currently only supports setting one input device at a time. |
| Input2(InputDeviceOptions), |
| Intl(Intl), |
| Light(LightGroup), |
| NightMode(NightMode), |
| Privacy(Privacy), |
| Setup(Setup), |
| VolumePolicy(VolumePolicy), |
| } |
| |
| #[derive(FromArgs, Debug, Clone, Default)] |
| #[argh(subcommand, name = "accessibility")] |
| /// pass no options to get current settings |
| pub struct Accessibility { |
| #[argh(option, short = 'a')] |
| /// when set to 'true', will turn on an audio track for videos that includes a description |
| /// of what is occurring in the video |
| pub audio_description: Option<bool>, |
| |
| #[argh(option, short = 's')] |
| /// when set to 'true', will read aloud elements of the screen selected by the user |
| pub screen_reader: Option<bool>, |
| |
| #[argh(option, short = 'i')] |
| /// when set to 'true', will invert the colors on the screen |
| pub color_inversion: Option<bool>, |
| |
| #[argh(option, short = 'm')] |
| /// when set to 'true', will interpret triple-taps on the touchscreen as a command to zoom in |
| pub enable_magnification: Option<bool>, |
| |
| #[argh(option, short = 'c', from_str_fn(str_to_color_blindness_type))] |
| /// configures the type of color-blindness to correct for. Valid options are none, protanomaly, |
| /// deuteranomaly, and tritanomaly |
| pub color_correction: Option<fidl_fuchsia_settings::ColorBlindnessType>, |
| |
| #[argh(subcommand)] |
| pub caption_options: Option<CaptionCommands>, |
| } |
| |
| #[derive(FromArgs, Debug, Clone)] |
| #[argh(subcommand)] |
| pub enum CaptionCommands { |
| CaptionOptions(CaptionOptions), |
| } |
| |
| #[derive(FromArgs, Debug, Clone)] |
| #[argh(subcommand, name = "caption_options")] |
| /// configuration for which sources get closed caption and how they look |
| pub struct CaptionOptions { |
| #[argh(option, short = 'm')] |
| /// enable closed captions for media sources of audio |
| pub for_media: Option<bool>, |
| |
| #[argh(option, short = 't')] |
| /// enable closed captions for Text-To-Speech sources of audio |
| pub for_tts: Option<bool>, |
| |
| #[argh(option, short = 'w', from_str_fn(str_to_color))] |
| /// border color used around the closed captions window. Valid options are red, green, and blue |
| pub window_color: Option<fidl_fuchsia_ui_types::ColorRgba>, |
| |
| #[argh(option, short = 'b', from_str_fn(str_to_color))] |
| /// border color used around the closed captions window. Valid options are red, green, and blue |
| pub background_color: Option<fidl_fuchsia_ui_types::ColorRgba>, |
| |
| // CaptionFontStyle options below |
| #[argh(option, short = 'f', from_str_fn(str_to_font_family))] |
| /// font family for captions as specified by 47 CFR §79.102(k). Valid options are unknown, |
| /// monospaced_serif, proportional_serif, monospaced_sans_serif, proportional_sans_serif, |
| /// casual, cursive, and small_capitals |
| pub font_family: Option<fidl_fuchsia_settings::CaptionFontFamily>, |
| |
| #[argh(option, short = 'c', from_str_fn(str_to_color))] |
| /// color of the closed caption text. Valid options are red, green, and blue |
| pub font_color: Option<fidl_fuchsia_ui_types::ColorRgba>, |
| |
| #[argh(option, short = 'r')] |
| /// size of closed captions text relative to the default captions size, specified in the |
| /// range [0.5, 2] as per 47 CFR §79.103(c)(4) |
| pub relative_size: Option<f32>, |
| |
| #[argh(option, short = 'e', from_str_fn(str_to_edge_style))] |
| /// edge style for fonts as specified in 47 CFR §79.103(c)(7). Valid options are none, |
| /// drop_shadow, raised, depressed, outline |
| pub char_edge_style: Option<fidl_fuchsia_settings::EdgeStyle>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "audio")] |
| /// get or set audio settings |
| pub struct Audio { |
| // AudioStreams |
| /// which stream should be modified. Valid options are background, media, interruption, |
| /// system_agent, and communication |
| #[argh(option, short = 't', from_str_fn(str_to_audio_stream))] |
| stream: Option<fidl_fuchsia_media::AudioRenderUsage>, |
| |
| /// which source is changing the stream. Valid options are user, system, and |
| /// system_with_feedback |
| #[argh(option, short = 's', from_str_fn(str_to_audio_source))] |
| source: Option<fidl_fuchsia_settings::AudioStreamSettingSource>, |
| |
| // UserVolume |
| /// the volume level specified as a float in the range [0, 1] |
| #[argh(option, short = 'l')] |
| level: Option<f32>, |
| |
| /// whether or not the volume is muted |
| #[argh(option, short = 'v')] |
| volume_muted: Option<bool>, |
| |
| // AudioInput |
| /// whether or not the input, e.g. microphone, is muted |
| #[argh(option, short = 'm')] |
| input_muted: Option<bool>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "display")] |
| /// get or set display settings |
| pub struct Display { |
| /// the brightness value specified as a float in the range [0, 1] |
| #[argh(option, short = 'b')] |
| brightness: Option<f32>, |
| |
| /// the brightness values used to control auto brightness as a float in the range [0, 1] |
| #[argh(option, short = 'o')] |
| auto_brightness_level: Option<f32>, |
| |
| /// when set to 'true', enables auto brightness |
| #[argh(option, short = 'a')] |
| auto_brightness: Option<bool>, |
| |
| /// when passed, reads values from the light sensor rather than display brightness |
| #[argh(switch, short = 'l')] |
| light_sensor: bool, |
| |
| /// which low light mode setting to enable. Valid options are enable, disable, and |
| /// disable_immediately |
| #[argh(option, short = 'm', from_str_fn(str_to_low_light_mode))] |
| low_light_mode: Option<fidl_fuchsia_settings::LowLightMode>, |
| |
| /// which theme to set for the device. Valid options are default, dark, light, darkauto, and |
| /// lightauto |
| #[argh(option, short = 't', from_str_fn(str_to_theme))] |
| theme: Option<fidl_fuchsia_settings::Theme>, |
| |
| /// when set to 'true' the screen is enabled |
| #[argh(option, short = 's')] |
| screen_enabled: Option<bool>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "do_not_disturb")] |
| /// get or set DnD settings |
| pub struct DoNotDisturb { |
| /// when set to 'true', allows the device to enter do not disturb mode |
| #[argh(option, short = 'u')] |
| user_dnd: Option<bool>, |
| |
| /// when set to 'true', forces the device into do not disturb mode |
| #[argh(option, short = 'n')] |
| night_mode_dnd: Option<bool>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "factory_reset")] |
| /// get or set factory reset settings |
| pub struct FactoryReset { |
| /// when set to 'true', factory reset can be performed on the device |
| #[argh(option, short = 'l')] |
| is_local_reset_allowed: Option<bool>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "input")] |
| /// get or set input settings |
| pub struct Input { |
| /// when set to 'true', mutes the mic and prevents it from being accessed |
| #[argh(option, short = 'm')] |
| mic_muted: Option<bool>, |
| } |
| |
| #[derive(FromArgs, Debug, Clone)] |
| #[argh(subcommand, name = "input_device")] |
| /// get or set input device settings |
| pub struct InputDeviceOptions { |
| #[argh(option, short = 't', from_str_fn(str_to_device_type))] |
| /// the type of input device. Valid options are camera and microphone |
| device_type: Option<fidl_fuchsia_settings::DeviceType>, |
| |
| #[argh(option, short = 'n', long = "name")] |
| /// the name of the device. Must be unique within a device type |
| device_name: Option<String>, |
| |
| #[argh(option, short = 's', long = "state", from_str_fn(str_to_device_state))] |
| /// the device state flags, pass a comma separated string of the values available, active, |
| /// muted, disabled and error. E.g. "-s available,active" |
| device_state: Option<fidl_fuchsia_settings::DeviceState>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "intl")] |
| /// get or set internationalization settings |
| pub struct Intl { |
| /// a valid timezone matching the data available at https://www.iana.org/time-zones |
| #[argh(option, short = 'z', from_str_fn(str_to_time_zone))] |
| time_zone: Option<fidl_fuchsia_intl::TimeZoneId>, |
| |
| #[argh(option, short = 'u', from_str_fn(str_to_temperature_unit))] |
| /// the unit to use for temperature. Valid options are celsius and fahrenheit |
| temperature_unit: Option<fidl_fuchsia_intl::TemperatureUnit>, |
| |
| #[argh(option, short = 'l', from_str_fn(str_to_locale))] |
| /// list of locales, separated by spaces, formatted by Unicode BCP-47 Locale Identifier, e.g. |
| /// en-us |
| locales: Vec<fidl_fuchsia_intl::LocaleId>, |
| |
| /// the hour cycle to use. Valid options are h11 for 12-hour clock with 0:10 am after midnight, |
| /// h12 for 12-hour clock with 12:10am after midnight, h23 for 24-hour clock with 0:10 after |
| /// midnight, and h24 for 24-hour clock with 24:10 after midnight |
| #[argh(option, short = 'h', from_str_fn(str_to_hour_cycle))] |
| hour_cycle: Option<fidl_fuchsia_settings::HourCycle>, |
| |
| #[argh(switch)] |
| /// if set, this flag will set locales as an empty list. Overrides the locales arguments |
| clear_locales: bool, |
| } |
| |
| #[derive(FromArgs, Debug, Clone)] |
| #[argh(subcommand, name = "light")] |
| /// get or set light settings |
| pub struct LightGroup { |
| #[argh(option, short = 'n')] |
| /// name of a light group to set values for. Required if setting the value of a light group |
| pub name: Option<String>, |
| |
| #[argh(option, short = 's')] |
| /// repeated parameter for a list of simple on/off values to set for a light group. |
| pub simple: Vec<bool>, |
| |
| #[argh(option, short = 'b')] |
| /// repeated parameter for a list of floating point brightness values in the range [0, 1] for a |
| /// light group |
| pub brightness: Vec<f64>, |
| |
| #[argh(option, short = 'r', from_str_fn(str_to_rgb))] |
| /// repeated parameter for a list of RGB values to set for a light group. Values should be in |
| /// the range [0, 1] and specified as a comma-separated list of the red, green, and blue |
| /// components. Ex. 0.1,0.4,0.23 |
| pub rgb: Vec<fidl_fuchsia_ui_types::ColorRgb>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "night_mode")] |
| /// get or set night mode settings |
| pub struct NightMode { |
| /// when 'true', enables night mode |
| #[argh(option, short = 'n')] |
| night_mode_enabled: Option<bool>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "privacy")] |
| /// get or set privacy settings |
| pub struct Privacy { |
| /// when 'true', is considered to be user giving consent to have their data shared with product |
| /// owner, e.g. for metrics collection and crash reporting |
| #[argh(option, short = 'u')] |
| user_data_sharing_consent: Option<bool>, |
| } |
| |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "setup")] |
| /// get or set setup settings |
| pub struct Setup { |
| /// a supported group of interfaces, specified as a comma-delimited string of the valid values |
| /// eth and wifi, e.g. "-i eth,wifi" or "-i wifi" |
| #[argh(option, short = 'i', long = "interfaces", from_str_fn(str_to_interfaces))] |
| configuration_interfaces: Option<ConfigurationInterfaces>, |
| } |
| #[derive(FromArgs, Debug)] |
| #[argh(subcommand, name = "volume_policy")] |
| /// configure volume policy |
| // Reads and modifies volume policies that affect the behavior of the fuchsia.settings.audio. |
| // To list the policies, run the subcommand without any arguments. |
| pub struct VolumePolicy { |
| /// adds a policy transform. |
| #[argh(subcommand)] |
| add: Option<VolumePolicyCommands>, |
| |
| /// removes a policy transform by its policy ID. |
| #[argh(option, short = 'r')] |
| remove: Option<u32>, |
| } |
| |
| #[derive(FromArgs, Debug, Clone)] |
| #[argh(subcommand)] |
| pub enum VolumePolicyCommands { |
| AddPolicy(VolumePolicyOptions), |
| } |
| |
| #[derive(FromArgs, Debug, Clone)] |
| #[argh(subcommand, name = "add")] |
| /// adds a new volume policy |
| pub struct VolumePolicyOptions { |
| /// target stream to apply the policy transform to. Valid options are background, media, |
| /// interruption, system_agent, and communication |
| #[argh(positional, from_str_fn(str_to_audio_stream))] |
| pub target: fidl_fuchsia_media::AudioRenderUsage, |
| |
| /// the minimum allowed value for the target |
| #[argh(option)] |
| pub min: Option<f32>, |
| |
| /// the maximum allowed value for the target |
| #[argh(option)] |
| pub max: Option<f32>, |
| } |
| |
| impl Into<Vec<LightState>> for LightGroup { |
| fn into(self) -> Vec<LightState> { |
| if self.simple.len() > 0 { |
| return self |
| .simple |
| .clone() |
| .into_iter() |
| .map(|val| LightState { value: Some(LightValue::On(val)), ..LightState::EMPTY }) |
| .collect::<Vec<_>>(); |
| } |
| |
| if self.brightness.len() > 0 { |
| return self |
| .brightness |
| .clone() |
| .into_iter() |
| .map(|val| LightState { |
| value: Some(LightValue::Brightness(val)), |
| ..LightState::EMPTY |
| }) |
| .collect::<Vec<_>>(); |
| } |
| |
| if self.rgb.len() > 0 { |
| return self |
| .rgb |
| .clone() |
| .into_iter() |
| .map(|val| LightState { value: Some(LightValue::Color(val)), ..LightState::EMPTY }) |
| .collect::<Vec<_>>(); |
| } |
| |
| return Vec::new(); |
| } |
| } |
| |
| pub async fn run_command(command: SettingClient) -> Result<(), Error> { |
| match command.nested { |
| SettingClientSubcommands::Display(Display { |
| brightness, |
| auto_brightness_level, |
| auto_brightness, |
| light_sensor, |
| low_light_mode, |
| theme, |
| screen_enabled, |
| }) => { |
| let display_service = connect_to_protocol::<fidl_fuchsia_settings::DisplayMarker>() |
| .context("Failed to connect to display service")?; |
| utils::handle_mixed_result( |
| "Display", |
| display::command( |
| display_service, |
| brightness, |
| auto_brightness, |
| auto_brightness_level, |
| light_sensor, |
| low_light_mode, |
| theme, |
| screen_enabled, |
| ) |
| .await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::DoNotDisturb(DoNotDisturb { user_dnd, night_mode_dnd }) => { |
| let dnd_service = connect_to_protocol::<fidl_fuchsia_settings::DoNotDisturbMarker>() |
| .context("Failed to connect to do_not_disturb service")?; |
| utils::handle_mixed_result( |
| "DoNoDisturb", |
| do_not_disturb::command(dnd_service, user_dnd, night_mode_dnd).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::FactoryReset(FactoryReset { is_local_reset_allowed }) => { |
| let factory_reset_service = |
| connect_to_protocol::<fidl_fuchsia_settings::FactoryResetMarker>() |
| .context("Failed to connect to factory_reset service")?; |
| utils::handle_mixed_result( |
| "FactoryReset", |
| factory_reset::command(factory_reset_service, is_local_reset_allowed).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::Intl(Intl { |
| time_zone, |
| temperature_unit, |
| locales, |
| hour_cycle, |
| clear_locales, |
| }) => { |
| let intl_service = connect_to_protocol::<fidl_fuchsia_settings::IntlMarker>() |
| .context("Failed to connect to intl service")?; |
| utils::handle_mixed_result( |
| "Intl", |
| intl::command( |
| intl_service, |
| time_zone, |
| temperature_unit, |
| locales, |
| hour_cycle, |
| clear_locales, |
| ) |
| .await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::Light(light_group) => { |
| let light_mode_service = connect_to_protocol::<fidl_fuchsia_settings::LightMarker>() |
| .context("Failed to connect to light service")?; |
| utils::handle_mixed_result( |
| "Light", |
| light::command(light_mode_service, light_group).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::NightMode(NightMode { night_mode_enabled }) => { |
| let night_mode_service = |
| connect_to_protocol::<fidl_fuchsia_settings::NightModeMarker>() |
| .context("Failed to connect to night mode service")?; |
| utils::handle_mixed_result( |
| "NightMode", |
| night_mode::command(night_mode_service, night_mode_enabled).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::Accessibility(accessibility_options) => { |
| let accessibility_service = |
| connect_to_protocol::<fidl_fuchsia_settings::AccessibilityMarker>() |
| .context("Failed to connect to accessibility service")?; |
| |
| utils::handle_mixed_result( |
| "Accessibility", |
| accessibility::command(accessibility_service, accessibility_options).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::Privacy(Privacy { user_data_sharing_consent }) => { |
| let privacy_service = connect_to_protocol::<fidl_fuchsia_settings::PrivacyMarker>() |
| .context("Failed to connect to privacy service")?; |
| utils::handle_mixed_result( |
| "Privacy", |
| privacy::command(privacy_service, user_data_sharing_consent).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::Audio(Audio { |
| stream, |
| source, |
| level, |
| volume_muted, |
| input_muted, |
| }) => { |
| let audio_service = connect_to_protocol::<fidl_fuchsia_settings::AudioMarker>() |
| .context("Failed to connect to audio service")?; |
| utils::handle_mixed_result( |
| "Audio", |
| audio::command(audio_service, stream, source, level, volume_muted, input_muted) |
| .await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::Input(Input { mic_muted }) => { |
| let input_service = connect_to_protocol::<fidl_fuchsia_settings::InputMarker>() |
| .context("Failed to connect to input service")?; |
| utils::handle_mixed_result("Input", input::command(input_service, mic_muted).await) |
| .await?; |
| } |
| SettingClientSubcommands::Input2(InputDeviceOptions { |
| device_type, |
| device_name, |
| device_state, |
| }) => { |
| let input_service = connect_to_protocol::<fidl_fuchsia_settings::InputMarker>() |
| .context("Failed to connect to input2 service")?; |
| utils::handle_mixed_result( |
| "Input2", |
| input::command2(input_service, device_type, device_name, device_state).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::Setup(Setup { configuration_interfaces }) => { |
| let setup_service = connect_to_protocol::<fidl_fuchsia_settings::SetupMarker>() |
| .context("Failed to connect to setup service")?; |
| utils::handle_mixed_result( |
| "Setup", |
| setup::command(setup_service, configuration_interfaces).await, |
| ) |
| .await?; |
| } |
| SettingClientSubcommands::VolumePolicy(VolumePolicy { add, remove }) => { |
| let setup_service = |
| connect_to_protocol::<fidl_fuchsia_settings_policy::VolumePolicyControllerMarker>() |
| .context("Failed to connect to volume policy service")?; |
| utils::handle_mixed_result( |
| "Volume policy", |
| volume_policy::command(setup_service, add, remove).await, |
| ) |
| .await?; |
| } |
| } |
| Ok(()) |
| } |
| |
| fn str_to_time_zone(src: &str) -> Result<fidl_fuchsia_intl::TimeZoneId, String> { |
| Ok(fidl_fuchsia_intl::TimeZoneId { id: src.to_string() }) |
| } |
| |
| fn str_to_locale(src: &str) -> Result<fidl_fuchsia_intl::LocaleId, String> { |
| Ok(fidl_fuchsia_intl::LocaleId { id: src.to_string() }) |
| } |
| |
| fn str_to_device_type(src: &str) -> Result<fidl_fuchsia_settings::DeviceType, String> { |
| let device_type = src.to_lowercase(); |
| match device_type.as_ref() { |
| "microphone" | "m" => Ok(fidl_fuchsia_settings::DeviceType::Microphone), |
| "camera" | "c" => Ok(fidl_fuchsia_settings::DeviceType::Camera), |
| _ => Err(String::from("Unidentified device type")), |
| } |
| } |
| |
| fn str_to_device_state(src: &str) -> Result<fidl_fuchsia_settings::DeviceState, String> { |
| use fidl_fuchsia_settings::ToggleStateFlags; |
| |
| Ok(fidl_fuchsia_settings::DeviceState { |
| toggle_flags: Some(src.to_lowercase().split(",").fold( |
| Ok(fidl_fuchsia_settings::ToggleStateFlags::empty()), |
| |acc, flag| { |
| acc.and_then(|acc| { |
| Ok(match flag { |
| "available" | "v" => ToggleStateFlags::Available, |
| "active" | "a" => ToggleStateFlags::Active, |
| "muted" | "m" => ToggleStateFlags::Muted, |
| "disabled" | "d" => ToggleStateFlags::Disabled, |
| "error" | "e" => ToggleStateFlags::Error, |
| flag => { |
| return Err(format!("Unrecognized ToggleStateFlags value {:?}", flag)) |
| } |
| } | acc) |
| }) |
| }, |
| )?), |
| ..fidl_fuchsia_settings::DeviceState::EMPTY |
| }) |
| } |
| |
| fn str_to_low_light_mode(src: &str) -> Result<fidl_fuchsia_settings::LowLightMode, String> { |
| match src { |
| "enable" | "e" => Ok(fidl_fuchsia_settings::LowLightMode::Enable), |
| "disable" | "d" => Ok(fidl_fuchsia_settings::LowLightMode::Disable), |
| "disable_immediately" | "i" => Ok(fidl_fuchsia_settings::LowLightMode::DisableImmediately), |
| _ => Err(String::from("Couldn't parse low light mode")), |
| } |
| } |
| |
| fn str_to_theme(src: &str) -> Result<fidl_fuchsia_settings::Theme, String> { |
| match src { |
| "default" => Ok(Theme { |
| theme_type: Some(fidl_fuchsia_settings::ThemeType::Default), |
| ..Theme::EMPTY |
| }), |
| "dark" => { |
| Ok(Theme { theme_type: Some(fidl_fuchsia_settings::ThemeType::Dark), ..Theme::EMPTY }) |
| } |
| "light" => { |
| Ok(Theme { theme_type: Some(fidl_fuchsia_settings::ThemeType::Light), ..Theme::EMPTY }) |
| } |
| "darkauto" => Ok(Theme { |
| theme_type: Some(fidl_fuchsia_settings::ThemeType::Dark), |
| theme_mode: Some(fidl_fuchsia_settings::ThemeMode::Auto), |
| ..Theme::EMPTY |
| }), |
| "lightauto" => Ok(Theme { |
| theme_type: Some(fidl_fuchsia_settings::ThemeType::Light), |
| theme_mode: Some(fidl_fuchsia_settings::ThemeMode::Auto), |
| ..Theme::EMPTY |
| }), |
| _ => Err(String::from("Couldn't parse theme.")), |
| } |
| } |
| |
| fn str_to_interfaces(src: &str) -> Result<ConfigurationInterfaces, String> { |
| src.to_lowercase().split(",").fold(Ok(ConfigurationInterfaces::empty()), |acc, flag| { |
| acc.and_then(|acc| { |
| Ok(match flag { |
| "eth" | "ethernet" => ConfigurationInterfaces::Ethernet, |
| "wireless" | "wifi" => ConfigurationInterfaces::Wifi, |
| bad_ifc => return Err(format!("Unknown interface: {:?}", bad_ifc)), |
| } | acc) |
| }) |
| }) |
| } |
| |
| fn str_to_color(src: &str) -> Result<fidl_fuchsia_ui_types::ColorRgba, String> { |
| Ok(match src.to_lowercase().as_str() { |
| "red" | "r" => { |
| fidl_fuchsia_ui_types::ColorRgba { red: 255.0, green: 0.0, blue: 0.0, alpha: 255.0 } |
| } |
| "green" | "g" => { |
| fidl_fuchsia_ui_types::ColorRgba { red: 0.0, green: 2.055, blue: 0.0, alpha: 255.0 } |
| } |
| "blue" | "b" => { |
| fidl_fuchsia_ui_types::ColorRgba { red: 0.0, green: 0.0, blue: 255.0, alpha: 255.0 } |
| } |
| _ => return Err(String::from("Couldn't parse color")), |
| }) |
| } |
| |
| /// Converts a comma-separated string of RGB values into a fidl_fuchsia_ui_types::ColorRgb. |
| fn str_to_rgb(src: &str) -> Result<fidl_fuchsia_ui_types::ColorRgb, String> { |
| let mut part_iter = |
| src.split(',').map(|p| p.parse::<f32>().map_err(|_| "failed to parse color value")); |
| |
| let color = { |
| let local_ref = &mut part_iter; |
| color_from_parts(local_ref) |
| }; |
| match (color, part_iter.next()) { |
| (Some(Ok(color)), None) => Ok(color), |
| (Some(Err(err)), _) => Err(err), |
| _ => Err(String::from("wrong number of values")), |
| } |
| } |
| |
| fn color_from_parts<'a, T>( |
| part_iter: &mut T, |
| ) -> Option<Result<fidl_fuchsia_ui_types::ColorRgb, String>> |
| where |
| T: Iterator<Item = Result<f32, &'a str>>, |
| { |
| Some(Ok(fidl_fuchsia_ui_types::ColorRgb { |
| red: match part_iter.next()? { |
| Ok(c) => c, |
| Err(e) => return Some(Err(e.to_string())), |
| }, |
| green: match part_iter.next()? { |
| Ok(c) => c, |
| Err(e) => return Some(Err(e.to_string())), |
| }, |
| blue: match part_iter.next()? { |
| Ok(c) => c, |
| Err(e) => return Some(Err(e.to_string())), |
| }, |
| })) |
| } |
| |
| fn str_to_font_family(src: &str) -> Result<fidl_fuchsia_settings::CaptionFontFamily, String> { |
| Ok(match src.to_lowercase().as_str() { |
| "unknown" => fidl_fuchsia_settings::CaptionFontFamily::Unknown, |
| "monospaced_serif" => fidl_fuchsia_settings::CaptionFontFamily::MonospacedSerif, |
| "proportional_serif" => fidl_fuchsia_settings::CaptionFontFamily::ProportionalSerif, |
| "monospaced_sans_serif" => fidl_fuchsia_settings::CaptionFontFamily::MonospacedSansSerif, |
| "proportional_sans_serif" => { |
| fidl_fuchsia_settings::CaptionFontFamily::ProportionalSansSerif |
| } |
| "casual" => fidl_fuchsia_settings::CaptionFontFamily::Casual, |
| "cursive" => fidl_fuchsia_settings::CaptionFontFamily::Cursive, |
| "small_capitals" => fidl_fuchsia_settings::CaptionFontFamily::SmallCapitals, |
| _ => return Err(String::from("Couldn't parse font family")), |
| }) |
| } |
| |
| fn str_to_edge_style(src: &str) -> Result<fidl_fuchsia_settings::EdgeStyle, String> { |
| Ok(match src.to_lowercase().as_str() { |
| "none" => fidl_fuchsia_settings::EdgeStyle::None, |
| "drop_shadow" => fidl_fuchsia_settings::EdgeStyle::DropShadow, |
| "raised" => fidl_fuchsia_settings::EdgeStyle::Raised, |
| "depressed" => fidl_fuchsia_settings::EdgeStyle::Depressed, |
| "outline" => fidl_fuchsia_settings::EdgeStyle::Outline, |
| _ => return Err(String::from("Couldn't parse edge style")), |
| }) |
| } |
| |
| fn str_to_temperature_unit(src: &str) -> Result<fidl_fuchsia_intl::TemperatureUnit, String> { |
| match src.to_lowercase().as_str() { |
| "c" | "celsius" => Ok(fidl_fuchsia_intl::TemperatureUnit::Celsius), |
| "f" | "fahrenheit" => Ok(fidl_fuchsia_intl::TemperatureUnit::Fahrenheit), |
| _ => Err(String::from("Couldn't parse temperature")), |
| } |
| } |
| |
| fn str_to_hour_cycle(src: &str) -> Result<fidl_fuchsia_settings::HourCycle, String> { |
| match src.to_lowercase().as_str() { |
| "unknown" => Ok(fidl_fuchsia_settings::HourCycle::Unknown), |
| "h11" => Ok(fidl_fuchsia_settings::HourCycle::H11), |
| "h12" => Ok(fidl_fuchsia_settings::HourCycle::H12), |
| "h23" => Ok(fidl_fuchsia_settings::HourCycle::H23), |
| "h24" => Ok(fidl_fuchsia_settings::HourCycle::H24), |
| _ => Err(String::from("Couldn't parse hour cycle")), |
| } |
| } |
| |
| fn str_to_color_blindness_type( |
| src: &str, |
| ) -> Result<fidl_fuchsia_settings::ColorBlindnessType, String> { |
| match src.to_lowercase().as_str() { |
| "none" | "n" => Ok(fidl_fuchsia_settings::ColorBlindnessType::None), |
| "protanomaly" | "p" => Ok(fidl_fuchsia_settings::ColorBlindnessType::Protanomaly), |
| "deuteranomaly" | "d" => Ok(fidl_fuchsia_settings::ColorBlindnessType::Deuteranomaly), |
| "tritanomaly" | "t" => Ok(fidl_fuchsia_settings::ColorBlindnessType::Tritanomaly), |
| _ => Err(String::from("Couldn't parse color blindness type")), |
| } |
| } |
| |
| fn str_to_audio_stream(src: &str) -> Result<fidl_fuchsia_media::AudioRenderUsage, String> { |
| match src.to_lowercase().as_str() { |
| "background" | "b" => Ok(fidl_fuchsia_media::AudioRenderUsage::Background), |
| "media" | "m" => Ok(fidl_fuchsia_media::AudioRenderUsage::Media), |
| "interruption" | "i" => Ok(fidl_fuchsia_media::AudioRenderUsage::Interruption), |
| "system_agent" | "systemagent" | "system agent" | "s" => { |
| Ok(fidl_fuchsia_media::AudioRenderUsage::SystemAgent) |
| } |
| "communication" | "c" => Ok(fidl_fuchsia_media::AudioRenderUsage::Communication), |
| _ => Err(String::from("Couldn't parse audio stream type")), |
| } |
| } |
| |
| fn str_to_audio_source( |
| src: &str, |
| ) -> Result<fidl_fuchsia_settings::AudioStreamSettingSource, String> { |
| match src.to_lowercase().as_str() { |
| "user" | "u" => Ok(fidl_fuchsia_settings::AudioStreamSettingSource::User), |
| "system" | "s" => Ok(fidl_fuchsia_settings::AudioStreamSettingSource::System), |
| "system_with_feedback" | "f" => { |
| Ok(fidl_fuchsia_settings::AudioStreamSettingSource::SystemWithFeedback) |
| } |
| _ => Err(String::from("Couldn't parse audio source type")), |
| } |
| } |
| |
| #[cfg(test)] |
| mod tests { |
| use super::*; |
| |
| /// Unit test for str_to_audio_stream. |
| #[test] |
| fn test_str_to_audio_stream() { |
| println!("Running test_str_to_audio_stream"); |
| let test_cases = vec![ |
| "Background", |
| "MEDIA", |
| "interruption", |
| "SYSTEM_AGENT", |
| "SystemAgent", |
| "system agent", |
| "Communication", |
| "unexpected_stream_type", |
| ]; |
| let expected = vec![ |
| Ok(fidl_fuchsia_media::AudioRenderUsage::Background), |
| Ok(fidl_fuchsia_media::AudioRenderUsage::Media), |
| Ok(fidl_fuchsia_media::AudioRenderUsage::Interruption), |
| Ok(fidl_fuchsia_media::AudioRenderUsage::SystemAgent), |
| Ok(fidl_fuchsia_media::AudioRenderUsage::SystemAgent), |
| Ok(fidl_fuchsia_media::AudioRenderUsage::SystemAgent), |
| Ok(fidl_fuchsia_media::AudioRenderUsage::Communication), |
| Err(String::from("Couldn't parse audio stream type")), |
| ]; |
| let mut results = vec![]; |
| for test_case in test_cases { |
| results.push(str_to_audio_stream(test_case)); |
| } |
| for (expected, result) in expected.iter().zip(results.iter()) { |
| assert_eq!(expected, result); |
| } |
| } |
| |
| /// Unit test for str_to_audio_source. |
| #[test] |
| fn test_str_to_audio_source() { |
| println!("Running test_str_to_audio_source"); |
| let test_cases = vec!["USER", "system", "unexpected_source_type"]; |
| let expected = vec![ |
| Ok(fidl_fuchsia_settings::AudioStreamSettingSource::User), |
| Ok(fidl_fuchsia_settings::AudioStreamSettingSource::System), |
| Err(String::from("Couldn't parse audio source type")), |
| ]; |
| let mut results = vec![]; |
| for test_case in test_cases { |
| results.push(str_to_audio_source(test_case)); |
| } |
| for (expected, result) in expected.iter().zip(results.iter()) { |
| assert_eq!(expected, result); |
| } |
| } |
| } |
| |
| #[cfg(test)] |
| mod interface_tests; |