appium_client/commands/
battery.rs

1//! Battery info
2use std::collections::HashMap;
3use std::marker::PhantomData;
4use std::ops::Deref;
5use async_trait::async_trait;
6use fantoccini::error::CmdError;
7use serde_json::Value;
8use crate::{AndroidClient, AppiumClientTrait, IOSClient};
9use crate::capabilities::android::AndroidCapabilities;
10use crate::capabilities::AppiumCapability;
11use crate::capabilities::ios::IOSCapabilities;
12
13/// Device battery level and state
14#[async_trait]
15pub trait HasBattery<Caps>: AppiumClientTrait
16    where Caps: AppiumCapability
17{
18    async fn battery_info(&self) -> Result<BatteryInfo<Caps>, CmdError> {
19        let value = self.execute("mobile: batteryInfo", vec![]).await?;
20        Ok(BatteryInfo {
21            inner: serde_json::from_value(value)?,
22            caps: PhantomData,
23        })
24    }
25}
26
27
28#[async_trait]
29impl HasBattery<AndroidCapabilities> for AndroidClient {}
30
31#[async_trait]
32impl HasBattery<IOSCapabilities> for IOSClient {}
33
34pub struct BatteryInfo<Caps>
35    where Caps: AppiumCapability {
36    inner: HashMap<String, Value>,
37    caps: PhantomData<Caps>,
38}
39
40impl<Caps> BatteryInfo<Caps>
41    where Caps: AppiumCapability {
42
43    pub fn level(&self) -> f64 {
44        self.get("level")
45            .cloned()
46            .and_then(|v| serde_json::from_value(v).ok())
47            .unwrap_or(0f64)
48    }
49}
50
51impl<Caps> Deref for BatteryInfo<Caps>
52    where Caps: AppiumCapability {
53    type Target = HashMap<String, Value>;
54
55    fn deref(&self) -> &Self::Target {
56        &self.inner
57    }
58}
59
60pub trait CanBeCharged {
61    fn is_full(&self) -> bool;
62    fn is_charging(&self) -> bool;
63    fn is_plugged(&self) -> bool;
64    fn is_invalid(&self) -> bool;
65}
66
67#[derive(Copy, Clone, Debug, Eq, PartialEq)]
68pub enum AndroidBatteryState {
69    Unknown,
70    Charging,
71    Discharging,
72    NotCharging,
73    Full,
74}
75
76impl BatteryInfo<AndroidCapabilities> {
77    pub fn state(&self) -> AndroidBatteryState {
78        self.get("state")
79            .cloned()
80            .and_then(|v| serde_json::from_value::<u32>(v).ok())
81            .map(|state| match state {
82                2 => AndroidBatteryState::Charging,
83                3 => AndroidBatteryState::Discharging,
84                4 => AndroidBatteryState::NotCharging,
85                5 => AndroidBatteryState::Full,
86                _ => AndroidBatteryState::Unknown
87            })
88            .unwrap_or(AndroidBatteryState::Unknown)
89    }
90}
91
92impl CanBeCharged for BatteryInfo<AndroidCapabilities> {
93    fn is_full(&self) -> bool {
94        self.state() == AndroidBatteryState::Full
95    }
96
97    fn is_charging(&self) -> bool {
98        self.state() == AndroidBatteryState::Charging
99    }
100
101    fn is_plugged(&self) -> bool {
102        let state = self.state();
103        state == AndroidBatteryState::NotCharging || state == AndroidBatteryState::Discharging
104    }
105
106    fn is_invalid(&self) -> bool {
107        self.state() == AndroidBatteryState::Unknown
108    }
109}
110
111#[derive(Copy, Clone, Debug, Eq, PartialEq)]
112pub enum IOSBatteryState {
113    Unknown,
114    Unplugged,
115    Charging,
116    Full,
117}
118
119impl BatteryInfo<IOSCapabilities> {
120    pub fn state(&self) -> IOSBatteryState {
121        self.get("state")
122            .cloned()
123            .and_then(|v| serde_json::from_value::<u32>(v).ok())
124            .map(|state| match state {
125                1 => IOSBatteryState::Unplugged,
126                2 => IOSBatteryState::Charging,
127                3 => IOSBatteryState::Full,
128                _ => IOSBatteryState::Unknown
129            })
130            .unwrap_or(IOSBatteryState::Unknown)
131    }
132}
133
134impl CanBeCharged for BatteryInfo<IOSCapabilities> {
135    fn is_full(&self) -> bool {
136        self.state() == IOSBatteryState::Full
137    }
138
139    fn is_charging(&self) -> bool {
140        self.state() == IOSBatteryState::Charging
141    }
142
143    fn is_plugged(&self) -> bool {
144        self.state() != IOSBatteryState::Unplugged
145    }
146
147    fn is_invalid(&self) -> bool {
148        self.state() == IOSBatteryState::Unknown
149    }
150}