creator_simctl/
status_bar.rs

1//! Supporting types for the `simctl status_bar` subcommand.
2
3use super::{Device, Result, Validate};
4
5/// Controls the battery state that is shown in the status bar.
6#[derive(Clone, Debug, Eq, PartialEq)]
7pub enum BatteryState {
8    /// Indicates that the battery is charging.
9    Charging,
10
11    /// Indicates that the battery is fully charged.
12    Charged,
13
14    /// Indicates that the battery is discharging (i.e. disconnected from an
15    /// external power source).
16    Discharging,
17}
18
19/// Controls the cellular mode that is shown in the status bar.
20#[derive(Copy, Clone, Debug, Eq, PartialEq)]
21pub enum CellularMode {
22    /// Indicates that this device does not support cellular connectivity.
23    NotSupported,
24
25    /// Indicates that the device is currently searching for a cellular network.
26    Searching,
27
28    /// Indicates that the device has failed to find a cellular network.
29    Failed,
30
31    /// Indicates that the device is currently connected to a cellular network.
32    Active,
33}
34
35/// Controls the data network that is shown in the status bar.
36#[derive(Copy, Clone, Debug, Eq, PartialEq)]
37pub enum DataNetworkType {
38    /// Indicates that the device is connected to a Wi-Fi network.
39    Wifi,
40
41    /// Indicates that the device is connected to a 3G cellular network.
42    Cell3G,
43
44    /// Indicates that the device is connected to a 4G cellular network.
45    Cell4G,
46
47    /// Indicates that the device is connected to a LTE cellular network.
48    CellLte,
49
50    /// Indicates that the device is connected to a LTE-Advanced cellular
51    /// network.
52    CellLteA,
53
54    /// Indicates that the device is connected to a LTE+ cellular network.
55    CellLtePlus,
56}
57
58/// Controls the Wi-Fi mode that is shown in the status bar.
59#[derive(Copy, Clone, Debug, Eq, PartialEq)]
60pub enum WifiMode {
61    /// Indicates that the device is searching for a Wi-Fi network.
62    Searching,
63
64    /// Indicates that the device failed to find a Wi-Fi network.
65    Failed,
66
67    /// Indicates that the device is currently connected to a Wi-Fi network.
68    Active,
69}
70
71/// Wrapper around the `simctl status_bar` subcommand.
72pub struct StatusBar {
73    device: Device,
74}
75
76impl StatusBar {
77    /// Clears any previous override.
78    pub fn clear(&self) -> Result<()> {
79        self.device
80            .simctl()
81            .command("status_bar")
82            .arg(&self.device.udid)
83            .arg("clear")
84            .output()?
85            .validate()
86    }
87
88    /// Creates a new empty override that can be applied to this status bar.
89    pub fn empty_override(&self) -> StatusBarOverride {
90        StatusBarOverride {
91            device: self.device.clone(),
92            time: None,
93            data_network: None,
94            wifi_mode: None,
95            wifi_bars: None,
96            cellular_mode: None,
97            cellular_bars: None,
98            operator_name: None,
99            battery_state: None,
100            battery_level: None,
101        }
102    }
103}
104
105/// Builder that can be used to customize the status bar override before
106/// applying it.
107pub struct StatusBarOverride {
108    device: Device,
109    time: Option<String>,
110    data_network: Option<DataNetworkType>,
111    wifi_mode: Option<WifiMode>,
112    wifi_bars: Option<usize>,
113    cellular_mode: Option<CellularMode>,
114    cellular_bars: Option<usize>,
115    operator_name: Option<String>,
116    battery_state: Option<BatteryState>,
117    battery_level: Option<usize>,
118}
119
120impl StatusBarOverride {
121    /// Updates the time that is shown in the status bar.
122    pub fn time(&mut self, time: &str) -> &mut StatusBarOverride {
123        self.time = Some(time.to_owned());
124        self
125    }
126
127    /// Updates the data network type that is shown in the status bar (e.g. 3G
128    /// or 4G).
129    pub fn data_network(&mut self, data_network: DataNetworkType) -> &mut StatusBarOverride {
130        self.data_network = Some(data_network);
131        self
132    }
133
134    /// Updates the wifi mode that is shown in the status bar (i.e. whether it's
135    /// active or not).
136    pub fn wifi_mode(&mut self, wifi_mode: WifiMode) -> &mut StatusBarOverride {
137        self.wifi_mode = Some(wifi_mode);
138        self
139    }
140
141    /// Updates the number of wifi bars that are shown in the status bar. This
142    /// is only applicable if the wifi mode is [`WifiMode::Active`].
143    pub fn wifi_bars(&mut self, wifi_bars: usize) -> &mut StatusBarOverride {
144        self.wifi_bars = Some(wifi_bars);
145        self
146    }
147
148    /// Updates the cellular mode that is shown in the status bar (i.e. whether
149    /// it's active or not).
150    pub fn cellular_mode(&mut self, cellular_mode: CellularMode) -> &mut StatusBarOverride {
151        self.cellular_mode = Some(cellular_mode);
152        self
153    }
154
155    /// Updates the number of cellular bars that are shown in the status bar.
156    /// This is only applicable if the cellular mode is
157    /// [`CellularMode::Active`].
158    pub fn cellular_bars(&mut self, cellular_bars: usize) -> &mut StatusBarOverride {
159        self.cellular_bars = Some(cellular_bars);
160        self
161    }
162
163    /// Updates the operator name that is shown in the status bar. This is only
164    /// applicable if the cellular mode is [`CellularMode::Active`].
165    pub fn operator_name(&mut self, name: &str) -> &mut StatusBarOverride {
166        self.operator_name = Some(name.to_owned());
167        self
168    }
169
170    /// Updates the battery state that is shown in the status bar.
171    pub fn battery_state(&mut self, state: BatteryState) -> &mut StatusBarOverride {
172        self.battery_state = Some(state);
173        self
174    }
175
176    /// Updates the battery state that is shown in the status bar. This is only
177    /// applicable if the battery state is [`BatteryState::Discharging`].
178    pub fn battery_level(&mut self, level: usize) -> &mut StatusBarOverride {
179        self.battery_level = Some(level);
180        self
181    }
182
183    /// Applies this override to the status bar.
184    pub fn apply(&self) -> Result<()> {
185        let mut command = self.device.simctl().command("status_bar");
186
187        command.arg(&self.device.udid).arg("override");
188
189        if let Some(time) = self.time.as_ref() {
190            command.arg("--time").arg(time);
191        }
192
193        if let Some(network) = self.data_network.as_ref() {
194            command.arg("--dataNetwork").arg(match network {
195                DataNetworkType::Wifi => "wifi",
196                DataNetworkType::Cell3G => "3g",
197                DataNetworkType::Cell4G => "4g",
198                DataNetworkType::CellLte => "lte",
199                DataNetworkType::CellLteA => "lte-a",
200                DataNetworkType::CellLtePlus => "lte+",
201            });
202        }
203
204        if let Some(mode) = self.wifi_mode.as_ref() {
205            command.arg("--wifiMode").arg(match mode {
206                WifiMode::Searching => "searching",
207                WifiMode::Failed => "failed",
208                WifiMode::Active => "active",
209            });
210        }
211
212        if let Some(bars) = self.wifi_bars.as_ref() {
213            command.arg("--wifiBars").arg(bars.to_string());
214        }
215
216        if let Some(mode) = self.cellular_mode.as_ref() {
217            command.arg("--cellularMode").arg(match mode {
218                CellularMode::NotSupported => "notSupported",
219                CellularMode::Searching => "searching",
220                CellularMode::Failed => "failed",
221                CellularMode::Active => "active",
222            });
223        }
224
225        if let Some(bars) = self.cellular_bars.as_ref() {
226            command.arg("--cellularBars").arg(bars.to_string());
227        }
228
229        if let Some(name) = self.operator_name.as_ref() {
230            command.arg("--operatorName").arg(&name);
231        }
232
233        if let Some(state) = self.battery_state.as_ref() {
234            command.arg("--batteryState").arg(match state {
235                BatteryState::Charging => "charging",
236                BatteryState::Charged => "charged",
237                BatteryState::Discharging => "discharging",
238            });
239        }
240
241        if let Some(level) = self.battery_level.as_ref() {
242            command.arg("--batteryLevel").arg(level.to_string());
243        }
244
245        command.output()?.validate()
246    }
247}
248
249impl Device {
250    /// Returns a wrapper around the `simctl status_bar` subcommand.
251    pub fn status_bar(&self) -> StatusBar {
252        StatusBar {
253            device: self.clone(),
254        }
255    }
256}
257
258#[cfg(test)]
259mod tests {
260    use serial_test::serial;
261
262    use super::*;
263    use crate::mock;
264
265    #[test]
266    #[serial]
267    fn test_status_bar() -> Result<()> {
268        mock::device()?.boot()?;
269        mock::device()?
270            .status_bar()
271            .empty_override()
272            .time("00:00")
273            .data_network(DataNetworkType::Cell4G)
274            .cellular_mode(CellularMode::Active)
275            .cellular_bars(3)
276            .operator_name("Babel")
277            .battery_state(BatteryState::Discharging)
278            .battery_level(42)
279            .apply()?;
280        mock::device()?.status_bar().clear()?;
281        mock::device()?.shutdown()?;
282
283        Ok(())
284    }
285}