Unverified Commit dbc18bbd authored by Victoria Ashworth's avatar Victoria Ashworth Committed by GitHub

Add flag to filter by device connection interface (#124034)

Add flag to filter by device connection interface
parent b2c65acd
......@@ -140,6 +140,7 @@ class AttachCommand extends FlutterCommand {
addDevToolsOptions(verboseHelp: verboseHelp);
addServeObservatoryOptions(verboseHelp: verboseHelp);
usesDeviceTimeoutOption();
usesDeviceConnectionOption();
}
final HotRunnerFactory _hotRunnerFactory;
......
......@@ -25,6 +25,7 @@ class DevicesCommand extends FlutterCommand {
hide: !verboseHelp,
);
usesDeviceTimeoutOption();
usesDeviceConnectionOption();
}
@override
......@@ -70,6 +71,7 @@ class DevicesCommand extends FlutterCommand {
logger: globals.logger,
deviceManager: globals.deviceManager,
deviceDiscoveryTimeout: deviceDiscoveryTimeout,
deviceConnectionInterface: deviceConnectionInterface,
);
await output.findAndOutputAllTargetDevices(
......@@ -86,18 +88,21 @@ class DevicesCommandOutput {
required Logger logger,
DeviceManager? deviceManager,
Duration? deviceDiscoveryTimeout,
DeviceConnectionInterface? deviceConnectionInterface,
}) {
if (platform.isMacOS) {
return DevicesCommandOutputWithExtendedWirelessDeviceDiscovery(
logger: logger,
deviceManager: deviceManager,
deviceDiscoveryTimeout: deviceDiscoveryTimeout,
deviceConnectionInterface: deviceConnectionInterface,
);
}
return DevicesCommandOutput._private(
logger: logger,
deviceManager: deviceManager,
deviceDiscoveryTimeout: deviceDiscoveryTimeout,
deviceConnectionInterface: deviceConnectionInterface,
);
}
......@@ -105,14 +110,27 @@ class DevicesCommandOutput {
required Logger logger,
required DeviceManager? deviceManager,
required this.deviceDiscoveryTimeout,
required this.deviceConnectionInterface,
}) : _deviceManager = deviceManager,
_logger = logger;
final DeviceManager? _deviceManager;
final Logger _logger;
final Duration? deviceDiscoveryTimeout;
final DeviceConnectionInterface? deviceConnectionInterface;
bool get _includeAttachedDevices =>
deviceConnectionInterface == null ||
deviceConnectionInterface == DeviceConnectionInterface.attached;
bool get _includeWirelessDevices =>
deviceConnectionInterface == null ||
deviceConnectionInterface == DeviceConnectionInterface.wireless;
Future<List<Device>> _getAttachedDevices(DeviceManager deviceManager) async {
if (!_includeAttachedDevices) {
return <Device>[];
}
return deviceManager.getAllDevices(
filter: DeviceDiscoveryFilter(
deviceConnectionInterface: DeviceConnectionInterface.attached,
......@@ -121,6 +139,9 @@ class DevicesCommandOutput {
}
Future<List<Device>> _getWirelessDevices(DeviceManager deviceManager) async {
if (!_includeWirelessDevices) {
return <Device>[];
}
return deviceManager.getAllDevices(
filter: DeviceDiscoveryFilter(
deviceConnectionInterface: DeviceConnectionInterface.wireless,
......@@ -207,19 +228,22 @@ class DevicesCommandOutputWithExtendedWirelessDeviceDiscovery extends DevicesCom
required super.logger,
super.deviceManager,
super.deviceDiscoveryTimeout,
super.deviceConnectionInterface,
}) : super._private();
@override
Future<void> findAndOutputAllTargetDevices({required bool machine}) async {
// When a user defines the timeout, use the super function that does not do
// longer wireless device discovery.
if (deviceDiscoveryTimeout != null) {
// When a user defines the timeout or filters to only attached devices,
// use the super function that does not do longer wireless device discovery.
if (deviceDiscoveryTimeout != null || deviceConnectionInterface == DeviceConnectionInterface.attached) {
return super.findAndOutputAllTargetDevices(machine: machine);
}
if (machine) {
final List<Device> devices = await _deviceManager?.refreshAllDevices(
filter: DeviceDiscoveryFilter(),
filter: DeviceDiscoveryFilter(
deviceConnectionInterface: deviceConnectionInterface,
),
timeout: DeviceManager.minimumWirelessDeviceDiscoveryTimeout,
) ?? <Device>[];
await printDevicesAsJson(devices);
......@@ -249,7 +273,7 @@ class DevicesCommandOutputWithExtendedWirelessDeviceDiscovery extends DevicesCom
}
// Display waiting message.
if (attachedDevices.isEmpty) {
if (attachedDevices.isEmpty && _includeAttachedDevices) {
_logger.printStatus(_noAttachedCheckForWireless);
} else {
_logger.printStatus(_checkingForWirelessDevicesMessage);
......@@ -265,7 +289,7 @@ class DevicesCommandOutputWithExtendedWirelessDeviceDiscovery extends DevicesCom
waitingStatus.stop();
final Terminal terminal = _logger.terminal;
if (_logger.isVerbose) {
if (_logger.isVerbose && _includeAttachedDevices) {
// Reprint the attach devices.
if (attachedDevices.isNotEmpty) {
_logger.printStatus('\n${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:\n');
......
......@@ -19,6 +19,7 @@ class InstallCommand extends FlutterCommand with DeviceBasedDevelopmentArtifacts
requiresPubspecYaml();
usesApplicationBinaryOption();
usesDeviceTimeoutOption();
usesDeviceConnectionOption();
usesDeviceUserOption();
usesFlavorOption();
argParser.addFlag('uninstall-only',
......
......@@ -19,6 +19,7 @@ class LogsCommand extends FlutterCommand {
help: 'Clear log history before reading from logs.',
);
usesDeviceTimeoutOption();
usesDeviceConnectionOption();
}
@override
......
......@@ -177,6 +177,7 @@ abstract class RunCommandBase extends FlutterCommand with DeviceBasedDevelopment
addNullSafetyModeOptions(hide: !verboseHelp);
usesDeviceUserOption();
usesDeviceTimeoutOption();
usesDeviceConnectionOption();
addDdsOptions(verboseHelp: verboseHelp);
addDevToolsOptions(verboseHelp: verboseHelp);
addServeObservatoryOptions(verboseHelp: verboseHelp);
......
......@@ -52,6 +52,7 @@ class ScreenshotCommand extends FlutterCommand {
defaultsTo: _kDeviceType,
);
usesDeviceTimeoutOption();
usesDeviceConnectionOption();
}
final FileSystem fs;
......
......@@ -112,6 +112,7 @@ class FlutterOptions {
static const String kNullSafety = 'sound-null-safety';
static const String kDeviceUser = 'device-user';
static const String kDeviceTimeout = 'device-timeout';
static const String kDeviceConnection = 'device-connection';
static const String kAnalyzeSize = 'analyze-size';
static const String kCodeSizeDirectory = 'code-size-directory';
static const String kNullAssertions = 'null-assertions';
......@@ -694,6 +695,19 @@ abstract class FlutterCommand extends Command<void> {
);
}
void usesDeviceConnectionOption() {
argParser.addOption(FlutterOptions.kDeviceConnection,
defaultsTo: 'both',
help: 'Discover devices based on connection type.',
allowed: <String>['attached', 'wireless', 'both'],
allowedHelp: <String, String>{
'both': 'Searches for both attached and wireless devices.',
'attached': 'Only searches for devices connected by USB or built-in (such as simulators/emulators, MacOS/Windows, Chrome)',
'wireless': 'Only searches for devices connected wirelessly. Discovering wireless devices may take longer.'
},
);
}
void usesApplicationBinaryOption() {
argParser.addOption(
FlutterOptions.kUseApplicationBinary,
......@@ -722,10 +736,24 @@ abstract class FlutterCommand extends Command<void> {
return null;
}();
DeviceConnectionInterface? get deviceConnectionInterface {
if ((argResults?.options.contains(FlutterOptions.kDeviceConnection) ?? false)
&& (argResults?.wasParsed(FlutterOptions.kDeviceConnection) ?? false)) {
final String? connectionType = stringArg(FlutterOptions.kDeviceConnection);
if (connectionType == 'attached') {
return DeviceConnectionInterface.attached;
} else if (connectionType == 'wireless') {
return DeviceConnectionInterface.wireless;
}
}
return null;
}
late final TargetDevices _targetDevices = TargetDevices(
platform: globals.platform,
deviceManager: globals.deviceManager!,
logger: globals.logger,
deviceConnectionInterface: deviceConnectionInterface,
);
void addBuildModeFlags({
......
......@@ -31,31 +31,46 @@ class TargetDevices {
required Platform platform,
required DeviceManager deviceManager,
required Logger logger,
DeviceConnectionInterface? deviceConnectionInterface,
}) {
if (platform.isMacOS) {
return TargetDevicesWithExtendedWirelessDeviceDiscovery(
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: deviceConnectionInterface,
);
}
return TargetDevices._private(
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: deviceConnectionInterface,
);
}
TargetDevices._private({
required DeviceManager deviceManager,
required Logger logger,
required this.deviceConnectionInterface,
}) : _deviceManager = deviceManager,
_logger = logger;
final DeviceManager _deviceManager;
final Logger _logger;
final DeviceConnectionInterface? deviceConnectionInterface;
bool get _includeAttachedDevices =>
deviceConnectionInterface == null ||
deviceConnectionInterface == DeviceConnectionInterface.attached;
bool get _includeWirelessDevices =>
deviceConnectionInterface == null ||
deviceConnectionInterface == DeviceConnectionInterface.wireless;
Future<List<Device>> _getAttachedDevices({
DeviceDiscoverySupportFilter? supportFilter,
}) async {
if (!_includeAttachedDevices) {
return <Device>[];
}
return _deviceManager.getDevices(
filter: DeviceDiscoveryFilter(
deviceConnectionInterface: DeviceConnectionInterface.attached,
......@@ -67,6 +82,9 @@ class TargetDevices {
Future<List<Device>> _getWirelessDevices({
DeviceDiscoverySupportFilter? supportFilter,
}) async {
if (!_includeWirelessDevices) {
return <Device>[];
}
return _deviceManager.getDevices(
filter: DeviceDiscoveryFilter(
deviceConnectionInterface: DeviceConnectionInterface.wireless,
......@@ -85,6 +103,7 @@ class TargetDevices {
supportFilter: _deviceManager.deviceSupportFilter(
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
),
deviceConnectionInterface: deviceConnectionInterface,
),
);
}
......@@ -166,7 +185,11 @@ class TargetDevices {
/// unsupported devices found.
Future<List<Device>?> _handleNoDevices() async {
// Get connected devices from cache, including unsupported ones.
final List<Device> unsupportedDevices = await _deviceManager.getAllDevices();
final List<Device> unsupportedDevices = await _deviceManager.getAllDevices(
filter: DeviceDiscoveryFilter(
deviceConnectionInterface: deviceConnectionInterface,
)
);
if (_deviceManager.hasSpecifiedDeviceId) {
_logger.printStatus(
......@@ -344,6 +367,7 @@ class TargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices {
TargetDevicesWithExtendedWirelessDeviceDiscovery({
required super.deviceManager,
required super.logger,
super.deviceConnectionInterface,
}) : super._private();
Future<void>? _wirelessDevicesRefresh;
......@@ -358,7 +382,7 @@ class TargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices {
void startExtendedWirelessDeviceDiscovery({
Duration? deviceDiscoveryTimeout,
}) {
if (deviceDiscoveryTimeout == null) {
if (deviceDiscoveryTimeout == null && _includeWirelessDevices) {
_wirelessDevicesRefresh ??= _deviceManager.refreshExtendedWirelessDeviceDiscoverers(
timeout: DeviceManager.minimumWirelessDeviceDiscoveryTimeout,
);
......@@ -369,6 +393,9 @@ class TargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices {
Future<List<Device>> _getRefreshedWirelessDevices({
bool includeDevicesUnsupportedByProject = false,
}) async {
if (!_includeWirelessDevices) {
return <Device>[];
}
startExtendedWirelessDeviceDiscovery();
return () async {
await _wirelessDevicesRefresh;
......@@ -428,9 +455,10 @@ class TargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices {
return null;
}
// When a user defines the timeout, use the super function that does not do
// longer wireless device discovery and does not wait for devices to connect.
if (deviceDiscoveryTimeout != null) {
// When a user defines the timeout or filters to only attached devices,
// use the super function that does not do longer wireless device
// discovery and does not wait for devices to connect.
if (deviceDiscoveryTimeout != null || deviceConnectionInterface == DeviceConnectionInterface.attached) {
return super.findAllTargetDevices(
deviceDiscoveryTimeout: deviceDiscoveryTimeout,
includeDevicesUnsupportedByProject: includeDevicesUnsupportedByProject,
......@@ -497,7 +525,11 @@ class TargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices {
List<Device> attachedDevices,
Future<List<Device>> futureWirelessDevices,
) async {
_logger.printStatus(_noAttachedCheckForWireless);
if (_includeAttachedDevices) {
_logger.printStatus(_noAttachedCheckForWireless);
} else {
_logger.printStatus(_checkingForWirelessDevicesMessage);
}
final List<Device> wirelessDevices = await futureWirelessDevices;
final List<Device> allDevices = attachedDevices + wirelessDevices;
......
......@@ -217,6 +217,48 @@ If you would like your app to run on android, consider running `flutter create .
expect(deviceManager.androidDiscoverer.discoverDevicesCalled, 0);
expect(deviceManager.androidDiscoverer.numberOfTimesPolled, 1);
});
group('when deviceConnectionInterface does not match', () {
testUsingContext('filter of wireless', () async {
deviceManager.androidDiscoverer.deviceList = <Device>[attachedAndroidDevice1];
final TargetDevices targetDevices = TargetDevices(
platform: platform,
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: DeviceConnectionInterface.wireless,
);
final List<Device>? devices = await targetDevices.findAllTargetDevices();
expect(logger.statusText, equals('''
No supported devices connected.
'''));
expect(devices, isNull);
expect(deviceManager.androidDiscoverer.devicesCalled, 2);
expect(deviceManager.androidDiscoverer.discoverDevicesCalled, 0);
expect(deviceManager.androidDiscoverer.numberOfTimesPolled, 1);
});
testUsingContext('filter of attached', () async {
deviceManager.androidDiscoverer.deviceList = <Device>[wirelessAndroidDevice1];
final TargetDevices targetDevices = TargetDevices(
platform: platform,
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: DeviceConnectionInterface.attached,
);
final List<Device>? devices = await targetDevices.findAllTargetDevices();
expect(logger.statusText, equals('''
No supported devices connected.
'''));
expect(devices, isNull);
expect(deviceManager.androidDiscoverer.devicesCalled, 2);
expect(deviceManager.androidDiscoverer.discoverDevicesCalled, 0);
expect(deviceManager.androidDiscoverer.numberOfTimesPolled, 1);
});
});
});
group('with hasSpecifiedDeviceId', () {
......@@ -272,6 +314,58 @@ target-device (mobile) • xxx • android • Android 10 (unsupported)
expect(deviceManager.androidDiscoverer.discoverDevicesCalled, 0);
expect(deviceManager.androidDiscoverer.numberOfTimesPolled, 1);
});
group('when deviceConnectionInterface does not match', () {
testUsingContext('filter of wireless', () async {
final FakeDevice device1 = FakeDevice(deviceName: 'not-a-match');
final FakeDevice device2 = FakeDevice.wireless(deviceName: 'not-a-match-2');
deviceManager.androidDiscoverer.deviceList = <Device>[exactMatchAndroidDevice, device1, device2];
final TargetDevices targetDevices = TargetDevices(
platform: platform,
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: DeviceConnectionInterface.wireless,
);
final List<Device>? devices = await targetDevices.findAllTargetDevices();
expect(logger.statusText, equals('''
No supported devices found with name or id matching 'target-device'.
The following devices were found:
not-a-match-2 (mobile) • xxx • android • Android 10
'''));
expect(devices, isNull);
expect(deviceManager.androidDiscoverer.devicesCalled, 3);
expect(deviceManager.androidDiscoverer.discoverDevicesCalled, 0);
expect(deviceManager.androidDiscoverer.numberOfTimesPolled, 1);
});
testUsingContext('filter of attached', () async {
final FakeDevice device1 = FakeDevice(deviceName: 'not-a-match');
final FakeDevice device2 = FakeDevice.wireless(deviceName: 'not-a-match-2');
deviceManager.androidDiscoverer.deviceList = <Device>[exactMatchWirelessAndroidDevice, device1, device2];
final TargetDevices targetDevices = TargetDevices(
platform: platform,
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: DeviceConnectionInterface.attached,
);
final List<Device>? devices = await targetDevices.findAllTargetDevices();
expect(logger.statusText, equals('''
No supported devices found with name or id matching 'target-device'.
The following devices were found:
not-a-match (mobile) • xxx • android • Android 10
'''));
expect(devices, isNull);
expect(deviceManager.androidDiscoverer.devicesCalled, 3);
expect(deviceManager.androidDiscoverer.discoverDevicesCalled, 0);
expect(deviceManager.androidDiscoverer.numberOfTimesPolled, 1);
});
});
});
group('with hasSpecifiedAllDevices', () {
......@@ -944,6 +1038,28 @@ Unable to locate a development device; please run 'flutter doctor' for informati
expect(deviceManager.iosDiscoverer.numberOfTimesPolled, 1);
});
testUsingContext('ensure no refresh when deviceConnectionInterface is attached', () async {
final BufferLogger logger = BufferLogger.test();
final TestDeviceManager deviceManager = TestDeviceManager(
logger: logger,
platform: platform,
);
deviceManager.iosDiscoverer.deviceList = <Device>[attachedIOSDevice1];
final TargetDevicesWithExtendedWirelessDeviceDiscovery targetDevices = TargetDevicesWithExtendedWirelessDeviceDiscovery(
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: DeviceConnectionInterface.attached,
);
final List<Device>? devices = await targetDevices.findAllTargetDevices();
expect(logger.statusText, equals(''));
expect(devices, <Device>[attachedIOSDevice1]);
expect(deviceManager.iosDiscoverer.devicesCalled, 1);
expect(deviceManager.iosDiscoverer.discoverDevicesCalled, 0);
expect(deviceManager.iosDiscoverer.numberOfTimesPolled, 1);
});
testUsingContext('ensure unsupported for projects are included when includeDevicesUnsupportedByProject is true', () async {
final BufferLogger logger = BufferLogger.test();
final TestDeviceManager deviceManager = TestDeviceManager(
......@@ -1055,6 +1171,30 @@ No supported devices connected.
expect(deviceManager.iosDiscoverer.discoverDevicesCalled, 1);
expect(deviceManager.iosDiscoverer.numberOfTimesPolled, 2);
});
group('when deviceConnectionInterface does not match', () {
testUsingContext('filter of wireless', () async {
deviceManager.iosDiscoverer.deviceList = <Device>[attachedIOSDevice1];
deviceManager.iosDiscoverer.refreshDeviceList = <Device>[attachedIOSDevice1];
final TestTargetDevicesWithExtendedWirelessDeviceDiscovery targetDevices = TestTargetDevicesWithExtendedWirelessDeviceDiscovery(
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: DeviceConnectionInterface.wireless,
);
final List<Device>? devices = await targetDevices.findAllTargetDevices();
expect(logger.statusText, equals('''
Checking for wireless devices...
No supported devices connected.
'''));
expect(devices, isNull);
expect(deviceManager.iosDiscoverer.devicesCalled, 2);
expect(deviceManager.iosDiscoverer.discoverDevicesCalled, 1);
expect(deviceManager.iosDiscoverer.numberOfTimesPolled, 1);
});
});
});
group('with hasSpecifiedDeviceId', () {
......@@ -1121,6 +1261,35 @@ target-device (mobile) • xxx • ios • iOS 16 (unsupported)
expect(deviceManager.iosDiscoverer.numberOfTimesPolled, 2);
expect(deviceManager.iosDiscoverer.xcdevice.waitedForDeviceToConnect, isFalse);
});
group('when deviceConnectionInterface does not match', () {
testUsingContext('filter of wireless', () async {
final FakeIOSDevice device1 = FakeIOSDevice.notConnectedWireless(deviceName: 'not-a-match');
final FakeIOSDevice device1Connected = FakeIOSDevice.connectedWireless(deviceName: 'not-a-match');
deviceManager.iosDiscoverer.deviceList = <Device>[exactMatchAttachedIOSDevice, device1];
deviceManager.iosDiscoverer.refreshDeviceList = <Device>[exactMatchAttachedIOSDevice, device1Connected];
final TestTargetDevicesWithExtendedWirelessDeviceDiscovery targetDevices = TestTargetDevicesWithExtendedWirelessDeviceDiscovery(
deviceManager: deviceManager,
logger: logger,
deviceConnectionInterface: DeviceConnectionInterface.wireless,
);
final List<Device>? devices = await targetDevices.findAllTargetDevices();
expect(logger.statusText, equals('''
Checking for wireless devices...
No supported devices found with name or id matching 'target-device'.
The following devices were found:
not-a-match (mobile) • xxx • ios • iOS 16
'''));
expect(devices, isNull);
expect(deviceManager.iosDiscoverer.devicesCalled, 3);
expect(deviceManager.iosDiscoverer.discoverDevicesCalled, 1);
expect(deviceManager.iosDiscoverer.numberOfTimesPolled, 2);
});
});
});
group('with hasSpecifiedAllDevices', () {
......@@ -2223,6 +2392,7 @@ class TestTargetDevicesWithExtendedWirelessDeviceDiscovery extends TargetDevices
TestTargetDevicesWithExtendedWirelessDeviceDiscovery({
required super.deviceManager,
required super.logger,
super.deviceConnectionInterface,
}) : _deviceSelection = TestTargetDeviceSelection(logger);
final TestTargetDeviceSelection _deviceSelection;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment