Switch many `Device` methods to be async (#9587)
`adb` can sometimes hang, which will in turn hang the Dart isolate if
we're using `Process.runSync()`. This changes many of the `Device` methods
to return `Future<T>` in order to allow them to use the async process
methods. A future change will add timeouts to the associated calls so
that we can properly alert the user to the hung `adb` process.
This is work towards #7102, #9567
diff --git a/packages/flutter_tools/lib/src/android/android_device.dart b/packages/flutter_tools/lib/src/android/android_device.dart
index c83ad4a..0d3044c 100644
--- a/packages/flutter_tools/lib/src/android/android_device.dart
+++ b/packages/flutter_tools/lib/src/android/android_device.dart
@@ -51,7 +51,7 @@
bool _isLocalEmulator;
TargetPlatform _platform;
- String _getProperty(String name) {
+ Future<String> _getProperty(String name) async {
if (_properties == null) {
_properties = <String, String>{};
@@ -79,19 +79,19 @@
}
@override
- bool get isLocalEmulator {
+ Future<bool> get isLocalEmulator async {
if (_isLocalEmulator == null) {
- final String characteristics = _getProperty('ro.build.characteristics');
+ final String characteristics = await _getProperty('ro.build.characteristics');
_isLocalEmulator = characteristics != null && characteristics.contains('emulator');
}
return _isLocalEmulator;
}
@override
- TargetPlatform get targetPlatform {
+ Future<TargetPlatform> get targetPlatform async {
if (_platform == null) {
// http://developer.android.com/ndk/guides/abis.html (x86, armeabi-v7a, ...)
- switch (_getProperty('ro.product.cpu.abi')) {
+ switch (await _getProperty('ro.product.cpu.abi')) {
case 'x86_64':
_platform = TargetPlatform.android_x64;
break;
@@ -108,11 +108,12 @@
}
@override
- String get sdkNameAndVersion => 'Android $_sdkVersion (API $_apiVersion)';
+ Future<String> get sdkNameAndVersion async =>
+ 'Android ${await _sdkVersion} (API ${await _apiVersion})';
- String get _sdkVersion => _getProperty('ro.build.version.release');
+ Future<String> get _sdkVersion => _getProperty('ro.build.version.release');
- String get _apiVersion => _getProperty('ro.build.version.sdk');
+ Future<String> get _apiVersion => _getProperty('ro.build.version.sdk');
_AdbLogReader _logReader;
_AndroidDevicePortForwarder _portForwarder;
@@ -160,16 +161,16 @@
return false;
}
- bool _checkForSupportedAndroidVersion() {
+ Future<bool> _checkForSupportedAndroidVersion() async {
try {
// If the server is automatically restarted, then we get irrelevant
// output lines like this, which we want to ignore:
// adb server is out of date. killing..
// * daemon started successfully *
- runCheckedSync(<String>[getAdbPath(androidSdk), 'start-server']);
+ await runCheckedAsync(<String>[getAdbPath(androidSdk), 'start-server']);
// Sample output: '22'
- final String sdkVersion = _getProperty('ro.build.version.sdk');
+ final String sdkVersion = await _getProperty('ro.build.version.sdk');
final int sdkVersionParsed = int.parse(sdkVersion, onError: (String source) => null);
if (sdkVersionParsed == null) {
@@ -195,8 +196,9 @@
return '/data/local/tmp/sky.${app.id}.sha1';
}
- String _getDeviceApkSha1(ApplicationPackage app) {
- return runSync(adbCommandForDevice(<String>['shell', 'cat', _getDeviceSha1Path(app)]));
+ Future<String> _getDeviceApkSha1(ApplicationPackage app) async {
+ final RunResult result = await runAsync(adbCommandForDevice(<String>['shell', 'cat', _getDeviceSha1Path(app)]));
+ return result.stdout;
}
String _getSourceSha1(ApplicationPackage app) {
@@ -209,15 +211,15 @@
String get name => modelID;
@override
- bool isAppInstalled(ApplicationPackage app) {
+ Future<bool> isAppInstalled(ApplicationPackage app) async {
// This call takes 400ms - 600ms.
- final String listOut = runCheckedSync(adbCommandForDevice(<String>['shell', 'pm', 'list', 'packages', app.id]));
- return LineSplitter.split(listOut).contains("package:${app.id}");
+ final RunResult listOut = await runCheckedAsync(adbCommandForDevice(<String>['shell', 'pm', 'list', 'packages', app.id]));
+ return LineSplitter.split(listOut.stdout).contains("package:${app.id}");
}
@override
- bool isLatestBuildInstalled(ApplicationPackage app) {
- final String installedSha1 = _getDeviceApkSha1(app);
+ Future<bool> isLatestBuildInstalled(ApplicationPackage app) async {
+ final String installedSha1 = await _getDeviceApkSha1(app);
return installedSha1.isNotEmpty && installedSha1 == _getSourceSha1(app);
}
@@ -229,7 +231,7 @@
return false;
}
- if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
+ if (!_checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
return false;
final Status status = logger.startProgress('Installing ${apk.apkPath}...', expectSlowOperation: true);
@@ -249,11 +251,11 @@
}
@override
- bool uninstallApp(ApplicationPackage app) {
- if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
+ Future<bool> uninstallApp(ApplicationPackage app) async {
+ if (!_checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
return false;
- final String uninstallOut = runCheckedSync(adbCommandForDevice(<String>['uninstall', app.id]));
+ final String uninstallOut = (await runCheckedAsync(adbCommandForDevice(<String>['uninstall', app.id]))).stdout;
final RegExp failureExp = new RegExp(r'^Failure.*$', multiLine: true);
final String failure = failureExp.stringMatch(uninstallOut);
if (failure != null) {
@@ -265,9 +267,9 @@
}
Future<bool> _installLatestApp(ApplicationPackage package) async {
- final bool wasInstalled = isAppInstalled(package);
+ final bool wasInstalled = await isAppInstalled(package);
if (wasInstalled) {
- if (isLatestBuildInstalled(package)) {
+ if (await isLatestBuildInstalled(package)) {
printTrace('Latest build already installed.');
return true;
}
@@ -277,7 +279,7 @@
printTrace('Warning: Failed to install APK.');
if (wasInstalled) {
printStatus('Uninstalling old version...');
- if (!uninstallApp(package)) {
+ if (!await uninstallApp(package)) {
printError('Error: Uninstalling old version failed.');
return false;
}
@@ -304,10 +306,10 @@
bool prebuiltApplication: false,
bool applicationNeedsRebuild: false,
}) async {
- if (!_checkForSupportedAdbVersion() || !_checkForSupportedAndroidVersion())
+ if (!_checkForSupportedAdbVersion() || !await _checkForSupportedAndroidVersion())
return new LaunchResult.failed();
- if (targetPlatform != TargetPlatform.android_arm && mode != BuildMode.debug) {
+ if (await targetPlatform != TargetPlatform.android_arm && mode != BuildMode.debug) {
printError('Profile and release builds are only supported on ARM targets.');
return new LaunchResult.failed();
}
@@ -369,7 +371,7 @@
cmd.addAll(<String>['--ez', 'use-test-fonts', 'true']);
}
cmd.add(apk.launchActivity);
- final String result = runCheckedSync(cmd);
+ final String result = (await runCheckedAsync(cmd)).stdout;
// This invocation returns 0 even when it fails.
if (result.contains('Error: ')) {
printError(result.trim());
@@ -455,16 +457,15 @@
bool get supportsScreenshot => true;
@override
- Future<Null> takeScreenshot(File outputFile) {
+ Future<Null> takeScreenshot(File outputFile) async {
const String remotePath = '/data/local/tmp/flutter_screenshot.png';
- runCheckedSync(adbCommandForDevice(<String>['shell', 'screencap', '-p', remotePath]));
- runCheckedSync(adbCommandForDevice(<String>['pull', remotePath, outputFile.path]));
- runCheckedSync(adbCommandForDevice(<String>['shell', 'rm', remotePath]));
- return new Future<Null>.value();
+ await runCheckedAsync(adbCommandForDevice(<String>['shell', 'screencap', '-p', remotePath]));
+ await runCheckedAsync(adbCommandForDevice(<String>['pull', remotePath, outputFile.path]));
+ await runCheckedAsync(adbCommandForDevice(<String>['shell', 'rm', remotePath]));
}
@override
- Future<List<DiscoveredApp>> discoverApps() {
+ Future<List<DiscoveredApp>> discoverApps() async {
final RegExp discoverExp = new RegExp(r'DISCOVER: (.*)');
final List<DiscoveredApp> result = <DiscoveredApp>[];
final StreamSubscription<String> logs = getLogReader().logLines.listen((String line) {
@@ -475,14 +476,13 @@
}
});
- runCheckedSync(adbCommandForDevice(<String>[
+ await runCheckedAsync(adbCommandForDevice(<String>[
'shell', 'am', 'broadcast', '-a', 'io.flutter.view.DISCOVER'
]));
- return new Future<List<DiscoveredApp>>.delayed(const Duration(seconds: 1), () {
- logs.cancel();
- return result;
- });
+ await new Future<Null>.delayed(const Duration(seconds: 1));
+ logs.cancel();
+ return result;
}
}
@@ -744,7 +744,7 @@
hostPort = await portScanner.findAvailablePort();
}
- runCheckedSync(device.adbCommandForDevice(
+ await runCheckedAsync(device.adbCommandForDevice(
<String>['forward', 'tcp:$hostPort', 'tcp:$devicePort']
));
@@ -753,7 +753,7 @@
@override
Future<Null> unforward(ForwardedPort forwardedPort) async {
- runCheckedSync(device.adbCommandForDevice(
+ await runCheckedAsync(device.adbCommandForDevice(
<String>['forward', '--remove', 'tcp:${forwardedPort.hostPort}']
));
}
diff --git a/packages/flutter_tools/lib/src/base/process.dart b/packages/flutter_tools/lib/src/base/process.dart
index 8ded4f6..7b589c4 100644
--- a/packages/flutter_tools/lib/src/base/process.dart
+++ b/packages/flutter_tools/lib/src/base/process.dart
@@ -221,6 +221,15 @@
}
}
+Future<bool> exitsHappyAsync(List<String> cli) async {
+ _traceCommand(cli);
+ try {
+ return (await processManager.run(cli)).exitCode == 0;
+ } catch (error) {
+ return false;
+ }
+}
+
/// Run cmd and return stdout.
///
/// Throws an error if cmd exits with a non-zero value.
@@ -241,16 +250,6 @@
);
}
-/// Run cmd and return stdout on success.
-///
-/// Throws the standard error output if cmd exits with a non-zero value.
-String runSyncAndThrowStdErrOnError(List<String> cmd) {
- return _runWithLoggingSync(cmd,
- checked: true,
- throwStandardErrorOnError: true,
- hideStdout: true);
-}
-
/// Run cmd and return stdout.
String runSync(List<String> cmd, {
String workingDirectory,
diff --git a/packages/flutter_tools/lib/src/commands/build_aot.dart b/packages/flutter_tools/lib/src/commands/build_aot.dart
index de0dce6..10f79bb 100644
--- a/packages/flutter_tools/lib/src/commands/build_aot.dart
+++ b/packages/flutter_tools/lib/src/commands/build_aot.dart
@@ -273,24 +273,24 @@
final List<String> commonBuildOptions = <String>['-arch', 'arm64', '-miphoneos-version-min=8.0'];
if (interpreter) {
- runCheckedSync(<String>['mv', vmSnapshotData, fs.path.join(outputDir.path, kVmSnapshotData)]);
- runCheckedSync(<String>['mv', isolateSnapshotData, fs.path.join(outputDir.path, kIsolateSnapshotData)]);
+ await runCheckedAsync(<String>['mv', vmSnapshotData, fs.path.join(outputDir.path, kVmSnapshotData)]);
+ await runCheckedAsync(<String>['mv', isolateSnapshotData, fs.path.join(outputDir.path, kIsolateSnapshotData)]);
- runCheckedSync(<String>[
+ await runCheckedAsync(<String>[
'xxd', '--include', kVmSnapshotData, fs.path.basename(kVmSnapshotDataC)
], workingDirectory: outputDir.path);
- runCheckedSync(<String>[
+ await runCheckedAsync(<String>[
'xxd', '--include', kIsolateSnapshotData, fs.path.basename(kIsolateSnapshotDataC)
], workingDirectory: outputDir.path);
- runCheckedSync(<String>['xcrun', 'cc']
+ await runCheckedAsync(<String>['xcrun', 'cc']
..addAll(commonBuildOptions)
..addAll(<String>['-c', kVmSnapshotDataC, '-o', kVmSnapshotDataO]));
- runCheckedSync(<String>['xcrun', 'cc']
+ await runCheckedAsync(<String>['xcrun', 'cc']
..addAll(commonBuildOptions)
..addAll(<String>['-c', kIsolateSnapshotDataC, '-o', kIsolateSnapshotDataO]));
} else {
- runCheckedSync(<String>['xcrun', 'cc']
+ await runCheckedAsync(<String>['xcrun', 'cc']
..addAll(commonBuildOptions)
..addAll(<String>['-c', assembly, '-o', assemblyO]));
}
@@ -313,7 +313,7 @@
} else {
linkCommand.add(assemblyO);
}
- runCheckedSync(linkCommand);
+ await runCheckedAsync(linkCommand);
}
return outputPath;
diff --git a/packages/flutter_tools/lib/src/commands/config.dart b/packages/flutter_tools/lib/src/commands/config.dart
index 59484e5..11f7e07 100644
--- a/packages/flutter_tools/lib/src/commands/config.dart
+++ b/packages/flutter_tools/lib/src/commands/config.dart
@@ -44,7 +44,7 @@
/// Return `null` to disable tracking of the `config` command.
@override
- String get usagePath => null;
+ Future<String> get usagePath => null;
@override
Future<Null> runCommand() async {
diff --git a/packages/flutter_tools/lib/src/commands/daemon.dart b/packages/flutter_tools/lib/src/commands/daemon.dart
index 50483fe..951a044 100644
--- a/packages/flutter_tools/lib/src/commands/daemon.dart
+++ b/packages/flutter_tools/lib/src/commands/daemon.dart
@@ -346,7 +346,7 @@
String packagesFilePath,
String projectAssets,
}) async {
- if (device.isLocalEmulator && !isEmulatorBuildMode(options.buildMode))
+ if (await device.isLocalEmulator && !isEmulatorBuildMode(options.buildMode))
throw '${toTitleCase(getModeName(options.buildMode))} mode is not supported for emulators.';
// We change the current working directory for the duration of the `start` command.
@@ -381,7 +381,7 @@
_sendAppEvent(app, 'start', <String, dynamic>{
'deviceId': device.id,
'directory': projectDirectory,
- 'supportsRestart': isRestartSupported(enableHotReload, device)
+ 'supportsRestart': isRestartSupported(enableHotReload, device),
});
Completer<DebugConnectionInfo> connectionInfoCompleter;
@@ -505,6 +505,8 @@
}
}
+typedef void _DeviceEventHandler(Device device);
+
/// This domain lets callers list and monitor connected devices.
///
/// It exports a `getDevices()` call, as well as firing `device.added` and
@@ -530,15 +532,20 @@
_discoverers.add(deviceDiscovery);
for (PollingDeviceDiscovery discoverer in _discoverers) {
- discoverer.onAdded.listen((Device device) {
- sendEvent('device.added', _deviceToMap(device));
- });
- discoverer.onRemoved.listen((Device device) {
- sendEvent('device.removed', _deviceToMap(device));
- });
+ discoverer.onAdded.listen(_onDeviceEvent('device.added'));
+ discoverer.onRemoved.listen(_onDeviceEvent('device.removed'));
}
}
+ Future<Null> _deviceEvents = new Future<Null>.value();
+ _DeviceEventHandler _onDeviceEvent(String eventName) {
+ return (Device device) {
+ _deviceEvents = _deviceEvents.then((_) async {
+ sendEvent(eventName, await _deviceToMap(device));
+ });
+ };
+ }
+
final List<PollingDeviceDiscovery> _discoverers = <PollingDeviceDiscovery>[];
Future<List<Device>> getDevices([Map<String, dynamic> args]) {
@@ -638,18 +645,16 @@
}
dynamic _jsonEncodeObject(dynamic object) {
- if (object is Device)
- return _deviceToMap(object);
if (object is OperationResult)
return _operationResultToMap(object);
return object;
}
-Map<String, dynamic> _deviceToMap(Device device) {
+Future<Map<String, dynamic>> _deviceToMap(Device device) async {
return <String, dynamic>{
'id': device.id,
'name': device.name,
- 'platform': getNameForTargetPlatform(device.targetPlatform),
+ 'platform': getNameForTargetPlatform(await device.targetPlatform),
'emulator': device.isLocalEmulator
};
}
@@ -664,8 +669,6 @@
dynamic _toJsonable(dynamic obj) {
if (obj is String || obj is int || obj is bool || obj is Map<dynamic, dynamic> || obj is List<dynamic> || obj == null)
return obj;
- if (obj is Device)
- return obj;
if (obj is OperationResult)
return obj;
return '$obj';
diff --git a/packages/flutter_tools/lib/src/commands/devices.dart b/packages/flutter_tools/lib/src/commands/devices.dart
index 2982216..51d7aed 100644
--- a/packages/flutter_tools/lib/src/commands/devices.dart
+++ b/packages/flutter_tools/lib/src/commands/devices.dart
@@ -27,7 +27,7 @@
exitCode: 1);
}
- final List<Device> devices = await deviceManager.getAllConnectedDevices();
+ final List<Device> devices = await deviceManager.getAllConnectedDevices().toList();
if (devices.isEmpty) {
printStatus(
@@ -36,7 +36,7 @@
'potential issues, or visit https://flutter.io/setup/ for troubleshooting tips.');
} else {
printStatus('${devices.length} connected ${pluralize('device', devices.length)}:\n');
- Device.printDevices(devices);
+ await Device.printDevices(devices);
}
}
}
diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart
index 4e7d2bd..bdc0b9f 100644
--- a/packages/flutter_tools/lib/src/commands/drive.dart
+++ b/packages/flutter_tools/lib/src/commands/drive.dart
@@ -183,7 +183,7 @@
}
Future<Device> findTargetDevice() async {
- final List<Device> devices = await deviceManager.getDevices();
+ final List<Device> devices = await deviceManager.getDevices().toList();
if (deviceManager.hasSpecifiedDeviceId) {
if (devices.isEmpty) {
@@ -192,7 +192,7 @@
}
if (devices.length > 1) {
printStatus("Found ${devices.length} devices with name or id matching '${deviceManager.specifiedDeviceId}':");
- Device.printDevices(devices);
+ await Device.printDevices(devices);
return null;
}
return devices.first;
@@ -203,16 +203,24 @@
// On Mac we look for the iOS Simulator. If available, we use that. Then
// we look for an Android device. If there's one, we use that. Otherwise,
// we launch a new iOS Simulator.
- final Device reusableDevice = devices.firstWhere(
- (Device d) => d.isLocalEmulator,
- orElse: () {
- return devices.firstWhere((Device d) => d is AndroidDevice,
- orElse: () => null);
+ Device reusableDevice;
+ for (Device device in devices) {
+ if (await device.isLocalEmulator) {
+ reusableDevice = device;
+ break;
}
- );
+ }
+ if (reusableDevice == null) {
+ for (Device device in devices) {
+ if (device is AndroidDevice) {
+ reusableDevice = device;
+ break;
+ }
+ }
+ }
if (reusableDevice != null) {
- printStatus('Found connected ${reusableDevice.isLocalEmulator ? "emulator" : "device"} "${reusableDevice.name}"; will reuse it.');
+ printStatus('Found connected ${await reusableDevice.isLocalEmulator ? "emulator" : "device"} "${reusableDevice.name}"; will reuse it.');
return reusableDevice;
}
@@ -262,8 +270,8 @@
printTrace('Installing application package.');
final ApplicationPackage package = command.applicationPackages
- .getPackageForPlatform(command.device.targetPlatform);
- if (command.device.isAppInstalled(package))
+ .getPackageForPlatform(await command.device.targetPlatform);
+ if (await command.device.isAppInstalled(package))
command.device.uninstallApp(package);
command.device.installApp(package);
@@ -335,7 +343,7 @@
Future<bool> _stopApp(DriveCommand command) async {
printTrace('Stopping application.');
- final ApplicationPackage package = command.applicationPackages.getPackageForPlatform(command.device.targetPlatform);
+ final ApplicationPackage package = command.applicationPackages.getPackageForPlatform(await command.device.targetPlatform);
final bool stopped = await command.device.stopApp(package);
await command._deviceLogSubscription?.cancel();
return stopped;
diff --git a/packages/flutter_tools/lib/src/commands/install.dart b/packages/flutter_tools/lib/src/commands/install.dart
index 063585e..3651c01 100644
--- a/packages/flutter_tools/lib/src/commands/install.dart
+++ b/packages/flutter_tools/lib/src/commands/install.dart
@@ -31,7 +31,7 @@
@override
Future<Null> runCommand() async {
- final ApplicationPackage package = applicationPackages.getPackageForPlatform(device.targetPlatform);
+ final ApplicationPackage package = applicationPackages.getPackageForPlatform(await device.targetPlatform);
Cache.releaseLockEarly();
@@ -46,9 +46,9 @@
if (package == null)
return false;
- if (uninstall && device.isAppInstalled(package)) {
+ if (uninstall && await device.isAppInstalled(package)) {
printStatus('Uninstalling old version...');
- if (!device.uninstallApp(package))
+ if (!await device.uninstallApp(package))
printError('Warning: uninstalling old version failed');
}
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index 50fe3ed..aad16e6 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -153,14 +153,14 @@
Device device;
@override
- String get usagePath {
+ Future<String> get usagePath async {
final String command = shouldUseHotMode() ? 'hotrun' : name;
if (device == null)
return command;
// Return 'run/ios'.
- return '$command/${getNameForTargetPlatform(device.targetPlatform)}';
+ return '$command/${getNameForTargetPlatform(await device.targetPlatform)}';
}
@override
@@ -249,7 +249,7 @@
return null;
}
- if (device.isLocalEmulator && !isEmulatorBuildMode(getBuildMode()))
+ if (await device.isLocalEmulator && !isEmulatorBuildMode(getBuildMode()))
throwToolExit('${toTitleCase(getModeName(getBuildMode()))} mode is not supported for emulators.');
if (hotMode) {
diff --git a/packages/flutter_tools/lib/src/commands/stop.dart b/packages/flutter_tools/lib/src/commands/stop.dart
index c506ee2..836538f 100644
--- a/packages/flutter_tools/lib/src/commands/stop.dart
+++ b/packages/flutter_tools/lib/src/commands/stop.dart
@@ -31,9 +31,10 @@
@override
Future<Null> runCommand() async {
- final ApplicationPackage app = applicationPackages.getPackageForPlatform(device.targetPlatform);
+ final TargetPlatform targetPlatform = await device.targetPlatform;
+ final ApplicationPackage app = applicationPackages.getPackageForPlatform(targetPlatform);
if (app == null) {
- final String platformName = getNameForTargetPlatform(device.targetPlatform);
+ final String platformName = getNameForTargetPlatform(targetPlatform);
throwToolExit('No Flutter application for $platformName found in the current directory.');
}
printStatus('Stopping apps on ${device.name}.');
diff --git a/packages/flutter_tools/lib/src/commands/upgrade.dart b/packages/flutter_tools/lib/src/commands/upgrade.dart
index d86864c..7722dc8 100644
--- a/packages/flutter_tools/lib/src/commands/upgrade.dart
+++ b/packages/flutter_tools/lib/src/commands/upgrade.dart
@@ -28,7 +28,7 @@
@override
Future<Null> runCommand() async {
try {
- runCheckedSync(<String>[
+ await runCheckedAsync(<String>[
'git', 'rev-parse', '@{u}'
], workingDirectory: Cache.flutterRoot);
} catch (e) {
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart
index 9a76b7e..b4e0fbc 100644
--- a/packages/flutter_tools/lib/src/device.dart
+++ b/packages/flutter_tools/lib/src/device.dart
@@ -37,42 +37,40 @@
bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
- /// Return the devices with a name or id matching [deviceId].
- /// This does a case insentitive compare with [deviceId].
- Future<List<Device>> getDevicesById(String deviceId) async {
+ Stream<Device> getDevicesById(String deviceId) async* {
+ final Stream<Device> devices = getAllConnectedDevices();
deviceId = deviceId.toLowerCase();
- final List<Device> devices = await getAllConnectedDevices();
- final Device device = devices.firstWhere(
- (Device device) =>
- device.id.toLowerCase() == deviceId ||
- device.name.toLowerCase() == deviceId,
- orElse: () => null);
+ bool exactlyMatchesDeviceId(Device device) =>
+ device.id.toLowerCase() == deviceId ||
+ device.name.toLowerCase() == deviceId;
+ bool startsWithDeviceId(Device device) =>
+ device.id.toLowerCase().startsWith(deviceId) ||
+ device.name.toLowerCase().startsWith(deviceId);
- if (device != null)
- return <Device>[device];
+ final Device exactMatch = await devices.firstWhere(
+ exactlyMatchesDeviceId, defaultValue: () => null);
+ if (exactMatch != null) {
+ yield exactMatch;
+ return;
+ }
// Match on a id or name starting with [deviceId].
- return devices.where((Device device) {
- return (device.id.toLowerCase().startsWith(deviceId) ||
- device.name.toLowerCase().startsWith(deviceId));
- }).toList();
+ await for (Device device in devices.where(startsWithDeviceId))
+ yield device;
}
/// Return the list of connected devices, filtered by any user-specified device id.
- Future<List<Device>> getDevices() async {
- if (specifiedDeviceId == null) {
- return getAllConnectedDevices();
- } else {
- return getDevicesById(specifiedDeviceId);
- }
+ Stream<Device> getDevices() {
+ return hasSpecifiedDeviceId
+ ? getDevicesById(specifiedDeviceId)
+ : getAllConnectedDevices();
}
/// Return the list of all connected devices.
- Future<List<Device>> getAllConnectedDevices() async {
- return _deviceDiscoverers
+ Stream<Device> getAllConnectedDevices() {
+ return new Stream<Device>.fromIterable(_deviceDiscoverers
.where((DeviceDiscovery discoverer) => discoverer.supportsPlatform)
- .expand((DeviceDiscovery discoverer) => discoverer.devices)
- .toList();
+ .expand((DeviceDiscovery discoverer) => discoverer.devices));
}
}
@@ -141,19 +139,19 @@
bool get supportsStartPaused => true;
/// Whether it is an emulated device running on localhost.
- bool get isLocalEmulator;
+ Future<bool> get isLocalEmulator;
/// Check if a version of the given app is already installed
- bool isAppInstalled(ApplicationPackage app);
+ Future<bool> isAppInstalled(ApplicationPackage app);
/// Check if the latest build of the [app] is already installed.
- bool isLatestBuildInstalled(ApplicationPackage app);
+ Future<bool> isLatestBuildInstalled(ApplicationPackage app);
/// Install an app package on the current device
Future<bool> installApp(ApplicationPackage app);
/// Uninstall an app package from the current device
- bool uninstallApp(ApplicationPackage app);
+ Future<bool> uninstallApp(ApplicationPackage app);
/// Check if the device is supported by Flutter
bool isSupported();
@@ -162,9 +160,10 @@
// supported by Flutter, and, if not, why.
String supportMessage() => isSupported() ? "Supported" : "Unsupported";
- TargetPlatform get targetPlatform;
+ /// The device's platform.
+ Future<TargetPlatform> get targetPlatform;
- String get sdkNameAndVersion;
+ Future<String> get sdkNameAndVersion;
/// Get a log reader for this device.
/// If [app] is specified, this will return a log reader specific to that
@@ -238,23 +237,24 @@
@override
String toString() => name;
- static Iterable<String> descriptions(List<Device> devices) {
+ static Stream<String> descriptions(List<Device> devices) async* {
if (devices.isEmpty)
- return <String>[];
+ return;
// Extract device information
final List<List<String>> table = <List<String>>[];
for (Device device in devices) {
String supportIndicator = device.isSupported() ? '' : ' (unsupported)';
- if (device.isLocalEmulator) {
- final String type = device.targetPlatform == TargetPlatform.ios ? 'simulator' : 'emulator';
+ final TargetPlatform targetPlatform = await device.targetPlatform;
+ if (await device.isLocalEmulator) {
+ final String type = targetPlatform == TargetPlatform.ios ? 'simulator' : 'emulator';
supportIndicator += ' ($type)';
}
table.add(<String>[
device.name,
device.id,
- '${getNameForTargetPlatform(device.targetPlatform)}',
- '${device.sdkNameAndVersion}$supportIndicator',
+ '${getNameForTargetPlatform(targetPlatform)}',
+ '${await device.sdkNameAndVersion}$supportIndicator',
]);
}
@@ -266,13 +266,13 @@
}
// Join columns into lines of text
- return table.map((List<String> row) =>
- indices.map((int i) => row[i].padRight(widths[i])).join(' • ') +
- ' • ${row.last}');
+ for (List<String> row in table) {
+ yield indices.map((int i) => row[i].padRight(widths[i])).join(' • ') + ' • ${row.last}';
+ }
}
- static void printDevices(List<Device> devices) {
- descriptions(devices).forEach(printStatus);
+ static Future<Null> printDevices(List<Device> devices) async {
+ await descriptions(devices).forEach(printStatus);
}
}
diff --git a/packages/flutter_tools/lib/src/doctor.dart b/packages/flutter_tools/lib/src/doctor.dart
index 3bac2cc..ba28a7b 100644
--- a/packages/flutter_tools/lib/src/doctor.dart
+++ b/packages/flutter_tools/lib/src/doctor.dart
@@ -486,12 +486,12 @@
@override
Future<ValidationResult> validate() async {
- final List<Device> devices = await deviceManager.getAllConnectedDevices();
+ final List<Device> devices = await deviceManager.getAllConnectedDevices().toList();
List<ValidationMessage> messages;
if (devices.isEmpty) {
messages = <ValidationMessage>[new ValidationMessage('None')];
} else {
- messages = Device.descriptions(devices)
+ messages = await Device.descriptions(devices)
.map((String msg) => new ValidationMessage(msg)).toList();
}
return new ValidationResult(ValidationType.installed, messages);
diff --git a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
index 0c4ce20..9b1a6a5 100644
--- a/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
+++ b/packages/flutter_tools/lib/src/fuchsia/fuchsia_device.dart
@@ -37,22 +37,22 @@
final String name;
@override
- bool get isLocalEmulator => false;
+ Future<bool> get isLocalEmulator async => false;
@override
bool get supportsStartPaused => false;
@override
- bool isAppInstalled(ApplicationPackage app) => false;
+ Future<bool> isAppInstalled(ApplicationPackage app) async => false;
@override
- bool isLatestBuildInstalled(ApplicationPackage app) => false;
+ Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => false;
@override
Future<bool> installApp(ApplicationPackage app) => new Future<bool>.value(false);
@override
- bool uninstallApp(ApplicationPackage app) => false;
+ Future<bool> uninstallApp(ApplicationPackage app) async => false;
@override
bool isSupported() => true;
@@ -77,10 +77,10 @@
}
@override
- TargetPlatform get targetPlatform => TargetPlatform.fuchsia;
+ Future<TargetPlatform> get targetPlatform async => TargetPlatform.fuchsia;
@override
- String get sdkNameAndVersion => 'Fuchsia';
+ Future<String> get sdkNameAndVersion async => 'Fuchsia';
_FuchsiaLogReader _logReader;
@override
diff --git a/packages/flutter_tools/lib/src/ios/devices.dart b/packages/flutter_tools/lib/src/ios/devices.dart
index fb6bc3d..f61d486 100644
--- a/packages/flutter_tools/lib/src/ios/devices.dart
+++ b/packages/flutter_tools/lib/src/ios/devices.dart
@@ -87,7 +87,7 @@
_IOSDevicePortForwarder _portForwarder;
@override
- bool get isLocalEmulator => false;
+ Future<bool> get isLocalEmulator async => false;
@override
bool get supportsStartPaused => false;
@@ -139,10 +139,10 @@
}
@override
- bool isAppInstalled(ApplicationPackage app) {
+ Future<bool> isAppInstalled(ApplicationPackage app) async {
try {
- final String apps = runCheckedSync(<String>[installerPath, '--list-apps']);
- if (new RegExp(app.id, multiLine: true).hasMatch(apps)) {
+ final RunResult apps = await runCheckedAsync(<String>[installerPath, '--list-apps']);
+ if (new RegExp(app.id, multiLine: true).hasMatch(apps.stdout)) {
return true;
}
} catch (e) {
@@ -152,7 +152,7 @@
}
@override
- bool isLatestBuildInstalled(ApplicationPackage app) => false;
+ Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => false;
@override
Future<bool> installApp(ApplicationPackage app) async {
@@ -164,7 +164,7 @@
}
try {
- runCheckedSync(<String>[installerPath, '-i', iosApp.deviceBundlePath]);
+ await runCheckedAsync(<String>[installerPath, '-i', iosApp.deviceBundlePath]);
return true;
} catch (e) {
return false;
@@ -172,9 +172,9 @@
}
@override
- bool uninstallApp(ApplicationPackage app) {
+ Future<bool> uninstallApp(ApplicationPackage app) async {
try {
- runCheckedSync(<String>[installerPath, '-U', app.id]);
+ await runCheckedAsync(<String>[installerPath, '-U', app.id]);
return true;
} catch (e) {
return false;
@@ -343,10 +343,10 @@
}
@override
- TargetPlatform get targetPlatform => TargetPlatform.ios;
+ Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;
@override
- String get sdkNameAndVersion => 'iOS $_sdkVersion ($_buildVersion)';
+ Future<String> get sdkNameAndVersion async => 'iOS $_sdkVersion ($_buildVersion)';
String get _sdkVersion => _getDeviceInfo(id, 'ProductVersion');
@@ -370,8 +370,7 @@
@override
Future<Null> takeScreenshot(File outputFile) {
- runCheckedSync(<String>[screenshotPath, outputFile.path]);
- return new Future<Null>.value();
+ return runCheckedAsync(<String>[screenshotPath, outputFile.path]);
}
}
diff --git a/packages/flutter_tools/lib/src/ios/ios_workflow.dart b/packages/flutter_tools/lib/src/ios/ios_workflow.dart
index 018469d..70bb702 100644
--- a/packages/flutter_tools/lib/src/ios/ios_workflow.dart
+++ b/packages/flutter_tools/lib/src/ios/ios_workflow.dart
@@ -165,7 +165,7 @@
// Check for compatibility between libimobiledevice and Xcode.
// TODO(cbracken) remove this check once libimobiledevice > 1.2.0 is released.
final ProcessResult result = (await runAsync(<String>['idevice_id', '-l'])).processResult;
- if (result.exitCode == 0 && result.stdout.isNotEmpty && !exitsHappy(<String>['ideviceName'])) {
+ if (result.exitCode == 0 && result.stdout.isNotEmpty && !await exitsHappyAsync(<String>['ideviceName'])) {
brewStatus = ValidationType.partial;
messages.add(new ValidationMessage.error(
'libimobiledevice is incompatible with the installed Xcode version. To update, run:\n'
diff --git a/packages/flutter_tools/lib/src/ios/mac.dart b/packages/flutter_tools/lib/src/ios/mac.dart
index 9baf97f..cf675ac 100644
--- a/packages/flutter_tools/lib/src/ios/mac.dart
+++ b/packages/flutter_tools/lib/src/ios/mac.dart
@@ -399,7 +399,7 @@
continue;
}
// Shell out so permissions on the dylib are preserved.
- runCheckedSync(<String>['/bin/cp', dylib.path, frameworksDirectory.path]);
+ await runCheckedAsync(<String>['/bin/cp', dylib.path, frameworksDirectory.path]);
}
}
diff --git a/packages/flutter_tools/lib/src/ios/simulators.dart b/packages/flutter_tools/lib/src/ios/simulators.dart
index 6fd46b8..1f5f3e7 100644
--- a/packages/flutter_tools/lib/src/ios/simulators.dart
+++ b/packages/flutter_tools/lib/src/ios/simulators.dart
@@ -224,8 +224,8 @@
bool _isAnyConnected() => getConnectedDevices().isNotEmpty;
- bool isInstalled(String appId) {
- return exitsHappy(<String>[
+ Future<bool> isInstalled(String appId) {
+ return exitsHappyAsync(<String>[
_xcrunPath,
'simctl',
'get_app_container',
@@ -234,23 +234,23 @@
]);
}
- void install(String deviceId, String appPath) {
- runCheckedSync(<String>[_xcrunPath, 'simctl', 'install', deviceId, appPath]);
+ Future<Null> install(String deviceId, String appPath) {
+ return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'install', deviceId, appPath]);
}
- void uninstall(String deviceId, String appId) {
- runCheckedSync(<String>[_xcrunPath, 'simctl', 'uninstall', deviceId, appId]);
+ Future<Null> uninstall(String deviceId, String appId) {
+ return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'uninstall', deviceId, appId]);
}
- void launch(String deviceId, String appIdentifier, [List<String> launchArgs]) {
+ Future<Null> launch(String deviceId, String appIdentifier, [List<String> launchArgs]) {
final List<String> args = <String>[_xcrunPath, 'simctl', 'launch', deviceId, appIdentifier];
if (launchArgs != null)
args.addAll(launchArgs);
- runCheckedSync(args);
+ return runCheckedAsync(args);
}
- void takeScreenshot(String outputPath) {
- runCheckedSync(<String>[_xcrunPath, 'simctl', 'io', 'booted', 'screenshot', outputPath]);
+ Future<Null> takeScreenshot(String outputPath) {
+ return runCheckedAsync(<String>[_xcrunPath, 'simctl', 'io', 'booted', 'screenshot', outputPath]);
}
}
@@ -313,7 +313,7 @@
final String category;
@override
- bool get isLocalEmulator => true;
+ Future<bool> get isLocalEmulator async => true;
@override
bool get supportsHotMode => true;
@@ -335,12 +335,12 @@
}
@override
- bool isAppInstalled(ApplicationPackage app) {
+ Future<bool> isAppInstalled(ApplicationPackage app) {
return SimControl.instance.isInstalled(app.id);
}
@override
- bool isLatestBuildInstalled(ApplicationPackage app) => false;
+ Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => false;
@override
Future<bool> installApp(ApplicationPackage app) async {
@@ -354,9 +354,9 @@
}
@override
- bool uninstallApp(ApplicationPackage app) {
+ Future<bool> uninstallApp(ApplicationPackage app) async {
try {
- SimControl.instance.uninstall(id, app.id);
+ await SimControl.instance.uninstall(id, app.id);
return true;
} catch (e) {
return false;
@@ -495,21 +495,18 @@
}
}
- bool _applicationIsInstalledAndRunning(ApplicationPackage app) {
- final bool isInstalled = isAppInstalled(app);
-
- final bool isRunning = exitsHappy(<String>[
- '/usr/bin/killall',
- 'Runner',
+ Future<bool> _applicationIsInstalledAndRunning(ApplicationPackage app) async {
+ final List<bool> criteria = await Future.wait(<Future<bool>>[
+ isAppInstalled(app),
+ exitsHappyAsync(<String>['/usr/bin/killall', 'Runner']),
]);
-
- return isInstalled && isRunning;
+ return criteria.reduce((bool a, bool b) => a && b);
}
Future<Null> _setupUpdatedApplicationBundle(ApplicationPackage app) async {
await _sideloadUpdatedAssetsForInstalledApplicationBundle(app);
- if (!_applicationIsInstalledAndRunning(app))
+ if (!await _applicationIsInstalledAndRunning(app))
return _buildAndInstallApplicationBundle(app);
}
@@ -544,7 +541,7 @@
ApplicationPackage app, String localFile, String targetFile) async {
if (platform.isMacOS) {
final String simulatorHomeDirectory = _getSimulatorAppHomeDirectory(app);
- runCheckedSync(<String>['cp', localFile, fs.path.join(simulatorHomeDirectory, targetFile)]);
+ await runCheckedAsync(<String>['cp', localFile, fs.path.join(simulatorHomeDirectory, targetFile)]);
return true;
}
return false;
@@ -555,10 +552,10 @@
}
@override
- TargetPlatform get targetPlatform => TargetPlatform.ios;
+ Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;
@override
- String get sdkNameAndVersion => category;
+ Future<String> get sdkNameAndVersion async => category;
@override
DeviceLogReader getLogReader({ApplicationPackage app}) {
@@ -595,8 +592,7 @@
@override
Future<Null> takeScreenshot(File outputFile) {
- SimControl.instance.takeScreenshot(outputFile.path);
- return new Future<Null>.value();
+ return SimControl.instance.takeScreenshot(outputFile.path);
}
}
diff --git a/packages/flutter_tools/lib/src/run_cold.dart b/packages/flutter_tools/lib/src/run_cold.dart
index d114a7f..0a7b671 100644
--- a/packages/flutter_tools/lib/src/run_cold.dart
+++ b/packages/flutter_tools/lib/src/run_cold.dart
@@ -61,11 +61,12 @@
printStatus('Launching ${getDisplayPath(mainPath)} on ${device.name} in $modeName mode...');
}
- package = getApplicationPackageForPlatform(device.targetPlatform, applicationBinary: applicationBinary);
+ final TargetPlatform targetPlatform = await device.targetPlatform;
+ package = getApplicationPackageForPlatform(targetPlatform, applicationBinary: applicationBinary);
if (package == null) {
- String message = 'No application found for ${device.targetPlatform}.';
- final String hint = getMissingPackageHintForPlatform(device.targetPlatform);
+ String message = 'No application found for $targetPlatform.';
+ final String hint = getMissingPackageHintForPlatform(targetPlatform);
if (hint != null)
message += '\n$hint';
printError(message);
diff --git a/packages/flutter_tools/lib/src/run_hot.dart b/packages/flutter_tools/lib/src/run_hot.dart
index 823ff7e..3b05d16 100644
--- a/packages/flutter_tools/lib/src/run_hot.dart
+++ b/packages/flutter_tools/lib/src/run_hot.dart
@@ -177,11 +177,12 @@
final String modeName = getModeName(debuggingOptions.buildMode);
printStatus('Launching ${getDisplayPath(mainPath)} on ${device.name} in $modeName mode...');
- package = getApplicationPackageForPlatform(device.targetPlatform, applicationBinary: applicationBinary);
+ final TargetPlatform targetPlatform = await device.targetPlatform;
+ package = getApplicationPackageForPlatform(targetPlatform, applicationBinary: applicationBinary);
if (package == null) {
- String message = 'No application found for ${device.targetPlatform}.';
- final String hint = getMissingPackageHintForPlatform(device.targetPlatform);
+ String message = 'No application found for $targetPlatform.';
+ final String hint = getMissingPackageHintForPlatform(targetPlatform);
if (hint != null)
message += '\n$hint';
printError(message);
diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart
index 9485618..3fd1e0f 100644
--- a/packages/flutter_tools/lib/src/runner/flutter_command.dart
+++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart
@@ -102,7 +102,7 @@
/// The path to send to Google Analytics. Return `null` here to disable
/// tracking of the command.
- String get usagePath => name;
+ Future<String> get usagePath async => name;
/// Runs this command.
///
@@ -144,9 +144,9 @@
setupApplicationPackages();
- final String commandPath = usagePath;
+ final String commandPath = await usagePath;
if (commandPath != null)
- flutterUsage.sendCommand(usagePath);
+ flutterUsage.sendCommand(commandPath);
await runCommand();
}
@@ -158,14 +158,14 @@
/// devices and criteria entered by the user on the command line.
/// If a device cannot be found that meets specified criteria,
/// then print an error message and return `null`.
- Future<Device> findTargetDevice({bool androidOnly: false}) async {
+ Future<Device> findTargetDevice() async {
if (!doctor.canLaunchAnything) {
printError("Unable to locate a development device; please run 'flutter doctor' "
"for information about installing additional components.");
return null;
}
- List<Device> devices = await deviceManager.getDevices();
+ List<Device> devices = await deviceManager.getDevices().toList();
if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) {
printStatus("No devices found with name or id "
@@ -178,9 +178,6 @@
devices = devices.where((Device device) => device.isSupported()).toList();
- if (androidOnly)
- devices = devices.where((Device device) => device.targetPlatform == TargetPlatform.android_arm).toList();
-
if (devices.isEmpty) {
printStatus('No supported devices connected.');
return null;
@@ -191,10 +188,10 @@
} else {
printStatus("More than one device connected; please specify a device with "
"the '-d <deviceId>' flag.");
- devices = await deviceManager.getAllConnectedDevices();
+ devices = await deviceManager.getAllConnectedDevices().toList();
}
printStatus('');
- Device.printDevices(devices);
+ await Device.printDevices(devices);
return null;
}
return devices.single;
diff --git a/packages/flutter_tools/lib/src/usage.dart b/packages/flutter_tools/lib/src/usage.dart
index 4f72326..bad768d 100644
--- a/packages/flutter_tools/lib/src/usage.dart
+++ b/packages/flutter_tools/lib/src/usage.dart
@@ -4,6 +4,7 @@
import 'dart:async';
+import 'package:meta/meta.dart';
import 'package:usage/usage_io.dart';
import 'base/context.dart';
@@ -96,7 +97,8 @@
_analytics.sendException('${exception.runtimeType}\n${sanitizeStacktrace(trace)}');
}
- /// Fires whenever analytics data is sent over the network; public for testing.
+ /// Fires whenever analytics data is sent over the network.
+ @visibleForTesting
Stream<Map<String, dynamic>> get onSend => _analytics.onSend;
/// Returns when the last analytics event has been sent, or after a fixed
diff --git a/packages/flutter_tools/lib/src/zip.dart b/packages/flutter_tools/lib/src/zip.dart
index a7b1161..f4107f0 100644
--- a/packages/flutter_tools/lib/src/zip.dart
+++ b/packages/flutter_tools/lib/src/zip.dart
@@ -86,7 +86,7 @@
final Iterable<String> compressedNames = _getCompressedNames();
if (compressedNames.isNotEmpty) {
- runCheckedSync(
+ await runCheckedAsync(
<String>['zip', '-q', outFile.absolute.path]..addAll(compressedNames),
workingDirectory: zipBuildDir.path
);
@@ -94,7 +94,7 @@
final Iterable<String> storedNames = _getStoredNames();
if (storedNames.isNotEmpty) {
- runCheckedSync(
+ await runCheckedAsync(
<String>['zip', '-q', '-0', outFile.absolute.path]..addAll(storedNames),
workingDirectory: zipBuildDir.path
);
diff --git a/packages/flutter_tools/test/analytics_test.dart b/packages/flutter_tools/test/analytics_test.dart
index 26f9f63..5619f97 100644
--- a/packages/flutter_tools/test/analytics_test.dart
+++ b/packages/flutter_tools/test/analytics_test.dart
@@ -56,7 +56,7 @@
Usage: () => new Usage(),
});
- // Ensure we con't send for the 'flutter config' command.
+ // Ensure we don't send for the 'flutter config' command.
testUsingContext('config doesn\'t send', () async {
int count = 0;
flutterUsage.onSend.listen((Map<String, dynamic> data) => count++);
diff --git a/packages/flutter_tools/test/device_test.dart b/packages/flutter_tools/test/device_test.dart
index f16d2e4..7f26d4a 100644
--- a/packages/flutter_tools/test/device_test.dart
+++ b/packages/flutter_tools/test/device_test.dart
@@ -14,7 +14,7 @@
testUsingContext('getDevices', () async {
// Test that DeviceManager.getDevices() doesn't throw.
final DeviceManager deviceManager = new DeviceManager();
- final List<Device> devices = await deviceManager.getDevices();
+ final List<Device> devices = await deviceManager.getDevices().toList();
expect(devices, isList);
});
@@ -26,7 +26,7 @@
final DeviceManager deviceManager = new TestDeviceManager(devices);
Future<Null> expectDevice(String id, List<Device> expected) async {
- expect(await deviceManager.getDevicesById(id), expected);
+ expect(await deviceManager.getDevicesById(id).toList(), expected);
}
expectDevice('01abfc49119c410e', <Device>[device2]);
expectDevice('Nexus 5X', <Device>[device2]);
@@ -44,8 +44,8 @@
TestDeviceManager(this.allDevices);
@override
- Future<List<Device>> getAllConnectedDevices() async {
- return allDevices;
+ Stream<Device> getAllConnectedDevices() {
+ return new Stream<Device>.fromIterable(allDevices);
}
}
diff --git a/packages/flutter_tools/test/src/context.dart b/packages/flutter_tools/test/src/context.dart
index 97fbd03..42bf7eb 100644
--- a/packages/flutter_tools/test/src/context.dart
+++ b/packages/flutter_tools/test/src/context.dart
@@ -134,20 +134,19 @@
bool get hasSpecifiedDeviceId => specifiedDeviceId != null;
@override
- Future<List<Device>> getAllConnectedDevices() => new Future<List<Device>>.value(devices);
+ Stream<Device> getAllConnectedDevices() => new Stream<Device>.fromIterable(devices);
@override
- Future<List<Device>> getDevicesById(String deviceId) async {
- return devices.where((Device device) => device.id == deviceId).toList();
+ Stream<Device> getDevicesById(String deviceId) {
+ return new Stream<Device>.fromIterable(
+ devices.where((Device device) => device.id == deviceId));
}
@override
- Future<List<Device>> getDevices() async {
- if (specifiedDeviceId == null) {
- return getAllConnectedDevices();
- } else {
- return getDevicesById(specifiedDeviceId);
- }
+ Stream<Device> getDevices() {
+ return hasSpecifiedDeviceId
+ ? getDevicesById(specifiedDeviceId)
+ : getAllConnectedDevices();
}
void addDevice(Device device) => devices.add(device);
diff --git a/packages/flutter_tools/test/src/ios/devices_test.dart b/packages/flutter_tools/test/src/ios/devices_test.dart
index 37a280d..20f9723 100644
--- a/packages/flutter_tools/test/src/ios/devices_test.dart
+++ b/packages/flutter_tools/test/src/ios/devices_test.dart
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'dart:async';
import 'dart:io' show ProcessResult;
import 'package:file/file.dart';
@@ -38,23 +39,23 @@
// Let everything else return exit code 0 so process.dart doesn't crash.
// The matcher order is important.
when(
- mockProcessManager.runSync(any, environment: null, workingDirectory: null)
+ mockProcessManager.run(any, environment: null, workingDirectory: null)
).thenReturn(
- new ProcessResult(2, 0, '', null)
+ new Future<ProcessResult>.value(new ProcessResult(2, 0, '', ''))
);
// Let `which idevicescreenshot` fail with exit code 1.
when(
mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null)
).thenReturn(
- new ProcessResult(1, 1, '', null)
+ new ProcessResult(1, 1, '', '')
);
iosDeviceUnderTest = new IOSDevice('1234');
- iosDeviceUnderTest.takeScreenshot(mockOutputFile);
+ await iosDeviceUnderTest.takeScreenshot(mockOutputFile);
verify(mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null));
- verifyNever(mockProcessManager.runSync(
+ verifyNever(mockProcessManager.run(
<String>['idevicescreenshot', fs.path.join('some', 'test', 'path', 'image.png')],
environment: null,
workingDirectory: null
@@ -74,23 +75,23 @@
// Let everything else return exit code 0.
// The matcher order is important.
when(
- mockProcessManager.runSync(any, environment: null, workingDirectory: null)
+ mockProcessManager.run(any, environment: null, workingDirectory: null)
).thenReturn(
- new ProcessResult(4, 0, '', null)
+ new Future<ProcessResult>.value(new ProcessResult(4, 0, '', ''))
);
// Let there be idevicescreenshot in the PATH.
when(
mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null)
).thenReturn(
- new ProcessResult(3, 0, fs.path.join('some', 'path', 'to', 'iscreenshot'), null)
+ new ProcessResult(3, 0, fs.path.join('some', 'path', 'to', 'iscreenshot'), '')
);
iosDeviceUnderTest = new IOSDevice('1234');
- iosDeviceUnderTest.takeScreenshot(mockOutputFile);
+ await iosDeviceUnderTest.takeScreenshot(mockOutputFile);
verify(mockProcessManager.runSync(
<String>['which', 'idevicescreenshot'], environment: null, workingDirectory: null));
- verify(mockProcessManager.runSync(
+ verify(mockProcessManager.run(
<String>[
fs.path.join('some', 'path', 'to', 'iscreenshot'),
fs.path.join('some', 'test', 'path', 'image.png')
diff --git a/packages/flutter_tools/test/src/ios/simulators_test.dart b/packages/flutter_tools/test/src/ios/simulators_test.dart
index 610c9e8..a731197 100644
--- a/packages/flutter_tools/test/src/ios/simulators_test.dart
+++ b/packages/flutter_tools/test/src/ios/simulators_test.dart
@@ -1,3 +1,4 @@
+import 'dart:async';
import 'dart:io' show ProcessResult;
import 'package:file/file.dart';
@@ -128,9 +129,9 @@
mockProcessManager = new MockProcessManager();
// Let everything else return exit code 0 so process.dart doesn't crash.
when(
- mockProcessManager.runSync(any, environment: null, workingDirectory: null)
+ mockProcessManager.run(any, environment: null, workingDirectory: null)
).thenReturn(
- new ProcessResult(2, 0, '', null)
+ new Future<ProcessResult>.value(new ProcessResult(2, 0, '', ''))
);
// Doesn't matter what the device is.
deviceUnderTest = new IOSSimulator('x', name: 'iPhone SE');
@@ -148,14 +149,14 @@
testUsingContext(
'Xcode 8.2+ supports screenshots',
- () {
+ () async {
when(mockXcode.xcodeMajorVersion).thenReturn(8);
when(mockXcode.xcodeMinorVersion).thenReturn(2);
expect(deviceUnderTest.supportsScreenshot, true);
final MockFile mockFile = new MockFile();
when(mockFile.path).thenReturn(fs.path.join('some', 'path', 'to', 'screenshot.png'));
- deviceUnderTest.takeScreenshot(mockFile);
- verify(mockProcessManager.runSync(
+ await deviceUnderTest.takeScreenshot(mockFile);
+ verify(mockProcessManager.run(
<String>[
'/usr/bin/xcrun',
'simctl',
diff --git a/packages/flutter_tools/test/src/mocks.dart b/packages/flutter_tools/test/src/mocks.dart
index 3fbc21d..6bd31ef 100644
--- a/packages/flutter_tools/test/src/mocks.dart
+++ b/packages/flutter_tools/test/src/mocks.dart
@@ -31,7 +31,7 @@
class MockAndroidDevice extends Mock implements AndroidDevice {
@override
- TargetPlatform get targetPlatform => TargetPlatform.android_arm;
+ Future<TargetPlatform> get targetPlatform async => TargetPlatform.android_arm;
@override
bool isSupported() => true;
@@ -39,7 +39,7 @@
class MockIOSDevice extends Mock implements IOSDevice {
@override
- TargetPlatform get targetPlatform => TargetPlatform.ios;
+ Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;
@override
bool isSupported() => true;
@@ -47,7 +47,7 @@
class MockIOSSimulator extends Mock implements IOSSimulator {
@override
- TargetPlatform get targetPlatform => TargetPlatform.ios;
+ Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;
@override
bool isSupported() => true;