mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
320 lines
11 KiB
Dart
320 lines
11 KiB
Dart
// Copyright 2014 The Flutter Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
|
|
import '../base/common.dart';
|
|
import '../base/logger.dart';
|
|
import '../base/platform.dart';
|
|
import '../base/terminal.dart';
|
|
import '../base/utils.dart';
|
|
import '../convert.dart';
|
|
import '../device.dart';
|
|
import '../globals.dart' as globals;
|
|
import '../runner/flutter_command.dart';
|
|
|
|
class DevicesCommand extends FlutterCommand {
|
|
DevicesCommand({ bool verboseHelp = false }) {
|
|
argParser.addFlag('machine',
|
|
negatable: false,
|
|
help: 'Output device information in machine readable structured JSON format.',
|
|
);
|
|
argParser.addOption(
|
|
'timeout',
|
|
abbr: 't',
|
|
help: '(deprecated) This option has been replaced by "--${FlutterOptions.kDeviceTimeout}".',
|
|
hide: !verboseHelp,
|
|
);
|
|
usesDeviceTimeoutOption();
|
|
usesDeviceConnectionOption();
|
|
}
|
|
|
|
@override
|
|
final String name = 'devices';
|
|
|
|
@override
|
|
final String description = 'List all connected devices.';
|
|
|
|
@override
|
|
final String category = FlutterCommandCategory.tools;
|
|
|
|
@override
|
|
Duration? get deviceDiscoveryTimeout {
|
|
if (argResults?['timeout'] != null) {
|
|
final int? timeoutSeconds = int.tryParse(stringArg('timeout')!);
|
|
if (timeoutSeconds == null) {
|
|
throwToolExit('Could not parse -t/--timeout argument. It must be an integer.');
|
|
}
|
|
return Duration(seconds: timeoutSeconds);
|
|
}
|
|
return super.deviceDiscoveryTimeout;
|
|
}
|
|
|
|
@override
|
|
Future<void> validateCommand() {
|
|
if (argResults?['timeout'] != null) {
|
|
globals.printWarning('${globals.logger.terminal.warningMark} The "--timeout" argument is deprecated; use "--${FlutterOptions.kDeviceTimeout}" instead.');
|
|
}
|
|
return super.validateCommand();
|
|
}
|
|
|
|
@override
|
|
Future<FlutterCommandResult> runCommand() async {
|
|
if (globals.doctor?.canListAnything != true) {
|
|
throwToolExit(
|
|
"Unable to locate a development device; please run 'flutter doctor' for "
|
|
'information about installing additional components.',
|
|
exitCode: 1);
|
|
}
|
|
|
|
final DevicesCommandOutput output = DevicesCommandOutput(
|
|
platform: globals.platform,
|
|
logger: globals.logger,
|
|
deviceManager: globals.deviceManager,
|
|
deviceDiscoveryTimeout: deviceDiscoveryTimeout,
|
|
deviceConnectionInterface: deviceConnectionInterface,
|
|
);
|
|
|
|
await output.findAndOutputAllTargetDevices(
|
|
machine: boolArg('machine'),
|
|
);
|
|
|
|
return FlutterCommandResult.success();
|
|
}
|
|
}
|
|
|
|
class DevicesCommandOutput {
|
|
factory DevicesCommandOutput({
|
|
required Platform platform,
|
|
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,
|
|
);
|
|
}
|
|
|
|
DevicesCommandOutput._private({
|
|
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,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<List<Device>> _getWirelessDevices(DeviceManager deviceManager) async {
|
|
if (!_includeWirelessDevices) {
|
|
return <Device>[];
|
|
}
|
|
return deviceManager.getAllDevices(
|
|
filter: DeviceDiscoveryFilter(
|
|
deviceConnectionInterface: DeviceConnectionInterface.wireless,
|
|
),
|
|
);
|
|
}
|
|
|
|
Future<void> findAndOutputAllTargetDevices({required bool machine}) async {
|
|
List<Device> attachedDevices = <Device>[];
|
|
List<Device> wirelessDevices = <Device>[];
|
|
final DeviceManager? deviceManager = _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(allDevices);
|
|
return;
|
|
}
|
|
|
|
if (allDevices.isEmpty) {
|
|
_logger.printStatus('No authorized devices detected.');
|
|
} else {
|
|
if (attachedDevices.isNotEmpty) {
|
|
_logger.printStatus('Found ${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:');
|
|
await Device.printDevices(attachedDevices, _logger, prefix: ' ');
|
|
}
|
|
if (wirelessDevices.isNotEmpty) {
|
|
if (attachedDevices.isNotEmpty) {
|
|
_logger.printStatus('');
|
|
}
|
|
_logger.printStatus('Found ${wirelessDevices.length} wirelessly connected ${pluralize('device', wirelessDevices.length)}:');
|
|
await Device.printDevices(wirelessDevices, _logger, prefix: ' ');
|
|
}
|
|
}
|
|
await _printDiagnostics(foundAny: allDevices.isNotEmpty);
|
|
}
|
|
|
|
Future<void> _printDiagnostics({ required bool foundAny }) async {
|
|
final StringBuffer status = StringBuffer();
|
|
status.writeln();
|
|
final List<String> diagnostics = await _deviceManager?.getDeviceDiagnostics() ?? <String>[];
|
|
if (diagnostics.isNotEmpty) {
|
|
for (final String diagnostic in diagnostics) {
|
|
status.writeln(diagnostic);
|
|
status.writeln();
|
|
}
|
|
}
|
|
status.writeln('Run "flutter emulators" to list and start any available device emulators.');
|
|
status.writeln();
|
|
status.write('If you expected ${ foundAny ? 'another' : 'a' } device to be detected, please run "flutter doctor" to diagnose potential issues. ');
|
|
if (deviceDiscoveryTimeout == null) {
|
|
status.write('You may also try increasing the time to wait for connected devices with the "--${FlutterOptions.kDeviceTimeout}" flag. ');
|
|
}
|
|
status.write('Visit https://flutter.dev/setup/ for troubleshooting tips.');
|
|
_logger.printStatus(status.toString());
|
|
}
|
|
|
|
Future<void> printDevicesAsJson(List<Device> devices) async {
|
|
_logger.printStatus(
|
|
const JsonEncoder.withIndent(' ').convert(
|
|
await Future.wait(devices.map((Device d) => d.toJson()))
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
const String _checkingForWirelessDevicesMessage = 'Checking for wireless devices...';
|
|
const String _noAttachedCheckForWireless = 'No devices found yet. Checking for wireless devices...';
|
|
const String _noWirelessDevicesFoundMessage = 'No wireless devices were found.';
|
|
|
|
class DevicesCommandOutputWithExtendedWirelessDeviceDiscovery extends DevicesCommandOutput {
|
|
DevicesCommandOutputWithExtendedWirelessDeviceDiscovery({
|
|
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 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(
|
|
deviceConnectionInterface: deviceConnectionInterface,
|
|
),
|
|
timeout: DeviceManager.minimumWirelessDeviceDiscoveryTimeout,
|
|
) ?? <Device>[];
|
|
await printDevicesAsJson(devices);
|
|
return;
|
|
}
|
|
|
|
final Future<void>? extendedWirelessDiscovery = _deviceManager?.refreshExtendedWirelessDeviceDiscoverers(
|
|
timeout: DeviceManager.minimumWirelessDeviceDiscoveryTimeout,
|
|
);
|
|
|
|
List<Device> attachedDevices = <Device>[];
|
|
final DeviceManager? deviceManager = _deviceManager;
|
|
if (deviceManager != null) {
|
|
attachedDevices = await _getAttachedDevices(deviceManager);
|
|
}
|
|
|
|
// Number of lines to clear starts at 1 because it's inclusive of the line
|
|
// the cursor is on, which will be blank for this use case.
|
|
int numLinesToClear = 1;
|
|
|
|
// Display list of attached devices.
|
|
if (attachedDevices.isNotEmpty) {
|
|
_logger.printStatus('Found ${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:');
|
|
await Device.printDevices(attachedDevices, _logger, prefix: ' ');
|
|
_logger.printStatus('');
|
|
numLinesToClear += 1;
|
|
}
|
|
|
|
// Display waiting message.
|
|
if (attachedDevices.isEmpty && _includeAttachedDevices) {
|
|
_logger.printStatus(_noAttachedCheckForWireless);
|
|
} else {
|
|
_logger.printStatus(_checkingForWirelessDevicesMessage);
|
|
}
|
|
numLinesToClear += 1;
|
|
|
|
final Status waitingStatus = _logger.startSpinner();
|
|
await extendedWirelessDiscovery;
|
|
List<Device> wirelessDevices = <Device>[];
|
|
if (deviceManager != null) {
|
|
wirelessDevices = await _getWirelessDevices(deviceManager);
|
|
}
|
|
waitingStatus.stop();
|
|
|
|
final Terminal terminal = _logger.terminal;
|
|
if (_logger.isVerbose && _includeAttachedDevices) {
|
|
// Reprint the attach devices.
|
|
if (attachedDevices.isNotEmpty) {
|
|
_logger.printStatus('\nFound ${attachedDevices.length} connected ${pluralize('device', attachedDevices.length)}:');
|
|
await Device.printDevices(attachedDevices, _logger, prefix: ' ');
|
|
}
|
|
} else if (terminal.supportsColor && terminal is AnsiTerminal) {
|
|
_logger.printStatus(
|
|
terminal.clearLines(numLinesToClear),
|
|
newline: false,
|
|
);
|
|
}
|
|
|
|
if (attachedDevices.isNotEmpty || !_logger.terminal.supportsColor) {
|
|
_logger.printStatus('');
|
|
}
|
|
|
|
if (wirelessDevices.isEmpty) {
|
|
if (attachedDevices.isEmpty) {
|
|
// No wireless or attached devices were found.
|
|
_logger.printStatus('No authorized devices detected.');
|
|
} else {
|
|
// Attached devices found, wireless devices not found.
|
|
_logger.printStatus(_noWirelessDevicesFoundMessage);
|
|
}
|
|
} else {
|
|
// Display list of wireless devices.
|
|
_logger.printStatus('Found ${wirelessDevices.length} wirelessly connected ${pluralize('device', wirelessDevices.length)}:');
|
|
await Device.printDevices(wirelessDevices, _logger, prefix: ' ');
|
|
}
|
|
await _printDiagnostics(foundAny: wirelessDevices.isNotEmpty || attachedDevices.isNotEmpty);
|
|
}
|
|
}
|