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