Show Mac Designed For iPad in 'flutter devices' (#141718)

Addresses https://github.com/flutter/flutter/issues/141290 by allow Mac Designed For IPad Devices to appear with 'flutter devices'.

<img width="573" alt="Screenshot 2024-01-29 at 12 23 24 AM" src="https://github.com/flutter/flutter/assets/36148254/35709a93-56fc-44c9-98d5-cf45afce967d">
<img width="725" alt="Screenshot 2024-01-29 at 12 26 01 AM" src="https://github.com/flutter/flutter/assets/36148254/b6cbcfce-44db-42c6-ac01-0ab716d30373">
This commit is contained in:
LouiseHsu 2024-01-31 11:34:07 -08:00 committed by GitHub
parent 071830663a
commit 42317804ee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 104 additions and 27 deletions

View file

@ -213,9 +213,6 @@ known, it can be explicitly provided to attach via the command-line, e.g.
@override
Future<void> validateCommand() async {
// ARM macOS as an iOS target is hidden, except for attach.
MacOSDesignedForIPadDevices.allowDiscovery = true;
await super.validateCommand();
final Device? targetDevice = await findTargetDevice();

View file

@ -25,6 +25,7 @@ import '../drive/drive_service.dart';
import '../drive/web_driver_service.dart' show Browser;
import '../globals.dart' as globals;
import '../ios/devices.dart';
import '../macos/macos_ipad_device.dart';
import '../resident_runner.dart';
import '../runner/flutter_command.dart' show FlutterCommandCategory, FlutterCommandResult, FlutterOptions;
import '../web/web_device.dart';
@ -222,6 +223,9 @@ class DriveCommand extends RunCommandBase {
if (device is! AndroidDevice) {
throwToolExit('--${FlutterOptions.kDeviceUser} is only supported for Android');
}
if (device is MacOSDesignedForIPadDevice) {
throwToolExit('Mac Designed for iPad is currently not supported for flutter drive.');
}
}
return super.validateCommand();
}

View file

@ -19,6 +19,7 @@ import '../device.dart';
import '../features.dart';
import '../globals.dart' as globals;
import '../ios/devices.dart';
import '../macos/macos_ipad_device.dart';
import '../project.dart';
import '../reporting/reporting.dart';
import '../resident_runner.dart';
@ -591,6 +592,15 @@ class RunCommand extends RunCommandBase {
if (devices == null) {
throwToolExit(null);
}
if (devices!.length == 1 && devices!.first is MacOSDesignedForIPadDevice) {
throwToolExit('Mac Designed for iPad is currently not supported for flutter run -d.');
}
if (globals.deviceManager!.hasSpecifiedAllDevices) {
devices?.removeWhere((Device device) => device is MacOSDesignedForIPadDevice);
}
if (globals.deviceManager!.hasSpecifiedAllDevices && runningWithPrebuiltApplication) {
throwToolExit('Using "-d all" with "--${FlutterOptions.kUseApplicationBinary}" is not supported');
}

View file

@ -28,7 +28,7 @@ class MacOSDesignedForIPadDevice extends DesktopDevice {
required OperatingSystemUtils operatingSystemUtils,
}) : _operatingSystemUtils = operatingSystemUtils,
super(
'designed-for-ipad',
'mac-designed-for-ipad',
platformType: PlatformType.macos,
ephemeral: false,
processManager: processManager,
@ -120,10 +120,7 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery {
/// and discovery is allowed for this command.
@override
bool get canListAnything =>
_iosWorkflow.canListDevices && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64 && allowDiscovery;
/// Set to show ARM macOS as an iOS device target.
static bool allowDiscovery = false;
_iosWorkflow.canListDevices && _operatingSystemUtils.hostPlatform == HostPlatform.darwin_arm64;
@override
Future<List<Device>> pollingGetDevices({Duration? timeout}) async {
@ -144,5 +141,5 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery {
Future<List<String>> getDiagnostics() async => const <String>[];
@override
List<String> get wellKnownIds => const <String>['designed-for-ipad'];
List<String> get wellKnownIds => const <String>['mac-designed-for-ipad'];
}

View file

@ -24,7 +24,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/macos/macos_ipad_device.dart';
import 'package:flutter_tools/src/mdns_discovery.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
@ -52,10 +51,6 @@ class FakeProcessInfo extends Fake implements ProcessInfo {
}
void main() {
tearDown(() {
MacOSDesignedForIPadDevices.allowDiscovery = false;
});
group('attach', () {
late StreamLogger logger;
late FileSystem testFileSystem;
@ -1067,7 +1062,6 @@ void main() {
expect(testLogger.statusText, containsIgnoringWhitespace('More than one device'));
expect(testLogger.statusText, contains('xx1'));
expect(testLogger.statusText, contains('yy2'));
expect(MacOSDesignedForIPadDevices.allowDiscovery, isTrue);
}, overrides: <Type, Generator>{
FileSystem: () => testFileSystem,
ProcessManager: () => FakeProcessManager.any(),

View file

@ -25,6 +25,7 @@ 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/macos/macos_ipad_device.dart';
import 'package:flutter_tools/src/project.dart';
import 'package:flutter_tools/src/reporting/reporting.dart';
import 'package:flutter_tools/src/resident_runner.dart';
@ -242,6 +243,62 @@ void main() {
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
});
testUsingContext('Using flutter run -d with MacOSDesignedForIPadDevices throws an error', () async {
final RunCommand command = RunCommand();
testDeviceManager.devices = <Device>[FakeMacDesignedForIpadDevice()];
await expectLater(
() => createTestCommandRunner(command).run(<String>[
'run',
'-d',
'mac-designed-for-ipad',
]), throwsToolExit(message: 'Mac Designed for iPad is currently not supported for flutter run -d'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
DeviceManager: () => testDeviceManager,
Stdio: () => FakeStdio(),
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
});
testUsingContext('Using flutter run -d all with a single MacOSDesignedForIPadDevices throws a tool error', () async {
final RunCommand command = RunCommand();
testDeviceManager.devices = <Device>[FakeMacDesignedForIpadDevice()];
await expectLater(
() => createTestCommandRunner(command).run(<String>[
'run',
'-d',
'all',
]), throwsToolExit(message: 'Mac Designed for iPad is currently not supported for flutter run -d'));
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
DeviceManager: () => testDeviceManager,
Stdio: () => FakeStdio(),
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
});
testUsingContext('Using flutter run -d all with MacOSDesignedForIPadDevices removes from device list, and attempts to launch', () async {
final RunCommand command = TestRunCommandThatOnlyValidates();
testDeviceManager.devices = <Device>[FakeMacDesignedForIpadDevice(), FakeDevice()];
await createTestCommandRunner(command).run(<String>[
'run',
'-d',
'all',
]);
expect(command.devices?.length, 1);
expect(command.devices?.single.id, 'fake_device');
}, overrides: <Type, Generator>{
FileSystem: () => fs,
ProcessManager: () => FakeProcessManager.any(),
DeviceManager: () => testDeviceManager,
Stdio: () => FakeStdio(),
Cache: () => Cache.test(processManager: FakeProcessManager.any()),
});
testUsingContext('exits and lists available devices when specified device not found', () async {
final RunCommand command = RunCommand();
final FakeDevice device = FakeDevice(isLocalEmulator: true);
@ -1413,6 +1470,27 @@ class FakeDevice extends Fake implements Device {
}
}
class FakeMacDesignedForIpadDevice extends Fake implements MacOSDesignedForIPadDevice {
@override
String get id => 'mac-designed-for-ipad';
@override
bool get isConnected => true;
@override
Future<TargetPlatform> get targetPlatform async => TargetPlatform.darwin;
@override
DeviceConnectionInterface connectionInterface = DeviceConnectionInterface.attached;
@override
bool isSupported() => true;
@override
bool isSupportedForProject(FlutterProject project) => true;
}
class FakeIOSDevice extends Fake implements IOSDevice {
FakeIOSDevice({
this.connectionInterface = DeviceConnectionInterface.attached,
@ -1479,6 +1557,9 @@ class TestRunCommandThatOnlyValidates extends RunCommand {
Future<FlutterCommandResult> runCommand() async {
return FlutterCommandResult.success();
}
@override
bool get shouldRunPub => false;
}
class FakeResidentRunner extends Fake implements ResidentRunner {

View file

@ -21,12 +21,7 @@ import '../../src/fakes.dart';
void main() {
group('MacOSDesignedForIPadDevices', () {
tearDown(() {
MacOSDesignedForIPadDevices.allowDiscovery = false;
});
testWithoutContext('does not support non-macOS platforms', () async {
MacOSDesignedForIPadDevices.allowDiscovery = true;
final MacOSDesignedForIPadDevices discoverer = MacOSDesignedForIPadDevices(
platform: FakePlatform(operatingSystem: 'windows'),
logger: BufferLogger.test(),
@ -39,7 +34,7 @@ void main() {
expect(discoverer.supportsPlatform, isFalse);
});
testWithoutContext('discovery not allowed', () async {
testWithoutContext('discovery is allowed', () async {
final MacOSDesignedForIPadDevices discoverer = MacOSDesignedForIPadDevices(
platform: FakePlatform(operatingSystem: 'macos'),
logger: BufferLogger.test(),
@ -51,11 +46,12 @@ void main() {
expect(discoverer.supportsPlatform, isTrue);
final List<Device> devices = await discoverer.devices();
expect(devices, isEmpty);
expect(devices, isNotNull);
expect(devices.first.id, 'mac-designed-for-ipad');
expect(devices.first is MacOSDesignedForIPadDevice, true);
});
testWithoutContext('no device on x86', () async {
MacOSDesignedForIPadDevices.allowDiscovery = true;
final MacOSDesignedForIPadDevices discoverer = MacOSDesignedForIPadDevices(
platform: FakePlatform(operatingSystem: 'macos'),
logger: BufferLogger.test(),
@ -71,7 +67,6 @@ void main() {
});
testWithoutContext('no device on when iOS development off', () async {
MacOSDesignedForIPadDevices.allowDiscovery = true;
final MacOSDesignedForIPadDevices discoverer = MacOSDesignedForIPadDevices(
platform: FakePlatform(operatingSystem: 'macos'),
logger: BufferLogger.test(),
@ -87,7 +82,6 @@ void main() {
});
testWithoutContext('device discovery on arm', () async {
MacOSDesignedForIPadDevices.allowDiscovery = true;
final MacOSDesignedForIPadDevices discoverer = MacOSDesignedForIPadDevices(
platform: FakePlatform(operatingSystem: 'macos'),
logger: BufferLogger.test(),
@ -103,7 +97,7 @@ void main() {
final Device device = devices.single;
expect(device, isA<MacOSDesignedForIPadDevice>());
expect(device.id, 'designed-for-ipad');
expect(device.id, 'mac-designed-for-ipad');
// Timeout ignored.
devices = await discoverer.discoverDevices(timeout: const Duration(seconds: 10));
@ -118,7 +112,7 @@ void main() {
fileSystem: MemoryFileSystem.test(),
operatingSystemUtils: FakeOperatingSystemUtils(hostPlatform: HostPlatform.darwin_arm64),
);
expect(device.id, 'designed-for-ipad');
expect(device.id, 'mac-designed-for-ipad');
expect(await device.isLocalEmulator, isFalse);
expect(device.name, 'Mac Designed for iPad');
expect(device.portForwarder, isNot(isNull));