pub trait DeviceControl: Send + Sync {
Show 24 methods
// Required methods
fn platform(&self) -> Platform;
fn launch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<u32, DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn launch_with_args<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
args: &'life3 [String],
activity: Option<&'life4 str>,
) -> Pin<Box<dyn Future<Output = Result<u32, DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait;
fn terminate<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn install<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
app_path: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn uninstall<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn keychain_reset<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn privacy_reset_all<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn clear_app_sandbox<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn open_url<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
url: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn send_push<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
apns_json_path: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait;
fn screenshot<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn pasteboard_set<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
text: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn pasteboard_get<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<String, DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn add_media<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
paths: &'life2 [String],
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn location_set<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
lat: f64,
lon: f64,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait;
fn location_start<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
points: &'life2 [(f64, f64)],
speed_mps: Option<f64>,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn set_permission<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
permission: Permission,
action: PermissionAction,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn start_recording<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
output_path: &'life2 Path,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait;
fn stop_recording<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait;
// Provided methods
fn as_ios_simctl(&self) -> Option<&SimctlClient> { ... }
fn set_animations_quiet<'life0, 'life1, 'async_trait>(
&'life0 self,
_id: &'life1 str,
_quiet: bool,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
fn user_defaults_delete<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_udid: &'life1 str,
_bundle_id: &'life2 str,
_key: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait { ... }
fn capture_bgra<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<CapturedFrame, DeviceControlError>> + Send + 'async_trait>>
where Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait { ... }
}Expand description
Sim/host control trait. The iOS impl wraps xcrun simctl; the
Android impl wraps adb.
Methods take udid: &str first (iOS terminology; Android maps this
to the device serial). All return Result<_, DeviceControlError> — the
Android impl wraps adb errors into the same enum.
Required Methods§
fn launch<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<u32, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Sourcefn launch_with_args<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
args: &'life3 [String],
activity: Option<&'life4 str>,
) -> Pin<Box<dyn Future<Output = Result<u32, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
fn launch_with_args<'life0, 'life1, 'life2, 'life3, 'life4, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
args: &'life3 [String],
activity: Option<&'life4 str>,
) -> Pin<Box<dyn Future<Output = Result<u32, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
'life4: 'async_trait,
Launch with process arguments, and on Android with an explicit entry point.
activity is None unless a flow’s app config named one. The
Android side resolved every launch to <pkg>/.MainActivity
before this parameter existed, which is right for a scaffolded
app and wrong for every AOSP one; None now means “ask the
package manager” rather than “assume”. iOS ignores it — a
bundle id already names what to launch.
fn terminate<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn install<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
app_path: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn uninstall<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn keychain_reset<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Sourcefn privacy_reset_all<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn privacy_reset_all<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Revoke every privacy permission the app has been granted.
Companion to Self::clear_app_sandbox; together they are the
in-place replacement for launchApp: clearState: true, which avoids
uninstall-and-reinstall and the XCUITest binding loss that follows.
Required, deliberately. This defaulted to Ok(()) “so non-iOS
device controls keep compiling”, and the result was that
clearState: true on Android reported success while clearing
nothing — the planner emits this op whatever the platform. A device
control that cannot do this has to say so out loud.
Sourcefn clear_app_sandbox<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn clear_app_sandbox<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
Wipe the app’s persisted data without uninstalling it, so the test binding survives.
Required for the same reason as Self::privacy_reset_all.
fn open_url<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
url: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn send_push<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
apns_json_path: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn screenshot<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<Vec<u8>, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn pasteboard_set<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
text: &'life2 str,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn pasteboard_get<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<String, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn add_media<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
paths: &'life2 [String],
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn location_set<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
lat: f64,
lon: f64,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn location_start<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
points: &'life2 [(f64, f64)],
speed_mps: Option<f64>,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn set_permission<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
bundle_id: &'life2 str,
permission: Permission,
action: PermissionAction,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn start_recording<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
udid: &'life1 str,
output_path: &'life2 Path,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn stop_recording<'life0, 'async_trait>(
&'life0 self,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
Provided Methods§
Sourcefn as_ios_simctl(&self) -> Option<&SimctlClient>
fn as_ios_simctl(&self) -> Option<&SimctlClient>
iOS-only escape hatch: downcast to &SimctlClient for legacy
App::simctl() API surface. Android impl returns None.
Sourcefn set_animations_quiet<'life0, 'life1, 'async_trait>(
&'life0 self,
_id: &'life1 str,
_quiet: bool,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn set_animations_quiet<'life0, 'life1, 'async_trait>(
&'life0 self,
_id: &'life1 str,
_quiet: bool,
) -> Pin<Box<dyn Future<Output = Result<(), DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Push the device’s animations as low as this platform allows, then read the settings back and refuse if they did not take.
quiet = true is the default a run gets; false restores the
device’s own settings for --animations.
How low differs by platform and the difference is not papered
over. Android zeroes three scales, which really is off. iOS
does nothing, because nothing on the host can: simctl ui has
no motion option, simctl spawn … defaults write cannot write
any domain, and XCUITest runs in its own process so
UIView.setAnimationsEnabled(false) cannot reach the app. This
interface first claimed iOS got Reduce Motion; a device said
otherwise.
Reading back is not belt-and-braces. simctl ui appearance is
documented per-simulator and behaves globally; a setting written
by smix is not believed until the device repeats it. A switch
that reports success while the device kept animating is worse
than no switch — the run that follows looks deterministic and is
not.
Sourcefn user_defaults_delete<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_udid: &'life1 str,
_bundle_id: &'life2 str,
_key: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
fn user_defaults_delete<'life0, 'life1, 'life2, 'life3, 'async_trait>(
&'life0 self,
_udid: &'life1 str,
_bundle_id: &'life2 str,
_key: &'life3 str,
) -> Pin<Box<dyn Future<Output = Result<bool, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
'life3: 'async_trait,
Delete a single key from the target app’s persisted
user-defaults / preferences store. iOS: simctl spawn defaults delete <bundle> <key> (NSUserDefaults via the sim’s cfprefsd).
Returns Ok(true) when the key existed, Ok(false) when
already absent (both are the “ensure absent” target state).
Default impl errors explicitly — Android SharedPreferences has
no host-side per-key deletion path (files are app-private;
pm clear is the whole-store hammer, which is clearAppData’s
job, not this verb’s). NOT a silent no-op: a consumer relying
on the deletion for test correctness must hear that it didn’t
happen.
Sourcefn capture_bgra<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<CapturedFrame, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
fn capture_bgra<'life0, 'life1, 'async_trait>(
&'life0 self,
udid: &'life1 str,
) -> Pin<Box<dyn Future<Output = Result<CapturedFrame, DeviceControlError>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
Capture a frame preferring the fast raw-BGRA path (iOS: resident
IOSurface host, ~0.3 ms, skips the PNG encode+decode round-trip for
diff-loop consumers). The default impl wraps screenshot
as a PNG frame, so backends without a direct path (Android) keep
working unchanged.
Since smix 2.0.0.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".