Unverified Commit 6c8d7b00 authored by JustWe's avatar JustWe Committed by GitHub

Show unsupported devices when no supported devices are connected (#56531)

parent 91e7678f
...@@ -237,6 +237,9 @@ class UserMessages { ...@@ -237,6 +237,9 @@ class UserMessages {
"matching '$deviceId'"; "matching '$deviceId'";
String get flutterNoDevicesFound => 'No devices found'; String get flutterNoDevicesFound => 'No devices found';
String get flutterNoSupportedDevices => 'No supported devices connected.'; 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.';
String get flutterFoundButUnsupportedDevices => 'The following devices were found, but are not supported by this project:';
String flutterFoundSpecifiedDevices(int count, String deviceId) => String flutterFoundSpecifiedDevices(int count, String deviceId) =>
'Found $count devices with name or id matching $deviceId:'; 'Found $count devices with name or id matching $deviceId:';
String get flutterSpecifyDeviceWithAllOption => String get flutterSpecifyDeviceWithAllOption =>
......
...@@ -557,6 +557,13 @@ abstract class Device { ...@@ -557,6 +557,13 @@ abstract class Device {
await descriptions(devices).forEach(globals.printStatus); await descriptions(devices).forEach(globals.printStatus);
} }
static List<String> devicesPlatformTypes(List<Device> devices) {
return devices
.map(
(Device d) => d.platformType.toString(),
).toSet().toList()..sort();
}
/// Convert the Device object to a JSON representation suitable for serialization. /// Convert the Device object to a JSON representation suitable for serialization.
Future<Map<String, Object>> toJson() async { Future<Map<String, Object>> toJson() async {
final bool isLocalEmu = await isLocalEmulator; final bool isLocalEmu = await isLocalEmulator;
......
...@@ -823,11 +823,28 @@ abstract class FlutterCommand extends Command<void> { ...@@ -823,11 +823,28 @@ abstract class FlutterCommand extends Command<void> {
if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) { if (devices.isEmpty && deviceManager.hasSpecifiedDeviceId) {
globals.printStatus(userMessages.flutterNoMatchingDevice(deviceManager.specifiedDeviceId)); globals.printStatus(userMessages.flutterNoMatchingDevice(deviceManager.specifiedDeviceId));
return null; return null;
} else if (devices.isEmpty && deviceManager.hasSpecifiedAllDevices) {
globals.printStatus(userMessages.flutterNoDevicesFound);
return null;
} else if (devices.isEmpty) { } else if (devices.isEmpty) {
if (deviceManager.hasSpecifiedAllDevices) {
globals.printStatus(userMessages.flutterNoDevicesFound);
} else {
globals.printStatus(userMessages.flutterNoSupportedDevices); globals.printStatus(userMessages.flutterNoSupportedDevices);
}
final List<Device> unsupportedDevices = await deviceManager.getDevices();
if (unsupportedDevices.isNotEmpty) {
final StringBuffer result = StringBuffer();
result.writeln(userMessages.flutterFoundButUnsupportedDevices);
result.writeAll(
await Device.descriptions(unsupportedDevices)
.map((String desc) => desc)
.toList(),
'\n',
);
result.writeln('');
result.writeln(userMessages.flutterMissPlatformProjects(
Device.devicesPlatformTypes(unsupportedDevices),
));
globals.printStatus(result.toString());
}
return null; return null;
} else if (devices.length > 1 && !deviceManager.hasSpecifiedAllDevices) { } else if (devices.length > 1 && !deviceManager.hasSpecifiedAllDevices) {
if (deviceManager.hasSpecifiedDeviceId) { if (deviceManager.hasSpecifiedDeviceId) {
......
...@@ -38,6 +38,16 @@ void main() { ...@@ -38,6 +38,16 @@ void main() {
ProcessManager: () => MockProcessManager(), ProcessManager: () => MockProcessManager(),
}); });
testUsingContext('get devices\' platform types', () async {
final List<String> platformTypes = Device.devicesPlatformTypes(
await deviceManager.getAllConnectedDevices(),
);
expect(platformTypes, <String>['android', 'web']);
}, overrides: <Type, Generator>{
DeviceManager: () => _FakeDeviceManager(),
ProcessManager: () => MockProcessManager(),
});
testUsingContext('Outputs parsable JSON with --machine flag', () async { testUsingContext('Outputs parsable JSON with --machine flag', () async {
final DevicesCommand command = DevicesCommand(); final DevicesCommand command = DevicesCommand();
await createTestCommandRunner(command).run(<String>['devices', '--machine']); await createTestCommandRunner(command).run(<String>['devices', '--machine']);
......
...@@ -241,6 +241,62 @@ void main() { ...@@ -241,6 +241,62 @@ void main() {
ProcessManager: () => mockProcessManager, ProcessManager: () => mockProcessManager,
}); });
testUsingContext('shows unsupported devices when no supported devices are found', () async {
final RunCommand command = RunCommand();
applyMocksToCommand(command);
final MockDevice mockDevice = MockDevice(TargetPlatform.android_arm);
when(mockDevice.isLocalEmulator).thenAnswer((Invocation invocation) => Future<bool>.value(true));
when(mockDevice.isSupported()).thenAnswer((Invocation invocation) => true);
when(mockDevice.supportsFastStart).thenReturn(true);
when(mockDevice.id).thenReturn('mock-id');
when(mockDevice.name).thenReturn('mock-name');
when(mockDevice.platformType).thenReturn(PlatformType.android);
when(mockDevice.sdkNameAndVersion).thenAnswer((Invocation invocation) => Future<String>.value('api-14'));
when(mockDeviceManager.getDevices()).thenAnswer((Invocation invocation) {
return Future<List<Device>>.value(<Device>[
mockDevice,
]);
});
when(mockDeviceManager.findTargetDevices(any)).thenAnswer(
(Invocation invocation) => Future<List<Device>>.value(<Device>[]),
);
try {
await createTestCommandRunner(command).run(<String>[
'run',
'--no-pub',
'--no-hot',
]);
fail('Expect exception');
} on ToolExit catch (e) {
expect(e.message, null);
}
expect(
testLogger.statusText,
containsIgnoringWhitespace(userMessages.flutterNoSupportedDevices),
);
expect(
testLogger.statusText,
containsIgnoringWhitespace(userMessages.flutterFoundButUnsupportedDevices),
);
expect(
testLogger.statusText,
containsIgnoringWhitespace(
userMessages.flutterMissPlatformProjects(
Device.devicesPlatformTypes(<Device>[mockDevice]),
),
),
);
}, overrides: <Type, Generator>{
DeviceManager: () => mockDeviceManager,
FileSystem: () => fs,
ProcessManager: () => mockProcessManager,
});
testUsingContext('updates cache before checking for devices', () async { testUsingContext('updates cache before checking for devices', () async {
final RunCommand command = RunCommand(); final RunCommand command = RunCommand();
applyMocksToCommand(command); applyMocksToCommand(command);
......
...@@ -11,7 +11,7 @@ import 'package:flutter_tools/src/project.dart'; ...@@ -11,7 +11,7 @@ import 'package:flutter_tools/src/project.dart';
/// (`Device.toJson()` and `--machine` flag for `devices` command) /// (`Device.toJson()` and `--machine` flag for `devices` command)
List<FakeDeviceJsonData> fakeDevices = <FakeDeviceJsonData>[ List<FakeDeviceJsonData> fakeDevices = <FakeDeviceJsonData>[
FakeDeviceJsonData( FakeDeviceJsonData(
FakeDevice('ephemeral', 'ephemeral', true), FakeDevice('ephemeral', 'ephemeral', true, true, PlatformType.android),
<String, Object>{ <String, Object>{
'name': 'ephemeral', 'name': 'ephemeral',
'id': 'ephemeral', 'id': 'ephemeral',
...@@ -56,9 +56,9 @@ List<FakeDeviceJsonData> fakeDevices = <FakeDeviceJsonData>[ ...@@ -56,9 +56,9 @@ List<FakeDeviceJsonData> fakeDevices = <FakeDeviceJsonData>[
/// Fake device to test `devices` command /// Fake device to test `devices` command
class FakeDevice extends Device { class FakeDevice extends Device {
FakeDevice(this.name, String id, [bool ephemeral = true, this._isSupported = true]) : super( FakeDevice(this.name, String id, [bool ephemeral = true, this._isSupported = true, PlatformType type = PlatformType.web]) : super(
id, id,
platformType: PlatformType.web, platformType: type,
category: Category.mobile, category: Category.mobile,
ephemeral: ephemeral, ephemeral: ephemeral,
); );
......
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