settings/input/
types.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::base::SettingInfo;
6use crate::handler::setting_handler::ControllerError;
7use crate::input::input_device_configuration::InputConfiguration;
8use settings_storage::device_storage::DeviceStorageConvertible;
9
10use anyhow::Error;
11use bitflags::bitflags;
12use fidl_fuchsia_settings::{
13    DeviceState as FidlDeviceState, DeviceStateSource as FidlDeviceStateSource,
14    DeviceType as FidlDeviceType, InputDevice as FidlInputDevice,
15    InputSettings as FidlInputSettings, SourceState as FidlSourceState,
16    ToggleStateFlags as FidlToggleFlags,
17};
18use serde::{Deserialize, Serialize};
19use std::borrow::Cow;
20use std::collections::{HashMap, HashSet};
21use std::fmt;
22
23impl From<SettingInfo> for FidlInputSettings {
24    fn from(response: SettingInfo) -> Self {
25        if let SettingInfo::Input(info) = response {
26            let mut input_settings = FidlInputSettings::default();
27            let mut input_devices: Vec<FidlInputDevice> = Vec::new();
28
29            info.input_device_state.input_categories.iter().for_each(|(_, category)| {
30                category.devices.iter().for_each(|(_, device)| {
31                    input_devices.push(device.clone().into());
32                })
33            });
34
35            input_settings.devices = Some(input_devices);
36            input_settings
37        } else {
38            panic!("Incorrect value sent to input");
39        }
40    }
41}
42
43#[derive(PartialEq, Debug, Clone)]
44pub struct InputInfo {
45    pub input_device_state: InputState,
46}
47
48impl DeviceStorageConvertible for InputInfo {
49    type Storable = InputInfoSources;
50
51    fn get_storable(&self) -> Cow<'_, Self::Storable> {
52        Cow::Owned(InputInfoSources { input_device_state: self.input_device_state.clone() })
53    }
54}
55
56#[derive(PartialEq, Default, Debug, Clone, Serialize, Deserialize)]
57#[serde(deny_unknown_fields)]
58pub struct InputInfoSources {
59    pub input_device_state: InputState,
60}
61
62#[derive(PartialEq, Default, Debug, Clone, Copy, Serialize, Deserialize)]
63// DO NOT USE - this type is deprecated and will be replaced by
64// the use of InputDevice.
65pub struct Microphone {
66    pub muted: bool,
67}
68
69#[derive(PartialEq, Debug, Default, Clone, Serialize, Deserialize)]
70/// The top-level struct for the input state. It categorizes the input devices
71/// by their device type.
72pub struct InputState {
73    /// The input devices categorized by device type.
74    pub input_categories: HashMap<InputDeviceType, InputCategory>,
75}
76
77impl InputState {
78    pub(crate) fn new() -> Self {
79        Self::default()
80    }
81
82    /// Insert an InputDevice's state into the internal InputState hierarchy, updating the
83    /// state if it already exists or adding the state if it does not.
84    pub(crate) fn insert_device(&mut self, input_device: InputDevice, source: DeviceStateSource) {
85        self.set_source_state(
86            input_device.device_type,
87            input_device.name,
88            source,
89            input_device.state,
90        );
91    }
92
93    /// Set the `state` for a given device and `source`.
94    /// The combination of `device_type` and `device_name`
95    /// uniquely identifies the device.
96    pub(crate) fn set_source_state(
97        &mut self,
98        device_type: InputDeviceType,
99        device_name: String,
100        source: DeviceStateSource,
101        state: DeviceState,
102    ) {
103        // Ensure the category has an entry in the categories map.
104        let category = self.input_categories.entry(device_type).or_default();
105
106        // Ensure the device has an entry in the devices map.
107        let input_device = category
108            .devices
109            .entry(device_name.clone())
110            .or_insert_with(|| InputDevice::new(device_name, device_type));
111
112        // Replace or add the source state in the map. Ignore the old value.
113        let _ = input_device.source_states.insert(source, state);
114        input_device.compute_input_state();
115    }
116
117    /// Retrieve the state of a given device for one of its `source`s.
118    /// The combination of `device_type` and `device_name`
119    /// uniquely identifies the device. Returns None if it fails to find
120    /// the corresponding state for the given arguments.
121    pub(crate) fn get_source_state(
122        &self,
123        device_type: InputDeviceType,
124        device_name: String,
125        source: DeviceStateSource,
126    ) -> Result<DeviceState, Error> {
127        Ok(*self
128            .input_categories
129            .get(&device_type)
130            .ok_or_else(|| {
131                ControllerError::UnexpectedError(
132                    "Failed to get input category by input type".into(),
133                )
134            })?
135            .devices
136            .get(&device_name)
137            .ok_or_else(|| {
138                ControllerError::UnexpectedError("Failed to get input device by device name".into())
139            })?
140            .source_states
141            .get(&source)
142            .ok_or_else(|| {
143                ControllerError::UnexpectedError("Failed to get state from source states".into())
144            })?)
145    }
146
147    /// Retrieve the overall state of a given device.
148    /// The combination of `device_type` and `device_name`
149    /// uniquely identifies the device. Returns None if it fails to find
150    /// the corresponding state for the given arguments.
151    #[cfg(test)]
152    pub(crate) fn get_state(
153        &self,
154        device_type: InputDeviceType,
155        device_name: String,
156    ) -> Result<DeviceState, Error> {
157        Ok(self
158            .input_categories
159            .get(&device_type)
160            .ok_or_else(|| {
161                ControllerError::UnexpectedError(
162                    "Failed to get input category by input type".into(),
163                )
164            })?
165            .devices
166            .get(&device_name)
167            .ok_or_else(|| {
168                ControllerError::UnexpectedError("Failed to get input device by device name".into())
169            })?
170            .state)
171    }
172
173    /// Returns true if the state map is empty.
174    pub(crate) fn is_empty(&self) -> bool {
175        self.input_categories.is_empty()
176    }
177
178    /// Returns a set of the `InputDeviceType`s contained in the
179    /// state map.
180    pub(crate) fn device_types(&self) -> HashSet<InputDeviceType> {
181        self.input_categories.keys().cloned().collect()
182    }
183}
184
185impl From<InputConfiguration> for InputState {
186    fn from(config: InputConfiguration) -> Self {
187        let mut categories = HashMap::<InputDeviceType, InputCategory>::new();
188        let devices = config.devices;
189
190        devices.iter().for_each(|device_config| {
191            // Ensure the category has an entry in the categories map.
192            let input_device_type = device_config.device_type;
193            let category = categories.entry(input_device_type).or_default();
194
195            // Ensure the device has an entry in the devices map.
196            let device_name = device_config.device_name.clone();
197            let device = category
198                .devices
199                .entry(device_name.clone())
200                .or_insert_with(|| InputDevice::new(device_name, input_device_type));
201
202            // Set the entry on the source states map.
203            device_config.source_states.iter().for_each(|source_state| {
204                let value = DeviceState::from_bits(source_state.state).unwrap_or_default();
205                // Ignore the old value.
206                let _ = device.source_states.insert(source_state.source, value);
207            });
208
209            // Recompute the overall state.
210            device.compute_input_state();
211        });
212        InputState { input_categories: categories }
213    }
214}
215
216#[derive(PartialEq, Debug, Default, Clone, Serialize, Deserialize)]
217pub struct InputCategory {
218    // Map of input devices in this category, identified by names.
219    // It is recommended that the name be the lower-case string
220    // representation of the device type if there is only one input
221    // device in this category.
222    pub devices: HashMap<String, InputDevice>,
223}
224
225#[derive(PartialEq, Debug, Clone, Serialize, Deserialize)]
226pub struct InputDevice {
227    /// The unique name within the device type.
228    pub name: String,
229
230    /// The type of input device.
231    pub device_type: InputDeviceType,
232
233    /// The states for each source.
234    pub source_states: HashMap<DeviceStateSource, DeviceState>,
235
236    /// The overall state of the device considering the `source_state`s.
237    pub state: DeviceState,
238}
239
240impl InputDevice {
241    fn new(name: String, device_type: InputDeviceType) -> Self {
242        Self {
243            name,
244            device_type,
245            source_states: HashMap::<DeviceStateSource, DeviceState>::new(),
246            state: DeviceState::new(),
247        }
248    }
249
250    fn compute_input_state(&mut self) {
251        let mut computed_state = DeviceState::from_bits(0).unwrap();
252
253        for state in self.source_states.values() {
254            if state.has_error() {
255                computed_state |= DeviceState::ERROR;
256            }
257            if state.has_state(DeviceState::DISABLED) {
258                computed_state |= DeviceState::DISABLED | DeviceState::MUTED;
259            }
260            if state.has_state(DeviceState::MUTED) {
261                computed_state |= DeviceState::MUTED;
262            }
263            if state.has_state(DeviceState::ACTIVE) {
264                computed_state |= DeviceState::ACTIVE | DeviceState::AVAILABLE;
265            }
266        }
267
268        // If any source has ERROR, DISABLED, MUTED, or ACTIVE, the overall
269        // state is that state, in order of precedence. Otherwise, the overall state
270        // is AVAILABLE.
271        if computed_state.has_error() {
272            self.state = DeviceState::ERROR;
273        } else if computed_state.has_state(DeviceState::DISABLED) {
274            self.state = DeviceState::DISABLED | DeviceState::MUTED;
275        } else if computed_state.has_state(DeviceState::MUTED) {
276            self.state = DeviceState::MUTED;
277        } else if computed_state.has_state(DeviceState::ACTIVE) {
278            self.state = DeviceState::ACTIVE | DeviceState::AVAILABLE;
279        } else {
280            self.state = DeviceState::AVAILABLE;
281        }
282    }
283}
284
285impl From<InputDevice> for FidlInputDevice {
286    fn from(device: InputDevice) -> Self {
287        let mut result = FidlInputDevice::default();
288
289        // Convert source states.
290        let source_states = Some(
291            device
292                .source_states
293                .keys()
294                .map(|source| FidlSourceState {
295                    source: Some((*source).into()),
296                    state: Some(
297                        (*device.source_states.get(source).expect("Source state map key missing"))
298                            .into(),
299                    ),
300                    ..Default::default()
301                })
302                .collect(),
303        );
304
305        let mutable_toggle_state: FidlDeviceState =
306            DeviceState::default_mutable_toggle_state().into();
307        result.device_name = Some(device.name.clone());
308        result.device_type = Some(device.device_type.into());
309        result.source_states = source_states;
310        result.mutable_toggle_state = mutable_toggle_state.toggle_flags;
311        result.state = Some(device.state.into());
312        result
313    }
314}
315
316#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash, Serialize, Deserialize)]
317#[allow(clippy::upper_case_acronyms)]
318pub enum InputDeviceType {
319    CAMERA,
320    MICROPHONE,
321}
322
323/// Instead of defining our own fmt function, an easier way
324/// is to derive the 'Display' trait for enums using `enum-display-derive` crate
325///
326/// <https://docs.rs/enum-display-derive/0.1.0/enum_display_derive/>
327///
328/// Since addition of this in third_party/rust_crates needs OSRB approval, we
329/// define our own function here.
330impl fmt::Display for InputDeviceType {
331    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
332        match self {
333            InputDeviceType::CAMERA => fmt.write_str("camera"),
334            InputDeviceType::MICROPHONE => fmt.write_str("microphone"),
335        }
336    }
337}
338
339impl From<FidlDeviceType> for InputDeviceType {
340    fn from(device_type: FidlDeviceType) -> Self {
341        match device_type {
342            FidlDeviceType::Camera => InputDeviceType::CAMERA,
343            FidlDeviceType::Microphone => InputDeviceType::MICROPHONE,
344        }
345    }
346}
347
348impl From<InputDeviceType> for FidlDeviceType {
349    fn from(device_type: InputDeviceType) -> Self {
350        match device_type {
351            InputDeviceType::CAMERA => FidlDeviceType::Camera,
352            InputDeviceType::MICROPHONE => FidlDeviceType::Microphone,
353        }
354    }
355}
356
357#[derive(PartialEq, Eq, Debug, Copy, Clone, Hash, Serialize, Deserialize)]
358#[allow(clippy::upper_case_acronyms)]
359pub enum DeviceStateSource {
360    HARDWARE,
361    SOFTWARE,
362}
363
364impl From<FidlDeviceStateSource> for DeviceStateSource {
365    fn from(device_state_source: FidlDeviceStateSource) -> Self {
366        match device_state_source {
367            FidlDeviceStateSource::Hardware => DeviceStateSource::HARDWARE,
368            FidlDeviceStateSource::Software => DeviceStateSource::SOFTWARE,
369        }
370    }
371}
372
373impl From<DeviceStateSource> for FidlDeviceStateSource {
374    fn from(device_state_source: DeviceStateSource) -> Self {
375        match device_state_source {
376            DeviceStateSource::HARDWARE => FidlDeviceStateSource::Hardware,
377            DeviceStateSource::SOFTWARE => FidlDeviceStateSource::Software,
378        }
379    }
380}
381
382bitflags! {
383    #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
384    pub struct DeviceState : u64 {
385        const AVAILABLE = 0b00000001;
386        const ACTIVE = 0b00000010;
387        const MUTED = 0b00000100;
388        const DISABLED = 0b00001000;
389        const ERROR = 0b00010000;
390    }
391}
392
393impl Default for DeviceState {
394    fn default() -> Self {
395        Self::new()
396    }
397}
398
399impl DeviceState {
400    pub(crate) fn new() -> Self {
401        // Represents AVAILABLE as the default.
402        Self::AVAILABLE
403    }
404
405    /// The flags that clients can manipulate by default.
406    fn default_mutable_toggle_state() -> Self {
407        DeviceState::MUTED | DeviceState::DISABLED
408    }
409
410    /// Returns true if the current state contains the given state.
411    /// e.g. All the 1 bits in the given `state` are also 1s in the
412    /// current state.
413    pub(crate) fn has_state(&self, state: DeviceState) -> bool {
414        *self & state == state
415    }
416
417    /// Returns true if the device's state has an error.
418    fn has_error(&self) -> bool {
419        let is_err = *self & DeviceState::ERROR == DeviceState::ERROR;
420        let incompatible_state = self.has_state(DeviceState::ACTIVE | DeviceState::DISABLED)
421            || self.has_state(DeviceState::ACTIVE | DeviceState::MUTED)
422            || self.has_state(DeviceState::AVAILABLE | DeviceState::DISABLED)
423            || self.has_state(DeviceState::AVAILABLE | DeviceState::MUTED);
424        is_err || incompatible_state
425    }
426}
427
428impl From<FidlDeviceState> for DeviceState {
429    fn from(device_state: FidlDeviceState) -> Self {
430        if let Some(toggle_flags) = device_state.toggle_flags {
431            if let Some(res) = Self::from_bits(toggle_flags.bits()) {
432                return res;
433            }
434        }
435        Self::default_mutable_toggle_state()
436    }
437}
438
439impl From<DeviceState> for FidlDeviceState {
440    fn from(device_state: DeviceState) -> Self {
441        FidlDeviceState {
442            toggle_flags: FidlToggleFlags::from_bits(device_state.bits()),
443            ..Default::default()
444        }
445    }
446}
447
448bitflags_serde_legacy::impl_traits!(DeviceState);
449
450#[cfg(test)]
451mod tests {
452    use super::*;
453    use crate::input::input_device_configuration::{InputDeviceConfiguration, SourceState};
454
455    const DEFAULT_MIC_NAME: &str = "microphone";
456    const DEFAULT_CAMERA_NAME: &str = "camera";
457    const AVAILABLE_BITS: u64 = 1;
458    const MUTED_BITS: u64 = 4;
459    const MUTED_DISABLED_BITS: u64 = 12;
460
461    /// Helper to create a `FidlInputDevice`.
462    fn create_fidl_input_device(
463        device_name: &str,
464        device_type: FidlDeviceType,
465        sw_bits: u64,
466        hw_bits: u64,
467        overall_bits: u64,
468    ) -> FidlInputDevice {
469        FidlInputDevice {
470            device_name: Some(device_name.to_string()),
471            device_type: Some(device_type),
472            source_states: Some(vec![
473                FidlSourceState {
474                    source: Some(FidlDeviceStateSource::Hardware),
475                    state: Some(FidlDeviceState {
476                        toggle_flags: FidlToggleFlags::from_bits(hw_bits),
477                        ..Default::default()
478                    }),
479                    ..Default::default()
480                },
481                FidlSourceState {
482                    source: Some(FidlDeviceStateSource::Software),
483                    state: Some(FidlDeviceState {
484                        toggle_flags: FidlToggleFlags::from_bits(sw_bits),
485                        ..Default::default()
486                    }),
487                    ..Default::default()
488                },
489            ]),
490            mutable_toggle_state: FidlToggleFlags::from_bits(MUTED_DISABLED_BITS),
491            state: Some(FidlDeviceState {
492                toggle_flags: FidlToggleFlags::from_bits(overall_bits),
493                ..Default::default()
494            }),
495            ..Default::default()
496        }
497    }
498
499    /// Helper to create an [`InputDevice`].
500    fn create_input_device(
501        device_name: &str,
502        device_type: InputDeviceType,
503        sw_bits: u64,
504        hw_bits: u64,
505        overall_bits: u64,
506    ) -> InputDevice {
507        let mut input_device = InputDevice::new(device_name.to_string(), device_type);
508        let _ = input_device
509            .source_states
510            .insert(DeviceStateSource::SOFTWARE, DeviceState::from_bits(sw_bits).unwrap());
511        let _ = input_device
512            .source_states
513            .insert(DeviceStateSource::HARDWARE, DeviceState::from_bits(hw_bits).unwrap());
514        input_device.state = DeviceState::from_bits(overall_bits).unwrap();
515        input_device
516    }
517
518    /// Helper for creating the config for an `InputDevice`.
519    fn create_device_config(
520        device_name: &str,
521        device_type: InputDeviceType,
522        sw_state: u64,
523        hw_state: u64,
524    ) -> InputDeviceConfiguration {
525        InputDeviceConfiguration {
526            device_name: device_name.to_string(),
527            device_type,
528            source_states: vec![
529                SourceState { source: DeviceStateSource::SOFTWARE, state: sw_state },
530                SourceState { source: DeviceStateSource::HARDWARE, state: hw_state },
531            ],
532            mutable_toggle_state: MUTED_DISABLED_BITS,
533        }
534    }
535
536    /// Helper for verifying the equality of a `FidlInputDevice`. Cannot directly
537    /// compare because the order of the source_states vector may vary.
538    fn verify_fidl_input_device_eq(res: FidlInputDevice, expected: FidlInputDevice) {
539        assert_eq!(res.device_name, expected.device_name);
540        assert_eq!(res.device_type, expected.device_type);
541        assert_eq!(res.mutable_toggle_state, expected.mutable_toggle_state);
542        assert_eq!(res.state, expected.state);
543        let res_source_states = res.source_states.unwrap();
544        for source_state in expected.source_states.unwrap() {
545            assert!(&res_source_states.contains(&source_state));
546        }
547    }
548
549    #[fuchsia::test]
550    fn test_input_state_manipulation() {
551        let mut input_state = InputState::new();
552
553        // Set the source state for each source and device type.
554        input_state.set_source_state(
555            InputDeviceType::MICROPHONE,
556            DEFAULT_MIC_NAME.to_string(),
557            DeviceStateSource::SOFTWARE,
558            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
559        );
560        input_state.set_source_state(
561            InputDeviceType::MICROPHONE,
562            DEFAULT_MIC_NAME.to_string(),
563            DeviceStateSource::HARDWARE,
564            DeviceState::from_bits(MUTED_BITS).unwrap(),
565        );
566        input_state.set_source_state(
567            InputDeviceType::CAMERA,
568            DEFAULT_CAMERA_NAME.to_string(),
569            DeviceStateSource::SOFTWARE,
570            DeviceState::from_bits(MUTED_BITS).unwrap(),
571        );
572        input_state.set_source_state(
573            InputDeviceType::CAMERA,
574            DEFAULT_CAMERA_NAME.to_string(),
575            DeviceStateSource::HARDWARE,
576            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
577        );
578
579        // Get the source state for each source and device type.
580        assert_eq!(
581            input_state
582                .get_source_state(
583                    InputDeviceType::MICROPHONE,
584                    DEFAULT_MIC_NAME.to_string(),
585                    DeviceStateSource::SOFTWARE
586                )
587                .unwrap(),
588            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
589        );
590        assert_eq!(
591            input_state
592                .get_source_state(
593                    InputDeviceType::MICROPHONE,
594                    DEFAULT_MIC_NAME.to_string(),
595                    DeviceStateSource::HARDWARE
596                )
597                .unwrap(),
598            DeviceState::from_bits(MUTED_BITS).unwrap(),
599        );
600        assert_eq!(
601            input_state
602                .get_source_state(
603                    InputDeviceType::CAMERA,
604                    DEFAULT_CAMERA_NAME.to_string(),
605                    DeviceStateSource::SOFTWARE
606                )
607                .unwrap(),
608            DeviceState::from_bits(MUTED_BITS).unwrap(),
609        );
610        assert_eq!(
611            input_state
612                .get_source_state(
613                    InputDeviceType::CAMERA,
614                    DEFAULT_CAMERA_NAME.to_string(),
615                    DeviceStateSource::HARDWARE
616                )
617                .unwrap(),
618            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
619        );
620
621        // Get the overall states for each device.
622        assert_eq!(
623            input_state
624                .get_state(InputDeviceType::MICROPHONE, DEFAULT_MIC_NAME.to_string())
625                .unwrap(),
626            DeviceState::from_bits(MUTED_BITS).unwrap(),
627        );
628        assert_eq!(
629            input_state
630                .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
631                .unwrap(),
632            DeviceState::from_bits(MUTED_BITS).unwrap(),
633        );
634
635        // Switch the mic hardware on.
636        input_state.set_source_state(
637            InputDeviceType::MICROPHONE,
638            DEFAULT_MIC_NAME.to_string(),
639            DeviceStateSource::HARDWARE,
640            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
641        );
642        assert_eq!(
643            input_state
644                .get_state(InputDeviceType::MICROPHONE, DEFAULT_MIC_NAME.to_string())
645                .unwrap(),
646            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
647        );
648
649        // Switch the camera software on.
650        input_state.set_source_state(
651            InputDeviceType::CAMERA,
652            DEFAULT_CAMERA_NAME.to_string(),
653            DeviceStateSource::SOFTWARE,
654            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
655        );
656        assert_eq!(
657            input_state
658                .get_state(InputDeviceType::CAMERA, DEFAULT_CAMERA_NAME.to_string())
659                .unwrap(),
660            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
661        );
662    }
663
664    #[fuchsia::test]
665    fn test_input_configuration_to_input_state() {
666        let config = InputConfiguration {
667            devices: vec![
668                create_device_config(
669                    DEFAULT_MIC_NAME,
670                    InputDeviceType::MICROPHONE,
671                    MUTED_BITS,
672                    AVAILABLE_BITS,
673                ),
674                create_device_config(
675                    DEFAULT_CAMERA_NAME,
676                    InputDeviceType::CAMERA,
677                    AVAILABLE_BITS,
678                    AVAILABLE_BITS,
679                ),
680                create_device_config(
681                    "camera2",
682                    InputDeviceType::CAMERA,
683                    AVAILABLE_BITS,
684                    MUTED_DISABLED_BITS,
685                ),
686            ],
687        };
688        let result: InputState = config.into();
689        assert_eq!(
690            result
691                .get_source_state(
692                    InputDeviceType::MICROPHONE,
693                    DEFAULT_MIC_NAME.to_string(),
694                    DeviceStateSource::SOFTWARE,
695                )
696                .unwrap(),
697            DeviceState::from_bits(MUTED_BITS).unwrap(),
698        );
699        assert_eq!(
700            result
701                .get_source_state(
702                    InputDeviceType::MICROPHONE,
703                    DEFAULT_MIC_NAME.to_string(),
704                    DeviceStateSource::HARDWARE,
705                )
706                .unwrap(),
707            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
708        );
709        assert_eq!(
710            result
711                .get_source_state(
712                    InputDeviceType::CAMERA,
713                    DEFAULT_CAMERA_NAME.to_string(),
714                    DeviceStateSource::SOFTWARE,
715                )
716                .unwrap(),
717            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
718        );
719        assert_eq!(
720            result
721                .get_source_state(
722                    InputDeviceType::CAMERA,
723                    DEFAULT_CAMERA_NAME.to_string(),
724                    DeviceStateSource::HARDWARE,
725                )
726                .unwrap(),
727            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
728        );
729        assert_eq!(
730            result
731                .get_source_state(
732                    InputDeviceType::CAMERA,
733                    "camera2".to_string(),
734                    DeviceStateSource::SOFTWARE,
735                )
736                .unwrap(),
737            DeviceState::from_bits(AVAILABLE_BITS).unwrap(),
738        );
739        assert_eq!(
740            result
741                .get_source_state(
742                    InputDeviceType::CAMERA,
743                    "camera2".to_string(),
744                    DeviceStateSource::HARDWARE,
745                )
746                .unwrap(),
747            DeviceState::from_bits(MUTED_DISABLED_BITS).unwrap(),
748        );
749    }
750
751    #[fuchsia::test]
752    /// Test that the combination of the input device's source states results
753    /// in the correct overall device state.
754    fn test_overall_state() {
755        // The last number doesn't matter here, it will be overwritten by the
756        // compute_input_state calls.
757        let mut mic_available = create_input_device(
758            DEFAULT_MIC_NAME,
759            InputDeviceType::MICROPHONE,
760            AVAILABLE_BITS,
761            AVAILABLE_BITS,
762            AVAILABLE_BITS,
763        );
764        let mut mic_disabled = create_input_device(
765            DEFAULT_MIC_NAME,
766            InputDeviceType::MICROPHONE,
767            MUTED_DISABLED_BITS,
768            AVAILABLE_BITS,
769            MUTED_DISABLED_BITS,
770        );
771        let mut mic_muted = create_input_device(
772            DEFAULT_MIC_NAME,
773            InputDeviceType::MICROPHONE,
774            AVAILABLE_BITS,
775            MUTED_BITS,
776            MUTED_BITS,
777        );
778        let mut mic_active = create_input_device(
779            DEFAULT_MIC_NAME,
780            InputDeviceType::MICROPHONE,
781            3,
782            AVAILABLE_BITS,
783            3,
784        );
785        let mut mic_error = create_input_device(
786            DEFAULT_MIC_NAME,
787            InputDeviceType::MICROPHONE,
788            10,
789            AVAILABLE_BITS,
790            16,
791        );
792
793        mic_available.compute_input_state();
794        mic_disabled.compute_input_state();
795        mic_muted.compute_input_state();
796        mic_active.compute_input_state();
797        mic_error.compute_input_state();
798
799        assert_eq!(mic_available.state, DeviceState::AVAILABLE);
800        assert_eq!(mic_disabled.state, DeviceState::DISABLED | DeviceState::MUTED);
801        assert_eq!(mic_muted.state, DeviceState::MUTED);
802        assert_eq!(mic_active.state, DeviceState::ACTIVE | DeviceState::AVAILABLE);
803        assert_eq!(mic_error.state, DeviceState::ERROR);
804    }
805
806    #[fuchsia::test]
807    fn test_input_device_to_fidl_input_device() {
808        let expected_mic: FidlInputDevice = create_fidl_input_device(
809            DEFAULT_MIC_NAME,
810            FidlDeviceType::Microphone,
811            AVAILABLE_BITS,
812            AVAILABLE_BITS,
813            AVAILABLE_BITS,
814        );
815        let expected_cam: FidlInputDevice = create_fidl_input_device(
816            DEFAULT_CAMERA_NAME,
817            FidlDeviceType::Camera,
818            AVAILABLE_BITS,
819            MUTED_BITS,
820            MUTED_BITS,
821        );
822
823        let mut mic = InputDevice::new(DEFAULT_MIC_NAME.to_string(), InputDeviceType::MICROPHONE);
824        let _ = mic
825            .source_states
826            .insert(DeviceStateSource::SOFTWARE, DeviceState::from_bits(AVAILABLE_BITS).unwrap());
827        let _ = mic
828            .source_states
829            .insert(DeviceStateSource::HARDWARE, DeviceState::from_bits(AVAILABLE_BITS).unwrap());
830        mic.state = DeviceState::from_bits(AVAILABLE_BITS).unwrap();
831
832        let mut cam = InputDevice::new(DEFAULT_CAMERA_NAME.to_string(), InputDeviceType::CAMERA);
833        let _ = cam
834            .source_states
835            .insert(DeviceStateSource::SOFTWARE, DeviceState::from_bits(AVAILABLE_BITS).unwrap());
836        let _ = cam
837            .source_states
838            .insert(DeviceStateSource::HARDWARE, DeviceState::from_bits(MUTED_BITS).unwrap());
839        cam.state = DeviceState::from_bits(MUTED_BITS).unwrap();
840
841        let mic_res: FidlInputDevice = mic.into();
842        let cam_res: FidlInputDevice = cam.into();
843
844        verify_fidl_input_device_eq(mic_res, expected_mic);
845        verify_fidl_input_device_eq(cam_res, expected_cam);
846    }
847
848    #[fuchsia::test]
849    fn test_input_device_type_to_string() {
850        assert_eq!(InputDeviceType::CAMERA.to_string(), DEFAULT_CAMERA_NAME);
851        assert_eq!(InputDeviceType::MICROPHONE.to_string(), DEFAULT_MIC_NAME);
852    }
853
854    #[fuchsia::test]
855    fn test_fidl_device_type_to_device_type() {
856        let cam_res: FidlDeviceType = InputDeviceType::CAMERA.into();
857        let mic_res: FidlDeviceType = InputDeviceType::MICROPHONE.into();
858        assert_eq!(cam_res, FidlDeviceType::Camera);
859        assert_eq!(mic_res, FidlDeviceType::Microphone);
860    }
861
862    #[fuchsia::test]
863    fn test_device_type_to_fidl_device_type() {
864        let cam_res: InputDeviceType = FidlDeviceType::Camera.into();
865        let mic_res: InputDeviceType = FidlDeviceType::Microphone.into();
866        assert_eq!(cam_res, InputDeviceType::CAMERA);
867        assert_eq!(mic_res, InputDeviceType::MICROPHONE);
868    }
869
870    #[fuchsia::test]
871    fn test_fidl_device_state_source_to_device_state_source() {
872        let hw_res: FidlDeviceStateSource = DeviceStateSource::HARDWARE.into();
873        let sw_res: FidlDeviceStateSource = DeviceStateSource::SOFTWARE.into();
874        assert_eq!(hw_res, FidlDeviceStateSource::Hardware);
875        assert_eq!(sw_res, FidlDeviceStateSource::Software);
876    }
877
878    #[fuchsia::test]
879    fn test_device_state_source_to_fidl_device_state_source() {
880        let hw_res: DeviceStateSource = FidlDeviceStateSource::Hardware.into();
881        let sw_res: DeviceStateSource = FidlDeviceStateSource::Software.into();
882        assert_eq!(hw_res, DeviceStateSource::HARDWARE);
883        assert_eq!(sw_res, DeviceStateSource::SOFTWARE);
884    }
885
886    #[fuchsia::test]
887    fn test_device_state_errors() {
888        let available_disabled = DeviceState::from_bits(9).unwrap();
889        let available_muted = DeviceState::from_bits(5).unwrap();
890        let active_muted = DeviceState::from_bits(6).unwrap();
891        let active_disabled = DeviceState::from_bits(10).unwrap();
892        assert!(available_disabled.has_error());
893        assert!(available_muted.has_error());
894        assert!(active_muted.has_error());
895        assert!(active_disabled.has_error());
896    }
897
898    #[fuchsia::test]
899    fn test_fidl_device_state_to_device_state() {
900        let device_state: DeviceState = FidlDeviceState {
901            toggle_flags: FidlToggleFlags::from_bits(MUTED_BITS),
902            ..Default::default()
903        }
904        .into();
905        assert_eq!(device_state, DeviceState::from_bits(MUTED_BITS).unwrap(),);
906    }
907
908    #[fuchsia::test]
909    fn test_device_state_to_fidl_device_state() {
910        let fidl_device_state: FidlDeviceState = DeviceState::from_bits(MUTED_BITS).unwrap().into();
911        assert_eq!(
912            fidl_device_state,
913            FidlDeviceState {
914                toggle_flags: FidlToggleFlags::from_bits(MUTED_BITS),
915                ..Default::default()
916            }
917        );
918    }
919}