Detect exact device ID matches quickly (#62070)
diff --git a/packages/flutter_tools/lib/src/device.dart b/packages/flutter_tools/lib/src/device.dart index 1130db6..1723582 100644 --- a/packages/flutter_tools/lib/src/device.dart +++ b/packages/flutter_tools/lib/src/device.dart
@@ -104,23 +104,51 @@ bool get hasSpecifiedAllDevices => _specifiedDeviceId == 'all'; Future<List<Device>> getDevicesById(String deviceId) async { - final List<Device> devices = await getAllConnectedDevices(); - deviceId = deviceId.toLowerCase(); + final String lowerDeviceId = deviceId.toLowerCase(); bool exactlyMatchesDeviceId(Device device) => - device.id.toLowerCase() == deviceId || - device.name.toLowerCase() == deviceId; + device.id.toLowerCase() == lowerDeviceId || + device.name.toLowerCase() == lowerDeviceId; bool startsWithDeviceId(Device device) => - device.id.toLowerCase().startsWith(deviceId) || - device.name.toLowerCase().startsWith(deviceId); + device.id.toLowerCase().startsWith(lowerDeviceId) || + device.name.toLowerCase().startsWith(lowerDeviceId); - final Device exactMatch = devices.firstWhere( - exactlyMatchesDeviceId, orElse: () => null); - if (exactMatch != null) { - return <Device>[exactMatch]; + // Some discoverers have hard-coded device IDs and return quickly, and others + // shell out to other processes and can take longer. + // Process discoverers as they can return results, so if an exact match is + // found quickly, we don't wait for all the discoverers to complete. + final List<Device> prefixMatches = <Device>[]; + final Completer<Device> exactMatchCompleter = Completer<Device>(); + final List<Future<List<Device>>> futureDevices = <Future<List<Device>>>[ + for (final DeviceDiscovery discoverer in _platformDiscoverers) + discoverer + .devices + .then((List<Device> devices) { + for (final Device device in devices) { + if (exactlyMatchesDeviceId(device)) { + exactMatchCompleter.complete(device); + return null; + } + if (startsWithDeviceId(device)) { + prefixMatches.add(device); + } + } + return null; + }, onError: (dynamic error, StackTrace stackTrace) { + // Return matches from other discoverers even if one fails. + globals.printTrace('Ignored error discovering $deviceId: $error'); + }) + ]; + + // Wait for an exact match, or for all discoverers to return results. + await Future.any<dynamic>(<Future<dynamic>>[ + exactMatchCompleter.future, + Future.wait<List<Device>>(futureDevices), + ]); + + if (exactMatchCompleter.isCompleted) { + return <Device>[await exactMatchCompleter.future]; } - - // Match on a id or name starting with [deviceId]. - return devices.where(startsWithDeviceId).toList(); + return prefixMatches; } /// Returns the list of connected devices, filtered by any user-specified device id.