Separate attached and wireless devices (#122615)
Separate attached and wireless devices
This commit is contained in:
parent
5d10cc28ca
commit
27248d4b64
@ -89,6 +89,14 @@ class AndroidDevice extends Device {
|
||||
final String modelID;
|
||||
final String? deviceCodeName;
|
||||
|
||||
@override
|
||||
// Wirelessly paired Android devices should have `adb-tls-connect` in the id.
|
||||
// Source: https://android.googlesource.com/platform/packages/modules/adb/+/f4ba8d73079b99532069dbe888a58167b8723d6c/adb_mdns.h#30
|
||||
DeviceConnectionInterface get connectionInterface =>
|
||||
id.contains('adb-tls-connect')
|
||||
? DeviceConnectionInterface.wireless
|
||||
: DeviceConnectionInterface.attached;
|
||||
|
||||
late final Future<Map<String, String>> _properties = () async {
|
||||
Map<String, String> properties = <String, String>{};
|
||||
|
||||
|
@ -265,7 +265,7 @@ class UserMessages {
|
||||
'for information about installing additional components.';
|
||||
String flutterNoMatchingDevice(String deviceId) => 'No supported devices found with name or id '
|
||||
"matching '$deviceId'.";
|
||||
String get flutterNoDevicesFound => 'No devices found';
|
||||
String get flutterNoDevicesFound => 'No devices found.';
|
||||
String get flutterNoSupportedDevices => 'No supported devices connected.';
|
||||
String flutterMissPlatformProjects(List<String> unsupportedDevicesType) =>
|
||||
'If you would like your app to run on ${unsupportedDevicesType.join(' or ')}, consider running `flutter create .` to generate projects for these platforms.';
|
||||
|
@ -24,7 +24,6 @@ import '../device.dart';
|
||||
import '../device_port_forwarder.dart';
|
||||
import '../fuchsia/fuchsia_device.dart';
|
||||
import '../ios/devices.dart';
|
||||
import '../ios/iproxy.dart';
|
||||
import '../ios/simulators.dart';
|
||||
import '../macos/macos_ipad_device.dart';
|
||||
import '../mdns_discovery.dart';
|
||||
@ -287,7 +286,7 @@ known, it can be explicitly provided to attach via the command-line, e.g.
|
||||
final String ipv6Loopback = InternetAddress.loopbackIPv6.address;
|
||||
final String ipv4Loopback = InternetAddress.loopbackIPv4.address;
|
||||
final String hostname = usesIpv6 ? ipv6Loopback : ipv4Loopback;
|
||||
final bool isNetworkDevice = (device is IOSDevice) && device.interfaceType == IOSDeviceConnectionInterface.network;
|
||||
final bool isNetworkDevice = (device is IOSDevice) && device.isWirelesslyConnected;
|
||||
|
||||
if ((debugPort == null && debugUri == null) || isNetworkDevice) {
|
||||
if (device is FuchsiaDevice) {
|
||||
|
@ -79,13 +79,59 @@ class DevicesCommandOutput {
|
||||
|
||||
final Duration? deviceDiscoveryTimeout;
|
||||
|
||||
Future<List<Device>> _getAttachedDevices(DeviceManager deviceManager) async {
|
||||
return deviceManager.getAllDevices(
|
||||
filter: DeviceDiscoveryFilter(
|
||||
deviceConnectionInterface: DeviceConnectionInterface.attached,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Device>> _getWirelessDevices(DeviceManager deviceManager) async {
|
||||
return deviceManager.getAllDevices(
|
||||
filter: DeviceDiscoveryFilter(
|
||||
deviceConnectionInterface: DeviceConnectionInterface.wireless,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> findAndOutputAllTargetDevices({required bool machine}) async {
|
||||
final List<Device> devices = await globals.deviceManager?.refreshAllDevices(timeout: deviceDiscoveryTimeout) ?? <Device>[];
|
||||
List<Device> attachedDevices = <Device>[];
|
||||
List<Device> wirelessDevices = <Device>[];
|
||||
final DeviceManager? deviceManager = globals.deviceManager;
|
||||
if (deviceManager != null) {
|
||||
// Refresh the cache and then get the attached and wireless devices from
|
||||
// the cache.
|
||||
await deviceManager.refreshAllDevices(timeout: deviceDiscoveryTimeout);
|
||||
attachedDevices = await _getAttachedDevices(deviceManager);
|
||||
wirelessDevices = await _getWirelessDevices(deviceManager);
|
||||
}
|
||||
final List<Device> allDevices = attachedDevices + wirelessDevices;
|
||||
|
||||
if (machine) {
|
||||
await printDevicesAsJson(devices);
|
||||
await printDevicesAsJson(allDevices);
|
||||
return;
|
||||
}
|
||||
|
||||
if (allDevices.isEmpty) {
|
||||
_printNoDevicesDetected();
|
||||
} else {
|
||||
if (devices.isEmpty) {
|
||||
if (attachedDevices.isNotEmpty) {
|
||||
globals.printStatus('${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:\n');
|
||||
await Device.printDevices(attachedDevices, globals.logger);
|
||||
}
|
||||
if (wirelessDevices.isNotEmpty) {
|
||||
if (attachedDevices.isNotEmpty) {
|
||||
globals.printStatus('');
|
||||
}
|
||||
globals.printStatus('${wirelessDevices.length} wirelessly connected ${pluralize('device', wirelessDevices.length)}:\n');
|
||||
await Device.printDevices(wirelessDevices, globals.logger);
|
||||
}
|
||||
}
|
||||
await _printDiagnostics();
|
||||
}
|
||||
|
||||
void _printNoDevicesDetected() {
|
||||
final StringBuffer status = StringBuffer('No devices detected.');
|
||||
status.writeln();
|
||||
status.writeln();
|
||||
@ -98,12 +144,6 @@ class DevicesCommandOutput {
|
||||
status.write('Visit https://flutter.dev/setup/ for troubleshooting tips.');
|
||||
|
||||
globals.printStatus(status.toString());
|
||||
} else {
|
||||
globals.printStatus('${devices.length} connected ${pluralize('device', devices.length)}:\n');
|
||||
await Device.printDevices(devices, globals.logger);
|
||||
}
|
||||
await _printDiagnostics();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _printDiagnostics() async {
|
||||
|
@ -23,7 +23,6 @@ import '../device.dart';
|
||||
import '../drive/drive_service.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../ios/devices.dart';
|
||||
import '../ios/iproxy.dart';
|
||||
import '../resident_runner.dart';
|
||||
import '../runner/flutter_command.dart' show FlutterCommandCategory, FlutterCommandResult, FlutterOptions;
|
||||
import '../web/web_device.dart';
|
||||
@ -220,7 +219,7 @@ class DriveCommand extends RunCommandBase {
|
||||
Future<bool> get disablePortPublication async {
|
||||
final ArgResults? localArgResults = argResults;
|
||||
final Device? device = await targetedDevice;
|
||||
final bool isNetworkDevice = device is IOSDevice && device.interfaceType == IOSDeviceConnectionInterface.network;
|
||||
final bool isNetworkDevice = device is IOSDevice && device.isWirelesslyConnected;
|
||||
if (isNetworkDevice && localArgResults != null && !localArgResults.wasParsed('publish-port')) {
|
||||
_logger.printTrace('Network device is being used. Changing `publish-port` to be enabled.');
|
||||
return false;
|
||||
|
@ -20,7 +20,6 @@ import '../device.dart';
|
||||
import '../features.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../ios/devices.dart';
|
||||
import '../ios/iproxy.dart';
|
||||
import '../project.dart';
|
||||
import '../reporting/reporting.dart';
|
||||
import '../resident_runner.dart';
|
||||
@ -426,7 +425,7 @@ class RunCommand extends RunCommandBase {
|
||||
final TargetPlatform platform = await device.targetPlatform;
|
||||
anyAndroidDevices = platform == TargetPlatform.android;
|
||||
anyIOSDevices = platform == TargetPlatform.ios;
|
||||
if (device is IOSDevice && device.interfaceType == IOSDeviceConnectionInterface.network) {
|
||||
if (device is IOSDevice && device.isWirelesslyConnected) {
|
||||
anyIOSNetworkDevices = true;
|
||||
}
|
||||
deviceType = getNameForTargetPlatform(platform);
|
||||
@ -440,7 +439,7 @@ class RunCommand extends RunCommandBase {
|
||||
final TargetPlatform platform = await device.targetPlatform;
|
||||
anyAndroidDevices = anyAndroidDevices || (platform == TargetPlatform.android);
|
||||
anyIOSDevices = anyIOSDevices || (platform == TargetPlatform.ios);
|
||||
if (device is IOSDevice && device.interfaceType == IOSDeviceConnectionInterface.network) {
|
||||
if (device is IOSDevice && device.isWirelesslyConnected) {
|
||||
anyIOSNetworkDevices = true;
|
||||
}
|
||||
if (anyAndroidDevices && anyIOSDevices) {
|
||||
|
@ -17,7 +17,6 @@ import 'base/utils.dart';
|
||||
import 'build_info.dart';
|
||||
import 'devfs.dart';
|
||||
import 'device_port_forwarder.dart';
|
||||
import 'ios/iproxy.dart';
|
||||
import 'project.dart';
|
||||
import 'vmservice.dart';
|
||||
|
||||
@ -1098,7 +1097,7 @@ class DebuggingOptions {
|
||||
String? route,
|
||||
Map<String, Object?> platformArgs, {
|
||||
bool ipv6 = false,
|
||||
IOSDeviceConnectionInterface interfaceType = IOSDeviceConnectionInterface.none
|
||||
DeviceConnectionInterface interfaceType = DeviceConnectionInterface.attached,
|
||||
}) {
|
||||
final String dartVmFlags = computeDartVmFlags(this);
|
||||
return <String>[
|
||||
@ -1137,7 +1136,7 @@ class DebuggingOptions {
|
||||
if (environmentType == EnvironmentType.simulator && hostVmServicePort != null)
|
||||
'--vm-service-port=$hostVmServicePort',
|
||||
// Tell the VM service to listen on all interfaces, don't restrict to the loopback.
|
||||
if (interfaceType == IOSDeviceConnectionInterface.network)
|
||||
if (interfaceType == DeviceConnectionInterface.wireless)
|
||||
'--vm-service-host=${ipv6 ? '::0' : '0.0.0.0'}',
|
||||
if (enableEmbedderApi) '--enable-embedder-api',
|
||||
];
|
||||
|
@ -151,7 +151,7 @@ class IOSDevice extends Device {
|
||||
required FileSystem fileSystem,
|
||||
required this.name,
|
||||
required this.cpuArchitecture,
|
||||
required this.interfaceType,
|
||||
required this.connectionInterface,
|
||||
String? sdkVersion,
|
||||
required Platform platform,
|
||||
required IOSDeploy iosDeploy,
|
||||
@ -199,7 +199,8 @@ class IOSDevice extends Device {
|
||||
|
||||
final DarwinArch cpuArchitecture;
|
||||
|
||||
final IOSDeviceConnectionInterface interfaceType;
|
||||
@override
|
||||
final DeviceConnectionInterface connectionInterface;
|
||||
|
||||
final Map<IOSApp?, DeviceLogReader> _logReaders = <IOSApp?, DeviceLogReader>{};
|
||||
|
||||
@ -256,7 +257,7 @@ class IOSDevice extends Device {
|
||||
bundlePath: bundle.path,
|
||||
appDeltaDirectory: app.appDeltaDirectory,
|
||||
launchArguments: <String>[],
|
||||
interfaceType: interfaceType,
|
||||
interfaceType: connectionInterface,
|
||||
);
|
||||
} on ProcessException catch (e) {
|
||||
_logger.printError(e.message);
|
||||
@ -311,7 +312,7 @@ class IOSDevice extends Device {
|
||||
@visibleForTesting Duration? discoveryTimeout,
|
||||
}) async {
|
||||
String? packageId;
|
||||
if (interfaceType == IOSDeviceConnectionInterface.network &&
|
||||
if (isWirelesslyConnected &&
|
||||
debuggingOptions.debuggingEnabled &&
|
||||
debuggingOptions.disablePortPublication) {
|
||||
throwToolExit('Cannot start app on wirelessly tethered iOS device. Try running again with the --publish-port flag');
|
||||
@ -351,7 +352,7 @@ class IOSDevice extends Device {
|
||||
route,
|
||||
platformArgs,
|
||||
ipv6: ipv6,
|
||||
interfaceType: interfaceType,
|
||||
interfaceType: connectionInterface,
|
||||
);
|
||||
Status startAppStatus = _logger.startProgress(
|
||||
'Installing and launching...',
|
||||
@ -371,7 +372,7 @@ class IOSDevice extends Device {
|
||||
bundlePath: bundle.path,
|
||||
appDeltaDirectory: package.appDeltaDirectory,
|
||||
launchArguments: launchArguments,
|
||||
interfaceType: interfaceType,
|
||||
interfaceType: connectionInterface,
|
||||
uninstallFirst: debuggingOptions.uninstallFirst,
|
||||
);
|
||||
if (deviceLogReader is IOSDeviceLogReader) {
|
||||
@ -381,7 +382,7 @@ class IOSDevice extends Device {
|
||||
// Don't port foward if debugging with a network device.
|
||||
vmServiceDiscovery = ProtocolDiscovery.vmService(
|
||||
deviceLogReader,
|
||||
portForwarder: interfaceType == IOSDeviceConnectionInterface.network ? null : portForwarder,
|
||||
portForwarder: isWirelesslyConnected ? null : portForwarder,
|
||||
hostPort: debuggingOptions.hostVmServicePort,
|
||||
devicePort: debuggingOptions.deviceVmServicePort,
|
||||
ipv6: ipv6,
|
||||
@ -394,7 +395,7 @@ class IOSDevice extends Device {
|
||||
bundlePath: bundle.path,
|
||||
appDeltaDirectory: package.appDeltaDirectory,
|
||||
launchArguments: launchArguments,
|
||||
interfaceType: interfaceType,
|
||||
interfaceType: connectionInterface,
|
||||
uninstallFirst: debuggingOptions.uninstallFirst,
|
||||
);
|
||||
} else {
|
||||
@ -414,13 +415,13 @@ class IOSDevice extends Device {
|
||||
|
||||
_logger.printTrace('Application launched on the device. Waiting for Dart VM Service url.');
|
||||
|
||||
final int defaultTimeout = interfaceType == IOSDeviceConnectionInterface.network ? 45 : 30;
|
||||
final int defaultTimeout = isWirelesslyConnected ? 45 : 30;
|
||||
final Timer timer = Timer(discoveryTimeout ?? Duration(seconds: defaultTimeout), () {
|
||||
_logger.printError('The Dart VM Service was not discovered after $defaultTimeout seconds. This is taking much longer than expected...');
|
||||
|
||||
// If debugging with a wireless device and the timeout is reached, remind the
|
||||
// user to allow local network permissions.
|
||||
if (interfaceType == IOSDeviceConnectionInterface.network) {
|
||||
if (isWirelesslyConnected) {
|
||||
_logger.printError(
|
||||
'\nClick "Allow" to the prompt asking if you would like to find and connect devices on your local network. '
|
||||
'This is required for wireless debugging. If you selected "Don\'t Allow", '
|
||||
@ -433,7 +434,7 @@ class IOSDevice extends Device {
|
||||
});
|
||||
|
||||
Uri? localUri;
|
||||
if (interfaceType == IOSDeviceConnectionInterface.network) {
|
||||
if (isWirelesslyConnected) {
|
||||
// Wait for Dart VM Service to start up.
|
||||
final Uri? serviceURL = await vmServiceDiscovery?.uri;
|
||||
if (serviceURL == null) {
|
||||
@ -538,7 +539,7 @@ class IOSDevice extends Device {
|
||||
|
||||
@override
|
||||
Future<void> takeScreenshot(File outputFile) async {
|
||||
await _iMobileDevice.takeScreenshot(outputFile, id, interfaceType);
|
||||
await _iMobileDevice.takeScreenshot(outputFile, id, connectionInterface);
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -15,8 +15,8 @@ import '../base/platform.dart';
|
||||
import '../base/process.dart';
|
||||
import '../cache.dart';
|
||||
import '../convert.dart';
|
||||
import '../device.dart';
|
||||
import 'code_signing.dart';
|
||||
import 'iproxy.dart';
|
||||
|
||||
// Error message patterns from ios-deploy output
|
||||
const String noProvisioningProfileErrorOne = 'Error 0xe8008015';
|
||||
@ -88,7 +88,7 @@ class IOSDeploy {
|
||||
required String deviceId,
|
||||
required String bundlePath,
|
||||
required List<String>launchArguments,
|
||||
required IOSDeviceConnectionInterface interfaceType,
|
||||
required DeviceConnectionInterface interfaceType,
|
||||
Directory? appDeltaDirectory,
|
||||
}) async {
|
||||
appDeltaDirectory?.createSync(recursive: true);
|
||||
@ -102,7 +102,7 @@ class IOSDeploy {
|
||||
'--app_deltas',
|
||||
appDeltaDirectory.path,
|
||||
],
|
||||
if (interfaceType != IOSDeviceConnectionInterface.network)
|
||||
if (interfaceType != DeviceConnectionInterface.wireless)
|
||||
'--no-wifi',
|
||||
if (launchArguments.isNotEmpty) ...<String>[
|
||||
'--args',
|
||||
@ -126,7 +126,7 @@ class IOSDeploy {
|
||||
required String deviceId,
|
||||
required String bundlePath,
|
||||
required List<String> launchArguments,
|
||||
required IOSDeviceConnectionInterface interfaceType,
|
||||
required DeviceConnectionInterface interfaceType,
|
||||
Directory? appDeltaDirectory,
|
||||
required bool uninstallFirst,
|
||||
}) {
|
||||
@ -149,7 +149,7 @@ class IOSDeploy {
|
||||
if (uninstallFirst)
|
||||
'--uninstall',
|
||||
'--debug',
|
||||
if (interfaceType != IOSDeviceConnectionInterface.network)
|
||||
if (interfaceType != DeviceConnectionInterface.wireless)
|
||||
'--no-wifi',
|
||||
if (launchArguments.isNotEmpty) ...<String>[
|
||||
'--args',
|
||||
@ -171,7 +171,7 @@ class IOSDeploy {
|
||||
required String deviceId,
|
||||
required String bundlePath,
|
||||
required List<String> launchArguments,
|
||||
required IOSDeviceConnectionInterface interfaceType,
|
||||
required DeviceConnectionInterface interfaceType,
|
||||
required bool uninstallFirst,
|
||||
Directory? appDeltaDirectory,
|
||||
}) async {
|
||||
@ -186,7 +186,7 @@ class IOSDeploy {
|
||||
'--app_deltas',
|
||||
appDeltaDirectory.path,
|
||||
],
|
||||
if (interfaceType != IOSDeviceConnectionInterface.network)
|
||||
if (interfaceType != DeviceConnectionInterface.wireless)
|
||||
'--no-wifi',
|
||||
if (uninstallFirst)
|
||||
'--uninstall',
|
||||
|
@ -8,12 +8,6 @@ import '../base/io.dart';
|
||||
import '../base/logger.dart';
|
||||
import '../base/process.dart';
|
||||
|
||||
enum IOSDeviceConnectionInterface {
|
||||
none,
|
||||
usb,
|
||||
network,
|
||||
}
|
||||
|
||||
/// Wraps iproxy command line tool port forwarding.
|
||||
///
|
||||
/// See https://github.com/libimobiledevice/libusbmuxd.
|
||||
|
@ -16,6 +16,7 @@ import '../base/project_migrator.dart';
|
||||
import '../base/utils.dart';
|
||||
import '../build_info.dart';
|
||||
import '../cache.dart';
|
||||
import '../device.dart';
|
||||
import '../flutter_manifest.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../macos/cocoapod_utils.dart';
|
||||
@ -27,7 +28,6 @@ import '../project.dart';
|
||||
import '../reporting/reporting.dart';
|
||||
import 'application_package.dart';
|
||||
import 'code_signing.dart';
|
||||
import 'iproxy.dart';
|
||||
import 'migrations/host_app_info_plist_migration.dart';
|
||||
import 'migrations/ios_deployment_target_migration.dart';
|
||||
import 'migrations/project_base_configuration_migration.dart';
|
||||
@ -87,7 +87,7 @@ class IMobileDevice {
|
||||
Future<void> takeScreenshot(
|
||||
File outputFile,
|
||||
String deviceID,
|
||||
IOSDeviceConnectionInterface interfaceType,
|
||||
DeviceConnectionInterface interfaceType,
|
||||
) {
|
||||
return _processUtils.run(
|
||||
<String>[
|
||||
@ -95,7 +95,7 @@ class IMobileDevice {
|
||||
outputFile.path,
|
||||
'--udid',
|
||||
deviceID,
|
||||
if (interfaceType == IOSDeviceConnectionInterface.network)
|
||||
if (interfaceType == DeviceConnectionInterface.wireless)
|
||||
'--network',
|
||||
],
|
||||
throwOnError: true,
|
||||
|
@ -14,6 +14,7 @@ import '../base/process.dart';
|
||||
import '../build_info.dart';
|
||||
import '../cache.dart';
|
||||
import '../convert.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart' as globals;
|
||||
import '../ios/devices.dart';
|
||||
import '../ios/ios_deploy.dart';
|
||||
@ -303,8 +304,6 @@ class XCDevice {
|
||||
}
|
||||
}
|
||||
|
||||
final IOSDeviceConnectionInterface interface = _interfaceType(device);
|
||||
|
||||
String? sdkVersion = _sdkVersion(device);
|
||||
|
||||
if (sdkVersion != null) {
|
||||
@ -318,7 +317,7 @@ class XCDevice {
|
||||
identifier,
|
||||
name: name,
|
||||
cpuArchitecture: _cpuArchitecture(device),
|
||||
interfaceType: interface,
|
||||
connectionInterface: _interfaceType(device),
|
||||
sdkVersion: sdkVersion,
|
||||
iProxy: _iProxy,
|
||||
fileSystem: globals.fs,
|
||||
@ -356,19 +355,16 @@ class XCDevice {
|
||||
return code is int ? code : null;
|
||||
}
|
||||
|
||||
static IOSDeviceConnectionInterface _interfaceType(Map<String, Object?> deviceProperties) {
|
||||
// Interface can be "usb", "network", or "none" for simulators
|
||||
// and unknown future interfaces.
|
||||
static DeviceConnectionInterface _interfaceType(Map<String, Object?> deviceProperties) {
|
||||
// Interface can be "usb" or "network". It can also be missing
|
||||
// (e.g. simulators do not have an interface property).
|
||||
// If the interface is "network", use `DeviceConnectionInterface.wireless`,
|
||||
// otherwise use `DeviceConnectionInterface.attached.
|
||||
final Object? interface = deviceProperties['interface'];
|
||||
if (interface is String) {
|
||||
if (interface.toLowerCase() == 'network') {
|
||||
return IOSDeviceConnectionInterface.network;
|
||||
} else {
|
||||
return IOSDeviceConnectionInterface.usb;
|
||||
if (interface is String && interface.toLowerCase() == 'network') {
|
||||
return DeviceConnectionInterface.wireless;
|
||||
}
|
||||
}
|
||||
|
||||
return IOSDeviceConnectionInterface.none;
|
||||
return DeviceConnectionInterface.attached;
|
||||
}
|
||||
|
||||
static String? _sdkVersion(Map<String, Object?> deviceProperties) {
|
||||
|
@ -2,14 +2,18 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
import '../base/common.dart';
|
||||
import '../base/logger.dart';
|
||||
import '../base/user_messages.dart';
|
||||
import '../device.dart';
|
||||
import '../globals.dart' as globals;
|
||||
|
||||
const String _wirelesslyConnectedDevicesMessage = 'Wirelessly connected devices:';
|
||||
|
||||
/// This class handles functionality of finding and selecting target devices.
|
||||
///
|
||||
/// Target devices are devices that are supported and selectable to run
|
||||
/// a flutter application on.
|
||||
class TargetDevices {
|
||||
TargetDevices({
|
||||
required DeviceManager deviceManager,
|
||||
@ -20,10 +24,64 @@ class TargetDevices {
|
||||
final DeviceManager _deviceManager;
|
||||
final Logger _logger;
|
||||
|
||||
/// Find and return all target [Device]s based upon currently connected
|
||||
/// devices and criteria entered by the user on the command line.
|
||||
/// If no device can be found that meets specified criteria,
|
||||
/// then print an error message and return null.
|
||||
Future<List<Device>> _getAttachedDevices({
|
||||
DeviceDiscoverySupportFilter? supportFilter,
|
||||
}) async {
|
||||
return _deviceManager.getDevices(
|
||||
filter: DeviceDiscoveryFilter(
|
||||
deviceConnectionInterface: DeviceConnectionInterface.attached,
|
||||
supportFilter: supportFilter,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Device>> _getWirelessDevices({
|
||||
DeviceDiscoverySupportFilter? supportFilter,
|
||||
}) async {
|
||||
return _deviceManager.getDevices(
|
||||
filter: DeviceDiscoveryFilter(
|
||||
deviceConnectionInterface: DeviceConnectionInterface.wireless,
|
||||
supportFilter: supportFilter,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<Device>> _getDeviceById({
|
||||
bool includeDevicesUnsupportedByProject = false,
|
||||
}) async {
|
||||
return _deviceManager.getDevices(
|
||||
filter: DeviceDiscoveryFilter(
|
||||
supportFilter: _deviceManager.deviceSupportFilter(
|
||||
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
DeviceDiscoverySupportFilter _defaultSupportFilter(
|
||||
bool includeDevicesUnsupportedByProject,
|
||||
) {
|
||||
return _deviceManager.deviceSupportFilter(
|
||||
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
|
||||
);
|
||||
}
|
||||
|
||||
/// Find and return all target [Device]s based upon criteria entered by the
|
||||
/// user on the command line.
|
||||
///
|
||||
/// When the user has specified `all` devices, return all devices meeting criteria.
|
||||
///
|
||||
/// When the user has specified a device id/name, attempt to find an exact or
|
||||
/// partial match. If an exact match or a single partial match is found,
|
||||
/// return it immediately.
|
||||
///
|
||||
/// When multiple devices are found and there is a terminal attached to
|
||||
/// stdin, allow the user to select which device to use. When a terminal
|
||||
/// with stdin is not available, print a list of available devices and
|
||||
/// return null.
|
||||
///
|
||||
/// When no devices meet user specifications, print a list of unsupported
|
||||
/// devices and return null.
|
||||
Future<List<Device>?> findAllTargetDevices({
|
||||
Duration? deviceDiscoveryTimeout,
|
||||
bool includeDevicesUnsupportedByProject = false,
|
||||
@ -32,67 +90,175 @@ class TargetDevices {
|
||||
_logger.printError(userMessages.flutterNoDevelopmentDevice);
|
||||
return null;
|
||||
}
|
||||
List<Device> devices = await getDevices(
|
||||
|
||||
if (deviceDiscoveryTimeout != null) {
|
||||
// Reset the cache with the specified timeout.
|
||||
await _deviceManager.refreshAllDevices(timeout: deviceDiscoveryTimeout);
|
||||
}
|
||||
|
||||
if (_deviceManager.hasSpecifiedDeviceId) {
|
||||
// Must check for device match separately from `_getAttachedDevices` and
|
||||
// `_getWirelessDevices` because if an exact match is found in one
|
||||
// and a partial match is found in another, there is no way to distinguish
|
||||
// between them.
|
||||
final List<Device> devices = await _getDeviceById(
|
||||
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
|
||||
timeout: deviceDiscoveryTimeout,
|
||||
);
|
||||
|
||||
if (devices.isEmpty) {
|
||||
if (_deviceManager.hasSpecifiedDeviceId) {
|
||||
_logger.printStatus(userMessages.flutterNoMatchingDevice(_deviceManager.specifiedDeviceId!));
|
||||
final List<Device> allDevices = await _deviceManager.getAllDevices();
|
||||
if (allDevices.isNotEmpty) {
|
||||
_logger.printStatus('');
|
||||
_logger.printStatus('The following devices were found:');
|
||||
await Device.printDevices(allDevices, _logger);
|
||||
}
|
||||
return null;
|
||||
} else if (_deviceManager.hasSpecifiedAllDevices) {
|
||||
_logger.printStatus(userMessages.flutterNoDevicesFound);
|
||||
await _printUnsupportedDevice(_deviceManager);
|
||||
return null;
|
||||
} else {
|
||||
_logger.printStatus(userMessages.flutterNoSupportedDevices);
|
||||
await _printUnsupportedDevice(_deviceManager);
|
||||
return null;
|
||||
}
|
||||
} else if (devices.length > 1) {
|
||||
if (_deviceManager.hasSpecifiedDeviceId) {
|
||||
_logger.printStatus(userMessages.flutterFoundSpecifiedDevices(devices.length, _deviceManager.specifiedDeviceId!));
|
||||
return null;
|
||||
} else if (!_deviceManager.hasSpecifiedAllDevices) {
|
||||
if (globals.terminal.stdinHasTerminal) {
|
||||
// If DeviceManager was not able to prioritize a device. For example, if the user
|
||||
// has two active Android devices running, then we request the user to
|
||||
// choose one. If the user has two nonEphemeral devices running, we also
|
||||
// request input to choose one.
|
||||
_logger.printStatus(userMessages.flutterMultipleDevicesFound);
|
||||
await Device.printDevices(devices, _logger);
|
||||
final Device chosenDevice = await _chooseOneOfAvailableDevices(devices);
|
||||
|
||||
// Update the [DeviceManager.specifiedDeviceId] so that we will not be prompted again.
|
||||
_deviceManager.specifiedDeviceId = chosenDevice.id;
|
||||
|
||||
devices = <Device>[chosenDevice];
|
||||
} else {
|
||||
// Show an error message asking the user to specify `-d all` if they
|
||||
// want to run on multiple devices.
|
||||
final List<Device> allDevices = await _deviceManager.getAllDevices();
|
||||
_logger.printStatus(userMessages.flutterSpecifyDeviceWithAllOption);
|
||||
_logger.printStatus('');
|
||||
await Device.printDevices(allDevices, _logger);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (devices.length == 1) {
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _printUnsupportedDevice(DeviceManager deviceManager) async {
|
||||
final List<Device> unsupportedDevices = await deviceManager.getDevices();
|
||||
final List<Device> attachedDevices = await _getAttachedDevices(
|
||||
supportFilter: _defaultSupportFilter(includeDevicesUnsupportedByProject),
|
||||
);
|
||||
final List<Device> wirelessDevices = await _getWirelessDevices(
|
||||
supportFilter: _defaultSupportFilter(includeDevicesUnsupportedByProject),
|
||||
);
|
||||
final List<Device> allDevices = attachedDevices + wirelessDevices;
|
||||
|
||||
if (allDevices.isEmpty) {
|
||||
return _handleNoDevices();
|
||||
} else if (_deviceManager.hasSpecifiedAllDevices) {
|
||||
return allDevices;
|
||||
} else if (allDevices.length > 1) {
|
||||
return _handleMultipleDevices(attachedDevices, wirelessDevices);
|
||||
}
|
||||
return allDevices;
|
||||
}
|
||||
|
||||
/// When no supported devices are found, display a message and list of
|
||||
/// unsupported devices found.
|
||||
Future<List<Device>?> _handleNoDevices() async {
|
||||
// Get connected devices from cache, including unsupported ones.
|
||||
final List<Device> unsupportedDevices = await _deviceManager.getAllDevices();
|
||||
|
||||
if (_deviceManager.hasSpecifiedDeviceId) {
|
||||
_logger.printStatus(
|
||||
userMessages.flutterNoMatchingDevice(_deviceManager.specifiedDeviceId!),
|
||||
);
|
||||
if (unsupportedDevices.isNotEmpty) {
|
||||
_logger.printStatus('');
|
||||
_logger.printStatus('The following devices were found:');
|
||||
await Device.printDevices(unsupportedDevices, _logger);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
_logger.printStatus(_deviceManager.hasSpecifiedAllDevices
|
||||
? userMessages.flutterNoDevicesFound
|
||||
: userMessages.flutterNoSupportedDevices);
|
||||
await _printUnsupportedDevice(unsupportedDevices);
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Determine which device to use when multiple found.
|
||||
///
|
||||
/// If user has not specified a device id/name, attempt to prioritize
|
||||
/// ephemeral devices. If a single ephemeral device is found, return it
|
||||
/// immediately.
|
||||
///
|
||||
/// Otherwise, prompt the user to select a device if there is a terminal
|
||||
/// with stdin. If there is not a terminal, display the list of devices with
|
||||
/// instructions to use a device selection flag.
|
||||
Future<List<Device>?> _handleMultipleDevices(
|
||||
List<Device> attachedDevices,
|
||||
List<Device> wirelessDevices,
|
||||
) async {
|
||||
final List<Device> allDevices = attachedDevices + wirelessDevices;
|
||||
|
||||
final Device? ephemeralDevice = _deviceManager.getSingleEphemeralDevice(allDevices);
|
||||
if (ephemeralDevice != null) {
|
||||
return <Device>[ephemeralDevice];
|
||||
}
|
||||
|
||||
if (globals.terminal.stdinHasTerminal) {
|
||||
return _selectFromMultipleDevices(attachedDevices, wirelessDevices);
|
||||
} else {
|
||||
return _printMultipleDevices(attachedDevices, wirelessDevices);
|
||||
}
|
||||
}
|
||||
|
||||
/// Display a list of found devices. When the user has not specified the
|
||||
/// device id/name, display devices unsupported by the project as well and
|
||||
/// give instructions to use a device selection flag.
|
||||
Future<List<Device>?> _printMultipleDevices(
|
||||
List<Device> attachedDevices,
|
||||
List<Device> wirelessDevices,
|
||||
) async {
|
||||
List<Device> supportedAttachedDevices = attachedDevices;
|
||||
List<Device> supportedWirelessDevices = wirelessDevices;
|
||||
if (_deviceManager.hasSpecifiedDeviceId) {
|
||||
final int allDeviceLength = supportedAttachedDevices.length + supportedWirelessDevices.length;
|
||||
_logger.printStatus(userMessages.flutterFoundSpecifiedDevices(
|
||||
allDeviceLength,
|
||||
_deviceManager.specifiedDeviceId!,
|
||||
));
|
||||
} else {
|
||||
// Get connected devices from cache, including ones unsupported for the
|
||||
// project but still supported by Flutter.
|
||||
supportedAttachedDevices = await _getAttachedDevices(
|
||||
supportFilter: DeviceDiscoverySupportFilter.excludeDevicesUnsupportedByFlutter(),
|
||||
);
|
||||
supportedWirelessDevices = await _getWirelessDevices(
|
||||
supportFilter: DeviceDiscoverySupportFilter.excludeDevicesUnsupportedByFlutter(),
|
||||
);
|
||||
|
||||
_logger.printStatus(userMessages.flutterSpecifyDeviceWithAllOption);
|
||||
_logger.printStatus('');
|
||||
}
|
||||
|
||||
await Device.printDevices(supportedAttachedDevices, _logger);
|
||||
|
||||
if (supportedWirelessDevices.isNotEmpty) {
|
||||
if (_deviceManager.hasSpecifiedDeviceId || supportedAttachedDevices.isNotEmpty) {
|
||||
_logger.printStatus('');
|
||||
}
|
||||
_logger.printStatus(_wirelesslyConnectedDevicesMessage);
|
||||
await Device.printDevices(supportedWirelessDevices, _logger);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Display a list of selectable devices, prompt the user to choose one, and
|
||||
/// wait for the user to select a valid option.
|
||||
Future<List<Device>?> _selectFromMultipleDevices(
|
||||
List<Device> attachedDevices,
|
||||
List<Device> wirelessDevices,
|
||||
) async {
|
||||
final List<Device> allDevices = attachedDevices + wirelessDevices;
|
||||
|
||||
if (_deviceManager.hasSpecifiedDeviceId) {
|
||||
_logger.printStatus(userMessages.flutterFoundSpecifiedDevices(
|
||||
allDevices.length,
|
||||
_deviceManager.specifiedDeviceId!,
|
||||
));
|
||||
} else {
|
||||
_logger.printStatus(userMessages.flutterMultipleDevicesFound);
|
||||
}
|
||||
|
||||
await Device.printDevices(attachedDevices, _logger);
|
||||
|
||||
if (wirelessDevices.isNotEmpty) {
|
||||
_logger.printStatus('');
|
||||
_logger.printStatus(_wirelesslyConnectedDevicesMessage);
|
||||
await Device.printDevices(wirelessDevices, _logger);
|
||||
_logger.printStatus('');
|
||||
}
|
||||
|
||||
final Device chosenDevice = await _chooseOneOfAvailableDevices(allDevices);
|
||||
|
||||
// Update the [DeviceManager.specifiedDeviceId] so that the user will not be prompted again.
|
||||
_deviceManager.specifiedDeviceId = chosenDevice.id;
|
||||
|
||||
return <Device>[chosenDevice];
|
||||
}
|
||||
|
||||
Future<void> _printUnsupportedDevice(List<Device> unsupportedDevices) async {
|
||||
if (unsupportedDevices.isNotEmpty) {
|
||||
final StringBuffer result = StringBuffer();
|
||||
result.writeln();
|
||||
result.writeln(userMessages.flutterFoundButUnsupportedDevices);
|
||||
result.writeAll(
|
||||
(await Device.descriptions(unsupportedDevices))
|
||||
@ -104,7 +270,7 @@ class TargetDevices {
|
||||
result.writeln(userMessages.flutterMissPlatformProjects(
|
||||
Device.devicesPlatformTypes(unsupportedDevices),
|
||||
));
|
||||
_logger.printStatus(result.toString());
|
||||
_logger.printStatus(result.toString(), newline: false);
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,48 +301,4 @@ class TargetDevices {
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Find and return all target [Device]s based upon currently connected
|
||||
/// devices, the current project, and criteria entered by the user on
|
||||
/// the command line.
|
||||
///
|
||||
/// Returns a list of devices specified by the user.
|
||||
///
|
||||
/// * If the user specified '-d all', then return all connected devices which
|
||||
/// support the current project, except for fuchsia and web.
|
||||
///
|
||||
/// * If the user specified a device id, then do nothing as the list is already
|
||||
/// filtered by [_deviceManager.getDevices].
|
||||
///
|
||||
/// * If the user did not specify a device id and there is more than one
|
||||
/// device connected, then filter out unsupported devices and prioritize
|
||||
/// ephemeral devices.
|
||||
@visibleForTesting
|
||||
Future<List<Device>> getDevices({
|
||||
bool includeDevicesUnsupportedByProject = false,
|
||||
Duration? timeout,
|
||||
}) async {
|
||||
if (timeout != null) {
|
||||
// Reset the cache with the specified timeout.
|
||||
await _deviceManager.refreshAllDevices(timeout: timeout);
|
||||
}
|
||||
|
||||
final List<Device> devices = await _deviceManager.getDevices(
|
||||
filter: DeviceDiscoveryFilter(
|
||||
supportFilter: _deviceManager.deviceSupportFilter(
|
||||
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
// If there is more than one device, attempt to prioritize ephemeral devices.
|
||||
if (devices.length > 1) {
|
||||
final Device? ephemeralDevice = _deviceManager.getSingleEphemeralDevice(devices);
|
||||
if (ephemeralDevice != null) {
|
||||
return <Device>[ephemeralDevice];
|
||||
}
|
||||
}
|
||||
|
||||
return devices;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,6 @@ import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/device_port_forwarder.dart';
|
||||
import 'package:flutter_tools/src/ios/application_package.dart';
|
||||
import 'package:flutter_tools/src/ios/devices.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
import 'package:flutter_tools/src/macos/macos_ipad_device.dart';
|
||||
import 'package:flutter_tools/src/mdns_discovery.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
@ -241,7 +240,7 @@ void main() {
|
||||
logReader: fakeLogReader,
|
||||
portForwarder: portForwarder,
|
||||
majorSdkVersion: 16,
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
connectionInterface: DeviceConnectionInterface.wireless,
|
||||
);
|
||||
testDeviceManager.devices = <Device>[device];
|
||||
final FakeHotRunner hotRunner = FakeHotRunner();
|
||||
@ -313,7 +312,7 @@ void main() {
|
||||
logReader: fakeLogReader,
|
||||
portForwarder: portForwarder,
|
||||
majorSdkVersion: 16,
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
connectionInterface: DeviceConnectionInterface.wireless,
|
||||
);
|
||||
testDeviceManager.devices = <Device>[device];
|
||||
final FakeHotRunner hotRunner = FakeHotRunner();
|
||||
@ -389,7 +388,7 @@ void main() {
|
||||
logReader: fakeLogReader,
|
||||
portForwarder: portForwarder,
|
||||
majorSdkVersion: 16,
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
connectionInterface: DeviceConnectionInterface.wireless,
|
||||
);
|
||||
testDeviceManager.devices = <Device>[device];
|
||||
final FakeHotRunner hotRunner = FakeHotRunner();
|
||||
@ -1237,6 +1236,10 @@ class FakeAndroidDevice extends Fake implements AndroidDevice {
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => TargetPlatform.android_arm;
|
||||
|
||||
@override
|
||||
DeviceConnectionInterface get connectionInterface =>
|
||||
DeviceConnectionInterface.attached;
|
||||
|
||||
@override
|
||||
bool isSupported() => true;
|
||||
|
||||
@ -1291,7 +1294,7 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
||||
DevicePortForwarder? portForwarder,
|
||||
DeviceLogReader? logReader,
|
||||
this.onGetLogReader,
|
||||
this.interfaceType = IOSDeviceConnectionInterface.none,
|
||||
this.connectionInterface = DeviceConnectionInterface.attached,
|
||||
this.majorSdkVersion = 0,
|
||||
}) : _portForwarder = portForwarder, _logReader = logReader;
|
||||
|
||||
@ -1300,7 +1303,11 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
||||
int majorSdkVersion;
|
||||
|
||||
@override
|
||||
final IOSDeviceConnectionInterface interfaceType;
|
||||
final DeviceConnectionInterface connectionInterface;
|
||||
|
||||
@override
|
||||
bool get isWirelesslyConnected =>
|
||||
connectionInterface == DeviceConnectionInterface.wireless;
|
||||
|
||||
@override
|
||||
DevicePortForwarder get portForwarder => _portForwarder!;
|
||||
|
@ -6,12 +6,12 @@ import 'dart:convert';
|
||||
|
||||
import 'package:flutter_tools/src/android/android_sdk.dart';
|
||||
import 'package:flutter_tools/src/artifacts.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/commands/devices.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/context.dart';
|
||||
import '../../src/fake_devices.dart';
|
||||
import '../../src/test_flutter_command_runner.dart';
|
||||
@ -23,9 +23,11 @@ void main() {
|
||||
});
|
||||
|
||||
late Cache cache;
|
||||
late Platform platform;
|
||||
|
||||
setUp(() {
|
||||
cache = Cache.test(processManager: FakeProcessManager.any());
|
||||
platform = FakePlatform();
|
||||
});
|
||||
|
||||
testUsingContext('returns 0 when called', () async {
|
||||
@ -39,7 +41,16 @@ void main() {
|
||||
testUsingContext('no error when no connected devices', () async {
|
||||
final DevicesCommand command = DevicesCommand();
|
||||
await createTestCommandRunner(command).run(<String>['devices']);
|
||||
expect(testLogger.statusText, containsIgnoringWhitespace('No devices detected'));
|
||||
expect(
|
||||
testLogger.statusText,
|
||||
equals('''
|
||||
No devices detected.
|
||||
|
||||
Run "flutter emulators" to list and start any available device emulators.
|
||||
|
||||
If you expected your device to be detected, please run "flutter doctor" to diagnose potential issues. You may also try increasing the time to wait for connected devices with the --device-timeout flag. Visit https://flutter.dev/setup/ for troubleshooting tips.
|
||||
'''),
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
AndroidSdk: () => null,
|
||||
DeviceManager: () => NoDevicesManager(),
|
||||
@ -48,16 +59,27 @@ void main() {
|
||||
Artifacts: () => Artifacts.test(),
|
||||
});
|
||||
|
||||
group('when includes both attached and wireless devices', () {
|
||||
List<FakeDeviceJsonData>? deviceList;
|
||||
setUp(() {
|
||||
deviceList = <FakeDeviceJsonData>[
|
||||
fakeDevices[0],
|
||||
fakeDevices[1],
|
||||
fakeDevices[2],
|
||||
];
|
||||
});
|
||||
|
||||
testUsingContext("get devices' platform types", () async {
|
||||
final List<String> platformTypes = Device.devicesPlatformTypes(
|
||||
await globals.deviceManager!.getAllDevices(),
|
||||
);
|
||||
expect(platformTypes, <String>['android', 'web']);
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => _FakeDeviceManager(),
|
||||
DeviceManager: () => _FakeDeviceManager(devices: deviceList),
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
Cache: () => cache,
|
||||
Artifacts: () => Artifacts.test(),
|
||||
Platform: () => platform,
|
||||
});
|
||||
|
||||
testUsingContext('Outputs parsable JSON with --machine flag', () async {
|
||||
@ -66,76 +88,114 @@ void main() {
|
||||
expect(
|
||||
json.decode(testLogger.statusText),
|
||||
<Map<String, Object>>[
|
||||
<String, Object>{
|
||||
'name': 'ephemeral',
|
||||
'id': 'ephemeral',
|
||||
'isSupported': true,
|
||||
'targetPlatform': 'android-arm',
|
||||
'emulator': true,
|
||||
'sdk': 'Test SDK (1.2.3)',
|
||||
'capabilities': <String, Object>{
|
||||
'hotReload': true,
|
||||
'hotRestart': true,
|
||||
'screenshot': false,
|
||||
'fastStart': false,
|
||||
'flutterExit': true,
|
||||
'hardwareRendering': true,
|
||||
'startPaused': true,
|
||||
},
|
||||
},
|
||||
<String,Object>{
|
||||
'name': 'webby',
|
||||
'id': 'webby',
|
||||
'isSupported': true,
|
||||
'targetPlatform': 'web-javascript',
|
||||
'emulator': true,
|
||||
'sdk': 'Web SDK (1.2.4)',
|
||||
'capabilities': <String, Object>{
|
||||
'hotReload': true,
|
||||
'hotRestart': true,
|
||||
'screenshot': false,
|
||||
'fastStart': false,
|
||||
'flutterExit': true,
|
||||
'hardwareRendering': true,
|
||||
'startPaused': true,
|
||||
},
|
||||
},
|
||||
fakeDevices[0].json,
|
||||
fakeDevices[1].json,
|
||||
fakeDevices[2].json,
|
||||
],
|
||||
);
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => _FakeDeviceManager(),
|
||||
DeviceManager: () => _FakeDeviceManager(devices: deviceList),
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
Cache: () => cache,
|
||||
Artifacts: () => Artifacts.test(),
|
||||
Platform: () => platform,
|
||||
});
|
||||
|
||||
testUsingContext('available devices and diagnostics', () async {
|
||||
final DevicesCommand command = DevicesCommand();
|
||||
await createTestCommandRunner(command).run(<String>['devices']);
|
||||
expect(
|
||||
testLogger.statusText,
|
||||
'''
|
||||
expect(testLogger.statusText, '''
|
||||
2 connected devices:
|
||||
|
||||
ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator)
|
||||
webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator)
|
||||
|
||||
1 wirelessly connected device:
|
||||
|
||||
wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator)
|
||||
|
||||
• Cannot connect to device ABC
|
||||
''');
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => _FakeDeviceManager(devices: deviceList),
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
Platform: () => platform,
|
||||
});
|
||||
});
|
||||
|
||||
group('when includes only attached devices', () {
|
||||
List<FakeDeviceJsonData>? deviceList;
|
||||
setUp(() {
|
||||
deviceList = <FakeDeviceJsonData>[
|
||||
fakeDevices[0],
|
||||
fakeDevices[1],
|
||||
];
|
||||
});
|
||||
|
||||
testUsingContext('available devices and diagnostics', () async {
|
||||
final DevicesCommand command = DevicesCommand();
|
||||
await createTestCommandRunner(command).run(<String>['devices']);
|
||||
expect(testLogger.statusText, '''
|
||||
2 connected devices:
|
||||
|
||||
ephemeral (mobile) • ephemeral • android-arm • Test SDK (1.2.3) (emulator)
|
||||
webby (mobile) • webby • web-javascript • Web SDK (1.2.4) (emulator)
|
||||
|
||||
• Cannot connect to device ABC
|
||||
'''
|
||||
);
|
||||
''');
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => _FakeDeviceManager(),
|
||||
DeviceManager: () => _FakeDeviceManager(devices: deviceList),
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
Platform: () => platform,
|
||||
});
|
||||
});
|
||||
|
||||
group('when includes only wireless devices', () {
|
||||
List<FakeDeviceJsonData>? deviceList;
|
||||
setUp(() {
|
||||
deviceList = <FakeDeviceJsonData>[
|
||||
fakeDevices[2],
|
||||
];
|
||||
});
|
||||
|
||||
testUsingContext('available devices and diagnostics', () async {
|
||||
final DevicesCommand command = DevicesCommand();
|
||||
await createTestCommandRunner(command).run(<String>['devices']);
|
||||
expect(testLogger.statusText, '''
|
||||
1 wirelessly connected device:
|
||||
|
||||
wireless android (mobile) • wireless-android • android-arm • Test SDK (1.2.3) (emulator)
|
||||
|
||||
• Cannot connect to device ABC
|
||||
''');
|
||||
}, overrides: <Type, Generator>{
|
||||
DeviceManager: () => _FakeDeviceManager(devices: deviceList),
|
||||
ProcessManager: () => FakeProcessManager.any(),
|
||||
Platform: () => platform,
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class _FakeDeviceManager extends DeviceManager {
|
||||
_FakeDeviceManager() : super(logger: testLogger);
|
||||
_FakeDeviceManager({
|
||||
List<FakeDeviceJsonData>? devices,
|
||||
}) : fakeDevices = devices ?? <FakeDeviceJsonData>[],
|
||||
super(logger: testLogger);
|
||||
|
||||
List<FakeDeviceJsonData> fakeDevices = <FakeDeviceJsonData>[];
|
||||
|
||||
@override
|
||||
Future<List<Device>> getAllDevices({DeviceDiscoveryFilter? filter}) =>
|
||||
Future<List<Device>>.value(fakeDevices.map((FakeDeviceJsonData d) => d.dev).toList());
|
||||
Future<List<Device>> getAllDevices({DeviceDiscoveryFilter? filter}) async {
|
||||
final List<Device> devices = <Device>[];
|
||||
for (final FakeDeviceJsonData deviceJson in fakeDevices) {
|
||||
if (filter?.deviceConnectionInterface == null ||
|
||||
deviceJson.dev.connectionInterface == filter?.deviceConnectionInterface) {
|
||||
devices.add(deviceJson.dev);
|
||||
}
|
||||
}
|
||||
return devices;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Device>> refreshAllDevices({
|
||||
|
@ -22,7 +22,6 @@ import 'package:flutter_tools/src/dart/pub.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/drive/drive_service.dart';
|
||||
import 'package:flutter_tools/src/ios/devices.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:package_config/package_config.dart';
|
||||
import 'package:test/fake.dart';
|
||||
@ -68,7 +67,7 @@ void main() {
|
||||
|
||||
final Device screenshotDevice = ThrowingScreenshotDevice()
|
||||
..supportsScreenshot = false;
|
||||
fakeDeviceManager.devices = <Device>[screenshotDevice];
|
||||
fakeDeviceManager.attachedDevices = <Device>[screenshotDevice];
|
||||
|
||||
await expectLater(() => createTestCommandRunner(command).run(
|
||||
<String>[
|
||||
@ -104,7 +103,7 @@ void main() {
|
||||
fileSystem.directory('drive_screenshots').createSync();
|
||||
|
||||
final Device screenshotDevice = ThrowingScreenshotDevice();
|
||||
fakeDeviceManager.devices = <Device>[screenshotDevice];
|
||||
fakeDeviceManager.attachedDevices = <Device>[screenshotDevice];
|
||||
|
||||
await expectLater(() => createTestCommandRunner(command).run(
|
||||
<String>[
|
||||
@ -142,7 +141,7 @@ void main() {
|
||||
fileSystem.directory('drive_screenshots').createSync();
|
||||
|
||||
final Device screenshotDevice = ScreenshotDevice();
|
||||
fakeDeviceManager.devices = <Device>[screenshotDevice];
|
||||
fakeDeviceManager.attachedDevices = <Device>[screenshotDevice];
|
||||
|
||||
await expectLater(() => createTestCommandRunner(command).run(
|
||||
<String>[
|
||||
@ -184,7 +183,7 @@ void main() {
|
||||
fileSystem.file('drive_screenshots').createSync();
|
||||
|
||||
final Device screenshotDevice = ThrowingScreenshotDevice();
|
||||
fakeDeviceManager.devices = <Device>[screenshotDevice];
|
||||
fakeDeviceManager.attachedDevices = <Device>[screenshotDevice];
|
||||
|
||||
await expectLater(() => createTestCommandRunner(command).run(
|
||||
<String>[
|
||||
@ -222,7 +221,7 @@ void main() {
|
||||
fileSystem.directory('drive_screenshots').createSync();
|
||||
|
||||
final ScreenshotDevice screenshotDevice = ScreenshotDevice();
|
||||
fakeDeviceManager.devices = <Device>[screenshotDevice];
|
||||
fakeDeviceManager.attachedDevices = <Device>[screenshotDevice];
|
||||
|
||||
expect(screenshotDevice.screenshots, isEmpty);
|
||||
bool caughtToolExit = false;
|
||||
@ -293,7 +292,7 @@ void main() {
|
||||
fileSystem.directory('drive_screenshots').createSync();
|
||||
|
||||
final ScreenshotDevice screenshotDevice = ScreenshotDevice();
|
||||
fakeDeviceManager.devices = <Device>[screenshotDevice];
|
||||
fakeDeviceManager.attachedDevices = <Device>[screenshotDevice];
|
||||
|
||||
expect(screenshotDevice.screenshots, isEmpty);
|
||||
|
||||
@ -423,8 +422,8 @@ void main() {
|
||||
fileSystem.file('pubspec.yaml').createSync();
|
||||
|
||||
final Device networkDevice = FakeIosDevice()
|
||||
..interfaceType = IOSDeviceConnectionInterface.network;
|
||||
fakeDeviceManager.devices = <Device>[networkDevice];
|
||||
..connectionInterface = DeviceConnectionInterface.wireless;
|
||||
fakeDeviceManager.wirelessDevices = <Device>[networkDevice];
|
||||
|
||||
await expectLater(() => createTestCommandRunner(command).run(<String>[
|
||||
'drive',
|
||||
@ -456,8 +455,8 @@ void main() {
|
||||
]), throwsToolExit());
|
||||
|
||||
final Device usbDevice = FakeIosDevice()
|
||||
..interfaceType = IOSDeviceConnectionInterface.usb;
|
||||
fakeDeviceManager.devices = <Device>[usbDevice];
|
||||
..connectionInterface = DeviceConnectionInterface.attached;
|
||||
fakeDeviceManager.attachedDevices = <Device>[usbDevice];
|
||||
|
||||
final DebuggingOptions options = await command.createDebuggingOptions(false);
|
||||
expect(options.disablePortPublication, true);
|
||||
@ -481,8 +480,8 @@ void main() {
|
||||
fileSystem.file('pubspec.yaml').createSync();
|
||||
|
||||
final Device networkDevice = FakeIosDevice()
|
||||
..interfaceType = IOSDeviceConnectionInterface.network;
|
||||
fakeDeviceManager.devices = <Device>[networkDevice];
|
||||
..connectionInterface = DeviceConnectionInterface.wireless;
|
||||
fakeDeviceManager.wirelessDevices = <Device>[networkDevice];
|
||||
|
||||
await expectLater(() => createTestCommandRunner(command).run(<String>[
|
||||
'drive',
|
||||
@ -661,7 +660,11 @@ class FakeProcessSignal extends Fake implements io.ProcessSignal {
|
||||
// ignore: avoid_implementing_value_types
|
||||
class FakeIosDevice extends Fake implements IOSDevice {
|
||||
@override
|
||||
IOSDeviceConnectionInterface interfaceType = IOSDeviceConnectionInterface.usb;
|
||||
DeviceConnectionInterface connectionInterface = DeviceConnectionInterface.attached;
|
||||
|
||||
@override
|
||||
bool get isWirelesslyConnected =>
|
||||
connectionInterface == DeviceConnectionInterface.wireless;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;
|
||||
|
@ -36,7 +36,7 @@ void main() {
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
|
||||
|
||||
final FakeAndroidDevice device = FakeAndroidDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
testDeviceManager.addAttachedDevice(device);
|
||||
|
||||
await createTestCommandRunner(command).run(<String>['install']);
|
||||
}, overrides: <Type, Generator>{
|
||||
@ -50,7 +50,7 @@ void main() {
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
|
||||
|
||||
final FakeIOSDevice device = FakeIOSDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
testDeviceManager.addAttachedDevice(device);
|
||||
|
||||
expect(() async => createTestCommandRunner(command).run(<String>['install', '--device-user', '10']),
|
||||
throwsToolExit(message: '--device-user is only supported for Android'));
|
||||
@ -65,7 +65,7 @@ void main() {
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeIOSApp());
|
||||
|
||||
final FakeIOSDevice device = FakeIOSDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
testDeviceManager.addAttachedDevice(device);
|
||||
|
||||
await createTestCommandRunner(command).run(<String>['install']);
|
||||
}, overrides: <Type, Generator>{
|
||||
@ -79,7 +79,7 @@ void main() {
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
|
||||
|
||||
final FakeAndroidDevice device = FakeAndroidDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
testDeviceManager.addAttachedDevice(device);
|
||||
|
||||
expect(() async => createTestCommandRunner(command).run(<String>['install', '--use-application-binary', 'bogus']),
|
||||
throwsToolExit(message: 'Prebuilt binary bogus does not exist'));
|
||||
@ -94,7 +94,7 @@ void main() {
|
||||
command.applicationPackages = FakeApplicationPackageFactory(FakeAndroidApk());
|
||||
|
||||
final FakeAndroidDevice device = FakeAndroidDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
testDeviceManager.addAttachedDevice(device);
|
||||
fileSystem.file('binary').createSync(recursive: true);
|
||||
|
||||
await createTestCommandRunner(command).run(<String>['install', '--use-application-binary', 'binary']);
|
||||
@ -111,7 +111,7 @@ void main() {
|
||||
command.applicationPackages = fakeAppFactory;
|
||||
|
||||
final FakeIOSDevice device = FakeIOSDevice();
|
||||
testDeviceManager.addDevice(device);
|
||||
testDeviceManager.addAttachedDevice(device);
|
||||
|
||||
await createTestCommandRunner(command).run(<String>['install', '--flavor', flavor]);
|
||||
expect(fakeAppFactory.buildInfo, isNotNull);
|
||||
@ -183,4 +183,7 @@ class FakeAndroidDevice extends Fake implements AndroidDevice {
|
||||
|
||||
@override
|
||||
String get name => 'Android';
|
||||
|
||||
@override
|
||||
bool get ephemeral => true;
|
||||
}
|
||||
|
@ -26,7 +26,6 @@ import 'package:flutter_tools/src/devfs.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/globals.dart' as globals;
|
||||
import 'package:flutter_tools/src/ios/devices.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:flutter_tools/src/reporting/reporting.dart';
|
||||
import 'package:flutter_tools/src/resident_runner.dart';
|
||||
@ -711,7 +710,7 @@ void main() {
|
||||
|
||||
testUsingContext('with only iOS usb device', () async {
|
||||
final List<Device> devices = <Device>[
|
||||
FakeIOSDevice(interfaceType: IOSDeviceConnectionInterface.usb, sdkNameAndVersion: 'iOS 16.2'),
|
||||
FakeIOSDevice(sdkNameAndVersion: 'iOS 16.2'),
|
||||
];
|
||||
final TestRunCommandForUsageValues command = TestRunCommandForUsageValues(devices: devices);
|
||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||
@ -752,7 +751,10 @@ void main() {
|
||||
|
||||
testUsingContext('with only iOS network device', () async {
|
||||
final List<Device> devices = <Device>[
|
||||
FakeIOSDevice(interfaceType: IOSDeviceConnectionInterface.network, sdkNameAndVersion: 'iOS 16.2'),
|
||||
FakeIOSDevice(
|
||||
connectionInterface: DeviceConnectionInterface.wireless,
|
||||
sdkNameAndVersion: 'iOS 16.2',
|
||||
),
|
||||
];
|
||||
final TestRunCommandForUsageValues command = TestRunCommandForUsageValues(devices: devices);
|
||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||
@ -793,8 +795,11 @@ void main() {
|
||||
|
||||
testUsingContext('with both iOS usb and network devices', () async {
|
||||
final List<Device> devices = <Device>[
|
||||
FakeIOSDevice(interfaceType: IOSDeviceConnectionInterface.network, sdkNameAndVersion: 'iOS 16.2'),
|
||||
FakeIOSDevice(interfaceType: IOSDeviceConnectionInterface.usb, sdkNameAndVersion: 'iOS 16.2'),
|
||||
FakeIOSDevice(
|
||||
connectionInterface: DeviceConnectionInterface.wireless,
|
||||
sdkNameAndVersion: 'iOS 16.2',
|
||||
),
|
||||
FakeIOSDevice(sdkNameAndVersion: 'iOS 16.2'),
|
||||
];
|
||||
final TestRunCommandForUsageValues command = TestRunCommandForUsageValues(devices: devices);
|
||||
final CommandRunner<void> runner = createTestCommandRunner(command);
|
||||
@ -1126,6 +1131,10 @@ class FakeDevice extends Fake implements Device {
|
||||
@override
|
||||
bool get isConnected => true;
|
||||
|
||||
@override
|
||||
DeviceConnectionInterface get connectionInterface =>
|
||||
DeviceConnectionInterface.attached;
|
||||
|
||||
bool supported = true;
|
||||
|
||||
@override
|
||||
@ -1209,7 +1218,7 @@ class FakeDevice extends Fake implements Device {
|
||||
// ignore: avoid_implementing_value_types
|
||||
class FakeIOSDevice extends Fake implements IOSDevice {
|
||||
FakeIOSDevice({
|
||||
this.interfaceType = IOSDeviceConnectionInterface.none,
|
||||
this.connectionInterface = DeviceConnectionInterface.attached,
|
||||
bool isLocalEmulator = false,
|
||||
String sdkNameAndVersion = '',
|
||||
}): _isLocalEmulator = isLocalEmulator,
|
||||
@ -1225,7 +1234,11 @@ class FakeIOSDevice extends Fake implements IOSDevice {
|
||||
Future<String> get sdkNameAndVersion => Future<String>.value(_sdkNameAndVersion);
|
||||
|
||||
@override
|
||||
final IOSDeviceConnectionInterface interfaceType;
|
||||
final DeviceConnectionInterface connectionInterface;
|
||||
|
||||
@override
|
||||
bool get isWirelesslyConnected =>
|
||||
connectionInterface == DeviceConnectionInterface.wireless;
|
||||
|
||||
@override
|
||||
Future<TargetPlatform> get targetPlatform async => TargetPlatform.ios;
|
||||
|
@ -922,8 +922,15 @@ class _FakeDeviceManager extends DeviceManager {
|
||||
@override
|
||||
Future<List<Device>> getAllDevices({
|
||||
DeviceDiscoveryFilter? filter,
|
||||
}) async => _connectedDevices;
|
||||
}) async => filteredDevices(filter);
|
||||
|
||||
@override
|
||||
List<DeviceDiscovery> get deviceDiscoverers => <DeviceDiscovery>[];
|
||||
|
||||
List<Device> filteredDevices(DeviceDiscoveryFilter? filter) {
|
||||
if (filter?.deviceConnectionInterface == DeviceConnectionInterface.wireless) {
|
||||
return <Device>[];
|
||||
}
|
||||
return _connectedDevices;
|
||||
}
|
||||
}
|
||||
|
@ -87,6 +87,13 @@ class FakeDeviceManager extends Fake implements DeviceManager {
|
||||
@override
|
||||
String? specifiedDeviceId;
|
||||
|
||||
@override
|
||||
Future<List<Device>> getAllDevices({
|
||||
DeviceDiscoveryFilter? filter,
|
||||
}) async {
|
||||
return devices;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Device>> refreshAllDevices({
|
||||
Duration? timeout,
|
||||
|
@ -122,7 +122,7 @@ void main() {
|
||||
expect(androidDevices.supportsPlatform, false);
|
||||
});
|
||||
|
||||
testWithoutContext('AndroidDevices can parse output for physical devices', () async {
|
||||
testWithoutContext('AndroidDevices can parse output for physical attached devices', () async {
|
||||
final AndroidDevices androidDevices = AndroidDevices(
|
||||
userMessages: UserMessages(),
|
||||
androidWorkflow: androidWorkflow,
|
||||
@ -147,6 +147,35 @@ List of devices attached
|
||||
expect(devices, hasLength(1));
|
||||
expect(devices.first.name, 'Nexus 7');
|
||||
expect(devices.first.category, Category.mobile);
|
||||
expect(devices.first.connectionInterface, DeviceConnectionInterface.attached);
|
||||
});
|
||||
|
||||
testWithoutContext('AndroidDevices can parse output for physical wireless devices', () async {
|
||||
final AndroidDevices androidDevices = AndroidDevices(
|
||||
userMessages: UserMessages(),
|
||||
androidWorkflow: androidWorkflow,
|
||||
androidSdk: FakeAndroidSdk(),
|
||||
logger: BufferLogger.test(),
|
||||
processManager: FakeProcessManager.list(<FakeCommand>[
|
||||
const FakeCommand(
|
||||
command: <String>['adb', 'devices', '-l'],
|
||||
stdout: '''
|
||||
List of devices attached
|
||||
05a02bac._adb-tls-connect._tcp. device product:razor model:Nexus_7 device:flo
|
||||
|
||||
''',
|
||||
),
|
||||
]),
|
||||
platform: FakePlatform(),
|
||||
fileSystem: MemoryFileSystem.test(),
|
||||
);
|
||||
|
||||
final List<Device> devices = await androidDevices.pollingGetDevices();
|
||||
|
||||
expect(devices, hasLength(1));
|
||||
expect(devices.first.name, 'Nexus 7');
|
||||
expect(devices.first.category, Category.mobile);
|
||||
expect(devices.first.connectionInterface, DeviceConnectionInterface.wireless);
|
||||
});
|
||||
|
||||
testWithoutContext('AndroidDevices can parse output for emulators and short listings', () async {
|
||||
|
@ -11,7 +11,6 @@ import 'package:flutter_tools/src/base/utils.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/convert.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
import 'package:test/fake.dart';
|
||||
|
||||
@ -832,7 +831,7 @@ void main() {
|
||||
EnvironmentType.physical,
|
||||
null,
|
||||
<String, Object?>{},
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
interfaceType: DeviceConnectionInterface.wireless,
|
||||
);
|
||||
|
||||
expect(
|
||||
@ -856,7 +855,7 @@ void main() {
|
||||
null,
|
||||
<String, Object?>{},
|
||||
ipv6: true,
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
interfaceType: DeviceConnectionInterface.wireless,
|
||||
);
|
||||
|
||||
expect(
|
||||
|
@ -74,7 +74,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
sdkVersion: '13.3',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
expect(device.isSupported(), isTrue);
|
||||
});
|
||||
@ -90,7 +90,7 @@ void main() {
|
||||
iMobileDevice: iMobileDevice,
|
||||
name: 'iPhone 1',
|
||||
cpuArchitecture: DarwinArch.armv7,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
expect(device.isSupported(), isFalse);
|
||||
});
|
||||
@ -107,7 +107,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
sdkVersion: '1.0.0',
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
).majorSdkVersion, 1);
|
||||
expect(IOSDevice(
|
||||
'device-123',
|
||||
@ -120,7 +120,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
sdkVersion: '13.1.1',
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
).majorSdkVersion, 13);
|
||||
expect(IOSDevice(
|
||||
'device-123',
|
||||
@ -133,7 +133,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
sdkVersion: '10',
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
).majorSdkVersion, 10);
|
||||
expect(IOSDevice(
|
||||
'device-123',
|
||||
@ -146,7 +146,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
sdkVersion: '0',
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
).majorSdkVersion, 0);
|
||||
expect(IOSDevice(
|
||||
'device-123',
|
||||
@ -159,7 +159,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
sdkVersion: 'bogus',
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
).majorSdkVersion, 0);
|
||||
});
|
||||
|
||||
@ -175,7 +175,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
sdkVersion: '13.3 17C54',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
|
||||
expect(await device.sdkNameAndVersion,'iOS 13.3 17C54');
|
||||
@ -193,7 +193,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
sdkVersion: '13.3',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
|
||||
expect(device.supportsRuntimeMode(BuildMode.debug), true);
|
||||
@ -217,7 +217,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
sdkVersion: '13.3',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
},
|
||||
throwsAssertionError,
|
||||
@ -307,7 +307,7 @@ void main() {
|
||||
name: 'iPhone 1',
|
||||
sdkVersion: '13.3',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
logReader1 = createLogReader(device, appPackage1, process1);
|
||||
logReader2 = createLogReader(device, appPackage2, process2);
|
||||
@ -368,7 +368,7 @@ void main() {
|
||||
logger: logger,
|
||||
platform: macPlatform,
|
||||
fileSystem: MemoryFileSystem.test(),
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
|
||||
device2 = IOSDevice(
|
||||
@ -382,7 +382,7 @@ void main() {
|
||||
logger: logger,
|
||||
platform: macPlatform,
|
||||
fileSystem: MemoryFileSystem.test(),
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
});
|
||||
|
||||
|
@ -12,8 +12,8 @@ import 'package:flutter_tools/src/base/file_system.dart';
|
||||
import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/ios/ios_deploy.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
|
||||
import '../../src/common.dart';
|
||||
import '../../src/fake_process_manager.dart';
|
||||
@ -73,7 +73,7 @@ void main () {
|
||||
bundlePath: '/',
|
||||
appDeltaDirectory: appDeltaDirectory,
|
||||
launchArguments: <String>['--enable-dart-profiling'],
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
interfaceType: DeviceConnectionInterface.wireless,
|
||||
uninstallFirst: true,
|
||||
);
|
||||
|
||||
|
@ -10,6 +10,7 @@ import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/ios/application_package.dart';
|
||||
import 'package:flutter_tools/src/ios/devices.dart';
|
||||
import 'package:flutter_tools/src/ios/ios_deploy.dart';
|
||||
@ -62,7 +63,7 @@ void main() {
|
||||
final IOSDevice device = setUpIOSDevice(
|
||||
processManager: processManager,
|
||||
fileSystem: fileSystem,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
interfaceType: DeviceConnectionInterface.attached,
|
||||
artifacts: artifacts,
|
||||
);
|
||||
final bool wasInstalled = await device.installApp(iosApp);
|
||||
@ -95,7 +96,7 @@ void main() {
|
||||
final IOSDevice device = setUpIOSDevice(
|
||||
processManager: processManager,
|
||||
fileSystem: fileSystem,
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
interfaceType: DeviceConnectionInterface.wireless,
|
||||
artifacts: artifacts,
|
||||
);
|
||||
final bool wasInstalled = await device.installApp(iosApp);
|
||||
@ -319,7 +320,7 @@ IOSDevice setUpIOSDevice({
|
||||
required ProcessManager processManager,
|
||||
FileSystem? fileSystem,
|
||||
Logger? logger,
|
||||
IOSDeviceConnectionInterface? interfaceType,
|
||||
DeviceConnectionInterface? interfaceType,
|
||||
Artifacts? artifacts,
|
||||
}) {
|
||||
logger ??= BufferLogger.test();
|
||||
@ -357,6 +358,6 @@ IOSDevice setUpIOSDevice({
|
||||
cache: cache,
|
||||
),
|
||||
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
||||
interfaceType: interfaceType ?? IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: interfaceType ?? DeviceConnectionInterface.attached,
|
||||
);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@ import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/ios/devices.dart';
|
||||
import 'package:flutter_tools/src/ios/ios_deploy.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
@ -98,6 +99,6 @@ IOSDevice setUpIOSDevice(FileSystem fileSystem) {
|
||||
sdkVersion: '13.3',
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
iProxy: IProxy.test(logger: logger, processManager: processManager),
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
}
|
||||
|
@ -337,7 +337,7 @@ IOSDevice setUpIOSDevice({
|
||||
cache: cache,
|
||||
),
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
interfaceType: IOSDeviceConnectionInterface.usb,
|
||||
connectionInterface: DeviceConnectionInterface.attached,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -250,7 +250,7 @@ void main() {
|
||||
processManager: processManager,
|
||||
fileSystem: fileSystem,
|
||||
logger: logger,
|
||||
interfaceType: IOSDeviceConnectionInterface.network,
|
||||
interfaceType: DeviceConnectionInterface.wireless,
|
||||
);
|
||||
final IOSApp iosApp = PrebuiltIOSApp(
|
||||
projectBundleId: 'app',
|
||||
@ -560,7 +560,7 @@ IOSDevice setUpIOSDevice({
|
||||
Logger? logger,
|
||||
ProcessManager? processManager,
|
||||
IOSDeploy? iosDeploy,
|
||||
IOSDeviceConnectionInterface interfaceType = IOSDeviceConnectionInterface.usb,
|
||||
DeviceConnectionInterface interfaceType = DeviceConnectionInterface.attached,
|
||||
}) {
|
||||
final Artifacts artifacts = Artifacts.test();
|
||||
final FakePlatform macPlatform = FakePlatform(
|
||||
@ -598,7 +598,7 @@ IOSDevice setUpIOSDevice({
|
||||
cache: cache,
|
||||
),
|
||||
cpuArchitecture: DarwinArch.arm64,
|
||||
interfaceType: interfaceType,
|
||||
connectionInterface: interfaceType,
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -10,8 +10,8 @@ import 'package:flutter_tools/src/base/logger.dart';
|
||||
import 'package:flutter_tools/src/base/process.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/ios/code_signing.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
import 'package:flutter_tools/src/ios/mac.dart';
|
||||
import 'package:flutter_tools/src/ios/xcresult.dart';
|
||||
import 'package:flutter_tools/src/project.dart';
|
||||
@ -77,7 +77,7 @@ void main() {
|
||||
expect(() async => iMobileDevice.takeScreenshot(
|
||||
outputFile,
|
||||
'1234',
|
||||
IOSDeviceConnectionInterface.usb,
|
||||
DeviceConnectionInterface.attached,
|
||||
), throwsA(anything));
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
});
|
||||
@ -100,7 +100,7 @@ void main() {
|
||||
await iMobileDevice.takeScreenshot(
|
||||
outputFile,
|
||||
'1234',
|
||||
IOSDeviceConnectionInterface.usb,
|
||||
DeviceConnectionInterface.attached,
|
||||
);
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
});
|
||||
@ -123,7 +123,7 @@ void main() {
|
||||
await iMobileDevice.takeScreenshot(
|
||||
outputFile,
|
||||
'1234',
|
||||
IOSDeviceConnectionInterface.network,
|
||||
DeviceConnectionInterface.wireless,
|
||||
);
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
});
|
||||
|
@ -11,6 +11,7 @@ import 'package:flutter_tools/src/base/platform.dart';
|
||||
import 'package:flutter_tools/src/base/version.dart';
|
||||
import 'package:flutter_tools/src/build_info.dart';
|
||||
import 'package:flutter_tools/src/cache.dart';
|
||||
import 'package:flutter_tools/src/device.dart';
|
||||
import 'package:flutter_tools/src/ios/devices.dart';
|
||||
import 'package:flutter_tools/src/ios/iproxy.dart';
|
||||
import 'package:flutter_tools/src/ios/xcodeproj.dart';
|
||||
@ -480,22 +481,31 @@ void main() {
|
||||
));
|
||||
final List<IOSDevice> devices = await xcdevice.getAvailableIOSDevices();
|
||||
expect(devices, hasLength(4));
|
||||
|
||||
expect(devices[0].id, '00008027-00192736010F802E');
|
||||
expect(devices[0].name, 'An iPhone (Space Gray)');
|
||||
expect(await devices[0].sdkNameAndVersion, 'iOS 13.3 17C54');
|
||||
expect(devices[0].cpuArchitecture, DarwinArch.arm64);
|
||||
expect(devices[0].connectionInterface, DeviceConnectionInterface.attached);
|
||||
|
||||
expect(devices[1].id, '98206e7a4afd4aedaff06e687594e089dede3c44');
|
||||
expect(devices[1].name, 'iPad 1');
|
||||
expect(await devices[1].sdkNameAndVersion, 'iOS 10.1 14C54');
|
||||
expect(devices[1].cpuArchitecture, DarwinArch.armv7);
|
||||
expect(devices[1].connectionInterface, DeviceConnectionInterface.attached);
|
||||
|
||||
expect(devices[2].id, '234234234234234234345445687594e089dede3c44');
|
||||
expect(devices[2].name, 'A networked iPad');
|
||||
expect(await devices[2].sdkNameAndVersion, 'iOS 10.1 14C54');
|
||||
expect(devices[2].cpuArchitecture, DarwinArch.arm64); // Defaults to arm64 for unknown architecture.
|
||||
expect(devices[2].connectionInterface, DeviceConnectionInterface.wireless);
|
||||
|
||||
expect(devices[3].id, 'f577a7903cc54959be2e34bc4f7f80b7009efcf4');
|
||||
expect(devices[3].name, 'iPad 2');
|
||||
expect(await devices[3].sdkNameAndVersion, 'iOS 10.1 14C54');
|
||||
expect(devices[3].cpuArchitecture, DarwinArch.arm64); // Defaults to arm64 for unknown architecture.
|
||||
expect(devices[3].connectionInterface, DeviceConnectionInterface.attached);
|
||||
|
||||
expect(fakeProcessManager, hasNoRemainingExpectations);
|
||||
}, overrides: <Type, Generator>{
|
||||
Platform: () => macPlatform,
|
||||
|
@ -705,15 +705,15 @@ void main() {
|
||||
});
|
||||
|
||||
testUsingContext('finds single device', () async {
|
||||
testDeviceManager.addDevice(device1);
|
||||
testDeviceManager.addAttachedDevice(device1);
|
||||
final DummyFlutterCommand flutterCommand = DummyFlutterCommand();
|
||||
final Device? device = await flutterCommand.findTargetDevice();
|
||||
expect(device, device1);
|
||||
});
|
||||
|
||||
testUsingContext('finds multiple devices', () async {
|
||||
testDeviceManager.addDevice(device1);
|
||||
testDeviceManager.addDevice(device2);
|
||||
testDeviceManager.addAttachedDevice(device1);
|
||||
testDeviceManager.addAttachedDevice(device2);
|
||||
testDeviceManager.specifiedDeviceId = 'all';
|
||||
final DummyFlutterCommand flutterCommand = DummyFlutterCommand();
|
||||
final Device? device = await flutterCommand.findTargetDevice();
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -181,7 +181,8 @@ void _printBufferedErrors(AppContext testContext) {
|
||||
}
|
||||
|
||||
class FakeDeviceManager implements DeviceManager {
|
||||
List<Device> devices = <Device>[];
|
||||
List<Device> attachedDevices = <Device>[];
|
||||
List<Device> wirelessDevices = <Device>[];
|
||||
|
||||
String? _specifiedDeviceId;
|
||||
|
||||
@ -209,20 +210,20 @@ class FakeDeviceManager implements DeviceManager {
|
||||
@override
|
||||
Future<List<Device>> getAllDevices({
|
||||
DeviceDiscoveryFilter? filter,
|
||||
}) async => devices;
|
||||
}) async => filteredDevices(filter);
|
||||
|
||||
@override
|
||||
Future<List<Device>> refreshAllDevices({
|
||||
Duration? timeout,
|
||||
DeviceDiscoveryFilter? filter,
|
||||
}) async => devices;
|
||||
}) async => filteredDevices(filter);
|
||||
|
||||
@override
|
||||
Future<List<Device>> getDevicesById(
|
||||
String deviceId, {
|
||||
DeviceDiscoveryFilter? filter,
|
||||
}) async {
|
||||
return devices.where((Device device) {
|
||||
return filteredDevices(filter).where((Device device) {
|
||||
return device.id == deviceId || device.id.startsWith(deviceId);
|
||||
}).toList();
|
||||
}
|
||||
@ -236,7 +237,8 @@ class FakeDeviceManager implements DeviceManager {
|
||||
: getAllDevices(filter: filter);
|
||||
}
|
||||
|
||||
void addDevice(Device device) => devices.add(device);
|
||||
void addAttachedDevice(Device device) => attachedDevices.add(device);
|
||||
void addWirelessDevice(Device device) => wirelessDevices.add(device);
|
||||
|
||||
@override
|
||||
bool get canListAnything => true;
|
||||
@ -257,6 +259,16 @@ class FakeDeviceManager implements DeviceManager {
|
||||
|
||||
@override
|
||||
Device? getSingleEphemeralDevice(List<Device> devices) => null;
|
||||
|
||||
List<Device> filteredDevices(DeviceDiscoveryFilter? filter) {
|
||||
if (filter?.deviceConnectionInterface == DeviceConnectionInterface.attached) {
|
||||
return attachedDevices;
|
||||
}
|
||||
if (filter?.deviceConnectionInterface == DeviceConnectionInterface.wireless) {
|
||||
return wirelessDevices;
|
||||
}
|
||||
return attachedDevices + wirelessDevices;
|
||||
}
|
||||
}
|
||||
|
||||
class TestDeviceDiscoverySupportFilter extends Fake implements DeviceDiscoverySupportFilter {
|
||||
|
@ -54,6 +54,31 @@ List<FakeDeviceJsonData> fakeDevices = <FakeDeviceJsonData>[
|
||||
},
|
||||
},
|
||||
),
|
||||
FakeDeviceJsonData(
|
||||
FakeDevice(
|
||||
'wireless android',
|
||||
'wireless-android',
|
||||
type: PlatformType.android,
|
||||
connectionInterface: DeviceConnectionInterface.wireless,
|
||||
),
|
||||
<String, Object>{
|
||||
'name': 'wireless android',
|
||||
'id': 'wireless-android',
|
||||
'isSupported': true,
|
||||
'targetPlatform': 'android-arm',
|
||||
'emulator': true,
|
||||
'sdk': 'Test SDK (1.2.3)',
|
||||
'capabilities': <String, Object>{
|
||||
'hotReload': true,
|
||||
'hotRestart': true,
|
||||
'screenshot': false,
|
||||
'fastStart': false,
|
||||
'flutterExit': true,
|
||||
'hardwareRendering': true,
|
||||
'startPaused': true,
|
||||
},
|
||||
}
|
||||
),
|
||||
];
|
||||
|
||||
/// Fake device to test `devices` command.
|
||||
|
Loading…
x
Reference in New Issue
Block a user