Add timeout flag to devices command, pipe through discovery (#51678)

This commit is contained in:
Jenn Magder 2020-03-16 14:15:00 -07:00 committed by GitHub
parent 0a09b78297
commit 2f216ceee5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
23 changed files with 251 additions and 52 deletions

View file

@ -62,7 +62,7 @@ class AndroidDevices extends PollingDeviceDiscovery {
bool get canListAnything => androidWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices() async => getAdbDevices();
Future<List<Device>> pollingGetDevices({ Duration timeout }) async => getAdbDevices();
@override
Future<List<String>> getDiagnostics() async => getAdbDeviceDiagnostics();

View file

@ -12,12 +12,36 @@ import '../globals.dart' as globals;
import '../runner/flutter_command.dart';
class DevicesCommand extends FlutterCommand {
DevicesCommand() {
argParser.addOption(
'timeout',
abbr: 't',
defaultsTo: null,
help: 'Time in seconds to wait for devices to attach. Longer timeouts may be necessary for networked devices.'
);
}
@override
final String name = 'devices';
@override
final String description = 'List all connected devices.';
Duration get timeout {
if (argResults['timeout'] == null) {
return null;
}
if (_timeout == null) {
final int timeoutSeconds = int.tryParse(stringArg('timeout'));
if (timeoutSeconds == null) {
throwToolExit( 'Could not parse -t/--timeout argument. It must be an integer.');
}
_timeout = Duration(seconds: timeoutSeconds);
}
return _timeout;
}
Duration _timeout;
@override
Future<FlutterCommandResult> runCommand() async {
if (!doctor.canListAnything) {
@ -27,14 +51,21 @@ class DevicesCommand extends FlutterCommand {
exitCode: 1);
}
final List<Device> devices = await deviceManager.getAllConnectedDevices();
final List<Device> devices = await deviceManager.refreshAllConnectedDevices(timeout: timeout);
if (devices.isEmpty) {
globals.printStatus(
'No devices detected.\n\n'
"Run 'flutter emulators' to list and start any available device emulators.\n\n"
'Or, if you expected your device to be detected, please run "flutter doctor" to diagnose '
'potential issues, or visit https://flutter.dev/setup/ for troubleshooting tips.');
final StringBuffer status = StringBuffer('No devices detected.');
status.writeln();
status.writeln();
status.writeln('Run "flutter emulators" to list and start any available device emulators.');
status.writeln();
status.write('If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues. ');
if (timeout == null) {
status.write('You may also try increasing the time to wait for connected devices with the --timeout flag. ');
}
status.write('Visit https://flutter.dev/setup/ for troubleshooting tips.');
globals.printStatus(status.toString());
final List<String> diagnostics = await deviceManager.getDeviceDiagnostics();
if (diagnostics.isNotEmpty) {
globals.printStatus('');

View file

@ -124,7 +124,7 @@ class DeviceManager {
return devices.where(startsWithDeviceId).toList();
}
/// Return the list of connected devices, filtered by any user-specified device id.
/// Returns the list of connected devices, filtered by any user-specified device id.
Future<List<Device>> getDevices() {
return hasSpecifiedDeviceId
? getDevicesById(specifiedDeviceId)
@ -135,7 +135,7 @@ class DeviceManager {
return deviceDiscoverers.where((DeviceDiscovery discoverer) => discoverer.supportsPlatform);
}
/// Return the list of all connected devices.
/// Returns the list of all connected devices.
Future<List<Device>> getAllConnectedDevices() async {
final List<List<Device>> devices = await Future.wait<List<Device>>(<Future<List<Device>>>[
for (final DeviceDiscovery discoverer in _platformDiscoverers)
@ -145,6 +145,16 @@ class DeviceManager {
return devices.expand<Device>((List<Device> deviceList) => deviceList).toList();
}
/// Returns the list of all connected devices. Discards existing cache of devices.
Future<List<Device>> refreshAllConnectedDevices({ Duration timeout }) async {
final List<List<Device>> devices = await Future.wait<List<Device>>(<Future<List<Device>>>[
for (final DeviceDiscovery discoverer in _platformDiscoverers)
discoverer.discoverDevices(timeout: timeout),
]);
return devices.expand<Device>((List<Device> deviceList) => deviceList).toList();
}
/// Whether we're capable of listing any devices given the current environment configuration.
bool get canListAnything {
return _platformDiscoverers.any((DeviceDiscovery discoverer) => discoverer.canListAnything);
@ -237,8 +247,12 @@ abstract class DeviceDiscovery {
/// current environment configuration.
bool get canListAnything;
/// Return all connected devices, cached on subsequent calls.
Future<List<Device>> get devices;
/// Return all connected devices. Discards existing cache of devices.
Future<List<Device>> discoverDevices({ Duration timeout });
/// Gets a list of diagnostic messages pertaining to issues with any connected
/// devices (will be an empty list if there are no issues).
Future<List<String>> getDiagnostics() => Future<List<String>>.value(<String>[]);
@ -256,7 +270,7 @@ abstract class PollingDeviceDiscovery extends DeviceDiscovery {
ItemListNotifier<Device> _items;
Timer _timer;
Future<List<Device>> pollingGetDevices();
Future<List<Device>> pollingGetDevices({ Duration timeout });
void startPolling() {
if (_timer == null) {
@ -268,7 +282,7 @@ abstract class PollingDeviceDiscovery extends DeviceDiscovery {
Timer _initTimer() {
return Timer(_pollingInterval, () async {
try {
final List<Device> devices = await pollingGetDevices().timeout(_pollingTimeout);
final List<Device> devices = await pollingGetDevices(timeout: _pollingTimeout);
_items.updateWithNewList(devices);
} on TimeoutException {
globals.printTrace('Device poll timed out. Will retry.');
@ -284,7 +298,17 @@ abstract class PollingDeviceDiscovery extends DeviceDiscovery {
@override
Future<List<Device>> get devices async {
_items ??= ItemListNotifier<Device>.from(await pollingGetDevices());
return _populateDevices();
}
@override
Future<List<Device>> discoverDevices({ Duration timeout }) async {
_items = null;
return _populateDevices(timeout: timeout);
}
Future<List<Device>> _populateDevices({ Duration timeout }) async {
_items ??= ItemListNotifier<Device>.from(await pollingGetDevices(timeout: timeout));
return _items.items;
}

View file

@ -22,7 +22,7 @@ class FuchsiaDevFinder {
/// Returns a list of attached devices as a list of strings with entries
/// formatted as follows:
/// 192.168.42.172 scare-cable-skip-joy
Future<List<String>> list() async {
Future<List<String>> list({ Duration timeout }) async {
if (fuchsiaArtifacts.devFinder == null ||
!fuchsiaArtifacts.devFinder.existsSync()) {
throwToolExit('Fuchsia device-finder tool not found.');
@ -31,6 +31,8 @@ class FuchsiaDevFinder {
fuchsiaArtifacts.devFinder.path,
'list',
'-full',
if (timeout != null)
...<String>['-timeout', '${timeout.inMilliseconds}ms']
];
final RunResult result = await processUtils.run(command);
if (result.exitCode != 0) {

View file

@ -145,11 +145,11 @@ class FuchsiaDevices extends PollingDeviceDiscovery {
bool get canListAnything => fuchsiaWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices() async {
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
if (!fuchsiaWorkflow.canListDevices) {
return <Device>[];
}
final String text = await fuchsiaSdk.listDevices();
final String text = await fuchsiaSdk.listDevices(timeout: timeout);
if (text == null || text.isEmpty) {
return <Device>[];
}

View file

@ -47,12 +47,12 @@ class FuchsiaSdk {
/// Example output:
/// $ device-finder list -full
/// > 192.168.42.56 paper-pulp-bush-angel
Future<String> listDevices() async {
Future<String> listDevices({ Duration timeout }) async {
if (fuchsiaArtifacts.devFinder == null ||
!fuchsiaArtifacts.devFinder.existsSync()) {
return null;
}
final List<String> devices = await fuchsiaDevFinder.list();
final List<String> devices = await fuchsiaDevFinder.list(timeout: timeout);
if (devices == null) {
return null;
}

View file

@ -38,7 +38,10 @@ class IOSDevices extends PollingDeviceDiscovery {
bool get canListAnything => globals.iosWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices() => IOSDevice.getAttachedDevices(globals.platform, globals.xcdevice);
Future<List<Device>> pollingGetDevices({ Duration timeout }) {
return IOSDevice.getAttachedDevices(
globals.platform, globals.xcdevice, timeout: timeout);
}
@override
Future<List<String>> getDiagnostics() => IOSDevice.getDiagnostics(globals.platform, globals.xcdevice);
@ -109,12 +112,12 @@ class IOSDevice extends Device {
@override
bool get supportsStartPaused => false;
static Future<List<IOSDevice>> getAttachedDevices(Platform platform, XCDevice xcdevice) async {
static Future<List<IOSDevice>> getAttachedDevices(Platform platform, XCDevice xcdevice, { Duration timeout }) async {
if (!platform.isMacOS) {
throw UnsupportedError('Control of iOS devices or simulators only supported on macOS.');
}
return await xcdevice.getAvailableTetheredIOSDevices();
return await xcdevice.getAvailableTetheredIOSDevices(timeout: timeout);
}
static Future<List<String>> getDiagnostics(Platform platform, XCDevice xcdevice) async {

View file

@ -43,7 +43,7 @@ class IOSSimulators extends PollingDeviceDiscovery {
bool get canListAnything => globals.iosWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices() async => _iosSimulatorUtils.getAttachedDevices();
Future<List<Device>> pollingGetDevices({ Duration timeout }) async => _iosSimulatorUtils.getAttachedDevices();
}
class IOSSimulatorUtils {

View file

@ -76,7 +76,7 @@ class LinuxDevices extends PollingDeviceDiscovery {
bool get canListAnything => _linuxWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices() async {
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
if (!canListAnything) {
return const <Device>[];
}

View file

@ -78,7 +78,7 @@ class MacOSDevices extends PollingDeviceDiscovery {
bool get canListAnything => macOSWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices() async {
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
if (!canListAnything) {
return const <Device>[];
}

View file

@ -228,7 +228,10 @@ class XCDevice {
return _xcdevicePath;
}
Future<List<dynamic>> _getAllDevices({bool useCache = false}) async {
Future<List<dynamic>> _getAllDevices({
bool useCache = false,
@required Duration timeout
}) async {
if (!isInstalled) {
_logger.printTrace("Xcode not found. Run 'flutter doctor' for more information.");
return null;
@ -244,7 +247,7 @@ class XCDevice {
'xcdevice',
'list',
'--timeout',
'1',
timeout.inSeconds.toString(),
],
throwOnError: true,
);
@ -265,9 +268,9 @@ class XCDevice {
List<dynamic> _cachedListResults;
/// List of devices available over USB.
Future<List<IOSDevice>> getAvailableTetheredIOSDevices() async {
final List<dynamic> allAvailableDevices = await _getAllDevices();
/// [timeout] defaults to 1 second.
Future<List<IOSDevice>> getAvailableTetheredIOSDevices({ Duration timeout }) async {
final List<dynamic> allAvailableDevices = await _getAllDevices(timeout: timeout ?? const Duration(seconds: 1));
if (allAvailableDevices == null) {
return const <IOSDevice>[];
@ -501,7 +504,10 @@ class XCDevice {
/// List of all devices reporting errors.
Future<List<String>> getDiagnostics() async {
final List<dynamic> allAvailableDevices = await _getAllDevices(useCache: true);
final List<dynamic> allAvailableDevices = await _getAllDevices(
useCache: true,
timeout: const Duration(seconds: 1)
);
if (allAvailableDevices == null) {
return const <String>[];

View file

@ -246,7 +246,7 @@ class FlutterTesterDevices extends PollingDeviceDiscovery {
bool get supportsPlatform => true;
@override
Future<List<Device>> pollingGetDevices() async {
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
return showFlutterTesterDevice ? <Device>[_testerDevice] : <Device>[];
}
}

View file

@ -185,7 +185,7 @@ class WebDevices extends PollingDeviceDiscovery {
bool get canListAnything => featureFlags.isWebEnabled;
@override
Future<List<Device>> pollingGetDevices() async {
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
return <Device>[
if (_chromeIsAvailable)
_webDevice,

View file

@ -66,7 +66,7 @@ class WindowsDevices extends PollingDeviceDiscovery {
bool get canListAnything => windowsWorkflow.canListDevices;
@override
Future<List<Device>> pollingGetDevices() async {
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
if (!canListAnything) {
return const <Device>[];
}

View file

@ -12,6 +12,7 @@ import 'package:mockito/mockito.dart';
import '../src/common.dart';
import '../src/context.dart';
import '../src/mocks.dart';
void main() {
group('DeviceManager', () {
@ -39,6 +40,26 @@ void main() {
await expectDevice('0553790', <Device>[device1]);
await expectDevice('Nexus', <Device>[device1, device2]);
});
testUsingContext('getAllConnectedDevices caches', () async {
final _MockDevice device1 = _MockDevice('Nexus 5', '0553790d0a4e726f');
final TestDeviceManager deviceManager = TestDeviceManager(<Device>[device1]);
expect(await deviceManager.getAllConnectedDevices(), <Device>[device1]);
final _MockDevice device2 = _MockDevice('Nexus 5X', '01abfc49119c410e');
deviceManager.resetDevices(<Device>[device2]);
expect(await deviceManager.getAllConnectedDevices(), <Device>[device1]);
});
testUsingContext('refreshAllConnectedDevices does not cache', () async {
final _MockDevice device1 = _MockDevice('Nexus 5', '0553790d0a4e726f');
final TestDeviceManager deviceManager = TestDeviceManager(<Device>[device1]);
expect(await deviceManager.refreshAllConnectedDevices(), <Device>[device1]);
final _MockDevice device2 = _MockDevice('Nexus 5X', '01abfc49119c410e');
deviceManager.resetDevices(<Device>[device2]);
expect(await deviceManager.refreshAllConnectedDevices(), <Device>[device2]);
});
});
group('Filter devices', () {
@ -164,13 +185,19 @@ void main() {
}
class TestDeviceManager extends DeviceManager {
TestDeviceManager(this.allDevices);
final List<Device> allDevices;
bool isAlwaysSupportedOverride;
TestDeviceManager(List<Device> allDevices) {
_deviceDiscoverer = MockPollingDeviceDiscovery();
resetDevices(allDevices);
}
@override
Future<List<Device>> getAllConnectedDevices() async => allDevices;
List<DeviceDiscovery> get deviceDiscoverers => <DeviceDiscovery>[_deviceDiscoverer];
MockPollingDeviceDiscovery _deviceDiscoverer;
void resetDevices(List<Device> allDevices) {
_deviceDiscoverer.setDevices(allDevices);
}
bool isAlwaysSupportedOverride;
@override
bool isDeviceSupportedForProject(Device device, FlutterProject flutterProject) {

View file

@ -1344,7 +1344,7 @@ class FailingKernelCompiler implements FuchsiaKernelCompiler {
class FakeFuchsiaDevFinder implements FuchsiaDevFinder {
@override
Future<List<String>> list() async {
Future<List<String>> list({ Duration timeout }) async {
return <String>['192.168.42.172 scare-cable-skip-joy'];
}
@ -1356,7 +1356,7 @@ class FakeFuchsiaDevFinder implements FuchsiaDevFinder {
class FailingDevFinder implements FuchsiaDevFinder {
@override
Future<List<String>> list() async {
Future<List<String>> list({ Duration timeout }) async {
return null;
}

View file

@ -5,7 +5,6 @@
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/linux/application_package.dart';
import 'package:flutter_tools/src/linux/linux_device.dart';
import 'package:flutter_tools/src/device.dart';
@ -17,14 +16,17 @@ import 'package:platform/platform.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/testbed.dart';
void main() {
final LinuxDevice device = LinuxDevice();
final MockPlatform notLinux = MockPlatform();
when(notLinux.isLinux).thenReturn(false);
testUsingContext('LinuxDevice defaults', () async {
final MockPlatform mockLinuxPlatform = MockPlatform();
when(mockLinuxPlatform.isLinux).thenReturn(true);
testWithoutContext('LinuxDevice defaults', () async {
final PrebuiltLinuxApp linuxApp = PrebuiltLinuxApp(executable: 'foo');
expect(await device.targetPlatform, TargetPlatform.linux_x64);
expect(device.name, 'Linux');
@ -36,13 +38,36 @@ void main() {
expect(device.category, Category.desktop);
});
testUsingContext('LinuxDevice: no devices listed if platform unsupported', () async {
testWithoutContext('LinuxDevice: no devices listed if platform unsupported', () async {
expect(await LinuxDevices(
platform: notLinux,
featureFlags: featureFlags,
featureFlags: TestFeatureFlags(isLinuxEnabled: true),
).devices, <Device>[]);
});
testWithoutContext('LinuxDevice: no devices listed if Linux feature flag disabled', () async {
expect(await LinuxDevices(
platform: mockLinuxPlatform,
featureFlags: TestFeatureFlags(isLinuxEnabled: false),
).devices, <Device>[]);
});
testWithoutContext('LinuxDevice: devices', () async {
expect(await LinuxDevices(
platform: mockLinuxPlatform,
featureFlags: TestFeatureFlags(isLinuxEnabled: true),
).devices, hasLength(1));
});
testWithoutContext('LinuxDevice: discoverDevices', () async {
// Timeout ignored.
final List<Device> devices = await LinuxDevices(
platform: mockLinuxPlatform,
featureFlags: TestFeatureFlags(isLinuxEnabled: true),
).discoverDevices(timeout: const Duration(seconds: 10));
expect(devices, hasLength(1));
});
testUsingContext('LinuxDevice.isSupportedForProject is true with editable host app', () async {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();

View file

@ -13,20 +13,27 @@ import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/base/io.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/device.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/macos/application_package.dart';
import 'package:flutter_tools/src/macos/macos_device.dart';
import 'package:flutter_tools/src/globals.dart' as globals;
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/testbed.dart';
void main() {
group(MacOSDevice, () {
final MockPlatform notMac = MockPlatform();
final MacOSDevice device = MacOSDevice();
final MockProcessManager mockProcessManager = MockProcessManager();
final MockPlatform notMac = MockPlatform();
when(notMac.isMacOS).thenReturn(false);
when(notMac.environment).thenReturn(const <String, String>{});
final MockPlatform mockMacPlatform = MockPlatform();
when(mockMacPlatform.isMacOS).thenReturn(true);
when(mockProcessManager.run(any)).thenAnswer((Invocation invocation) async {
return ProcessResult(0, 1, '', '');
});
@ -48,6 +55,22 @@ void main() {
Platform: () => notMac,
});
testUsingContext('devices', () async {
expect(await MacOSDevices().devices, hasLength(1));
}, overrides: <Type, Generator>{
Platform: () => mockMacPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
testUsingContext('discoverDevices', () async {
// Timeout ignored.
final List<Device> devices = await MacOSDevices().discoverDevices(timeout: const Duration(seconds: 10));
expect(devices, hasLength(1));
}, overrides: <Type, Generator>{
Platform: () => mockMacPlatform,
FeatureFlags: () => TestFeatureFlags(isMacOSEnabled: true),
});
testUsingContext('isSupportedForProject is true with editable host app', () async {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();

View file

@ -359,6 +359,18 @@ void main() {
Platform: () => macPlatform,
});
testWithoutContext('uses timeout', () async {
when(mockXcode.isInstalledAndMeetsVersionCheck).thenReturn(true);
when(processManager.runSync(<String>['xcrun', '--find', 'xcdevice']))
.thenReturn(ProcessResult(1, 0, '/path/to/xcdevice', ''));
when(processManager.run(any))
.thenAnswer((_) => Future<ProcessResult>.value(ProcessResult(1, 0, '[]', '')));
await xcdevice.getAvailableTetheredIOSDevices(timeout: const Duration(seconds: 20));
verify(processManager.run(<String>['xcrun', 'xcdevice', 'list', '--timeout', '20'])).called(1);
});
testUsingContext('ignores "Preparing debugger support for iPhone" error', () async {
when(mockXcode.isInstalledAndMeetsVersionCheck).thenReturn(true);

View file

@ -64,6 +64,15 @@ void main() {
expect(device, isA<FlutterTesterDevice>());
expect(device.id, 'flutter-tester');
});
testUsingContext('discoverDevices', () async {
FlutterTesterDevices.showFlutterTesterDevice = true;
final FlutterTesterDevices discoverer = FlutterTesterDevices();
// Timeout ignored.
final List<Device> devices = await discoverer.discoverDevices(timeout: const Duration(seconds: 10));
expect(devices, hasLength(1));
});
});
group('FlutterTesterDevice', () {

View file

@ -5,6 +5,7 @@
import 'package:file/memory.dart';
import 'package:flutter_tools/src/base/file_system.dart';
import 'package:flutter_tools/src/build_info.dart';
import 'package:flutter_tools/src/features.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/windows/application_package.dart';
import 'package:flutter_tools/src/windows/windows_device.dart';
@ -15,15 +16,19 @@ import 'package:platform/platform.dart';
import '../../src/common.dart';
import '../../src/context.dart';
import '../../src/testbed.dart';
void main() {
group(WindowsDevice, () {
final WindowsDevice device = WindowsDevice();
final MockPlatform notWindows = MockPlatform();
final MockPlatform notWindows = MockPlatform();
when(notWindows.isWindows).thenReturn(false);
when(notWindows.environment).thenReturn(const <String, String>{});
final MockPlatform mockWindowsPlatform = MockPlatform();
when(mockWindowsPlatform.isWindows).thenReturn(true);
testUsingContext('defaults', () async {
final PrebuiltWindowsApp windowsApp = PrebuiltWindowsApp(executable: 'foo');
expect(await device.targetPlatform, TargetPlatform.windows_x64);
@ -41,6 +46,22 @@ void main() {
Platform: () => notWindows,
});
testUsingContext('WindowsDevices: devices', () async {
expect(await WindowsDevices().devices, hasLength(1));
}, overrides: <Type, Generator>{
Platform: () => mockWindowsPlatform,
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
});
testUsingContext('WindowsDevices: discoverDevices', () async {
// Timeout ignored.
final List<Device> devices = await WindowsDevices().discoverDevices(timeout: const Duration(seconds: 10));
expect(devices, hasLength(1));
}, overrides: <Type, Generator>{
Platform: () => mockWindowsPlatform,
FeatureFlags: () => TestFeatureFlags(isWindowsEnabled: true),
});
testUsingContext('isSupportedForProject is true with editable host app', () async {
globals.fs.file('pubspec.yaml').createSync();
globals.fs.file('.packages').createSync();

View file

@ -218,6 +218,9 @@ class FakeDeviceManager implements DeviceManager {
@override
Future<List<Device>> getAllConnectedDevices() async => devices;
@override
Future<List<Device>> refreshAllConnectedDevices({ Duration timeout }) async => devices;
@override
Future<List<Device>> getDevicesById(String deviceId) async {
return devices.where((Device device) => device.id == deviceId).toList();

View file

@ -526,7 +526,12 @@ class MockPollingDeviceDiscovery extends PollingDeviceDiscovery {
final StreamController<Device> _onRemovedController = StreamController<Device>.broadcast();
@override
Future<List<Device>> pollingGetDevices() async => _devices;
Future<List<Device>> pollingGetDevices({ Duration timeout }) async {
lastPollingTimeout = timeout;
return _devices;
}
Duration lastPollingTimeout;
@override
bool get supportsPlatform => true;
@ -534,14 +539,22 @@ class MockPollingDeviceDiscovery extends PollingDeviceDiscovery {
@override
bool get canListAnything => true;
void addDevice(MockAndroidDevice device) {
void addDevice(Device device) {
_devices.add(device);
_onAddedController.add(device);
}
@override
Future<List<Device>> get devices async => _devices;
void _removeDevice(Device device) {
_devices.remove(device);
_onRemovedController.add(device);
}
void setDevices(List<Device> devices) {
while(_devices.isNotEmpty) {
_removeDevice(_devices.first);
}
devices.forEach(addDevice);
}
@override
Stream<Device> get onAdded => _onAddedController.stream;