diff --git a/packages/flutter_tools/lib/src/commands/attach.dart b/packages/flutter_tools/lib/src/commands/attach.dart index 2589a2aaff..04a0d91e46 100644 --- a/packages/flutter_tools/lib/src/commands/attach.dart +++ b/packages/flutter_tools/lib/src/commands/attach.dart @@ -213,9 +213,6 @@ known, it can be explicitly provided to attach via the command-line, e.g. @override Future validateCommand() async { - // ARM macOS as an iOS target is hidden, except for attach. - MacOSDesignedForIPadDevices.allowDiscovery = true; - await super.validateCommand(); final Device? targetDevice = await findTargetDevice(); diff --git a/packages/flutter_tools/lib/src/commands/drive.dart b/packages/flutter_tools/lib/src/commands/drive.dart index 379afa690b..be6b19c74a 100644 --- a/packages/flutter_tools/lib/src/commands/drive.dart +++ b/packages/flutter_tools/lib/src/commands/drive.dart @@ -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(); } diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index 54fa2c4f30..9759d4ef1f 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -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'); } diff --git a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart index 4e5d3f7a8d..cb34310d09 100644 --- a/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart +++ b/packages/flutter_tools/lib/src/macos/macos_ipad_device.dart @@ -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> pollingGetDevices({Duration? timeout}) async { @@ -144,5 +141,5 @@ class MacOSDesignedForIPadDevices extends PollingDeviceDiscovery { Future> getDiagnostics() async => const []; @override - List get wellKnownIds => const ['designed-for-ipad']; + List get wellKnownIds => const ['mac-designed-for-ipad']; } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart index 775632d1c4..f9e40d61d5 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/attach_test.dart @@ -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: { FileSystem: () => testFileSystem, ProcessManager: () => FakeProcessManager.any(), diff --git a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart index 3d14b0a5b3..510adf1c3f 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -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 = [FakeMacDesignedForIpadDevice()]; + + await expectLater( + () => createTestCommandRunner(command).run([ + 'run', + '-d', + 'mac-designed-for-ipad', + ]), throwsToolExit(message: 'Mac Designed for iPad is currently not supported for flutter run -d')); + }, overrides: { + 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 = [FakeMacDesignedForIpadDevice()]; + + await expectLater( + () => createTestCommandRunner(command).run([ + 'run', + '-d', + 'all', + ]), throwsToolExit(message: 'Mac Designed for iPad is currently not supported for flutter run -d')); + }, overrides: { + 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 = [FakeMacDesignedForIpadDevice(), FakeDevice()]; + + await createTestCommandRunner(command).run([ + 'run', + '-d', + 'all', + ]); + + expect(command.devices?.length, 1); + expect(command.devices?.single.id, 'fake_device'); + }, overrides: { + 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 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 runCommand() async { return FlutterCommandResult.success(); } + + @override + bool get shouldRunPub => false; } class FakeResidentRunner extends Fake implements ResidentRunner { diff --git a/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart b/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart index c960ccaff0..611c0ccc0d 100644 --- a/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart +++ b/packages/flutter_tools/test/general.shard/macos/macos_ipad_device_test.dart @@ -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 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()); - 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));