Removes check for Homebrew if all necessary packages are present. (#23844)

* Removes need for homebrew installation if all other packages are installed. Modifies test to work with this new functionality.
diff --git a/packages/flutter_tools/lib/src/ios/ios_workflow.dart b/packages/flutter_tools/lib/src/ios/ios_workflow.dart
index cfd12fb..07b30ad 100644
--- a/packages/flutter_tools/lib/src/ios/ios_workflow.dart
+++ b/packages/flutter_tools/lib/src/ios/ios_workflow.dart
@@ -68,11 +68,14 @@
     }
   }
 
+  // Change this value if the number of checks for packages needed for installation changes
+  static const int totalChecks = 4;
+
   @override
   Future<ValidationResult> validate() async {
     final List<ValidationMessage> messages = <ValidationMessage>[];
     ValidationType xcodeStatus = ValidationType.missing;
-    ValidationType brewStatus = ValidationType.missing;
+    ValidationType packageManagerStatus = ValidationType.installed;
     String xcodeVersionInfo;
 
     if (xcode.isInstalled) {
@@ -125,76 +128,84 @@
       }
     }
 
-    // brew installed
-    if (hasHomebrew) {
-      brewStatus = ValidationType.installed;
+    int checksFailed = 0;
 
-      if (!iMobileDevice.isInstalled) {
-        brewStatus = ValidationType.partial;
-        messages.add(ValidationMessage.error(
-            'libimobiledevice and ideviceinstaller are not installed. To install, run:\n'
-            '  brew update\n'
-            '  brew install --HEAD usbmuxd\n'
-            '  brew link usbmuxd\n'
-            '  brew install --HEAD libimobiledevice\n'
-            '  brew install ideviceinstaller'
-        ));
-      } else if (!await iMobileDevice.isWorking) {
-        brewStatus = ValidationType.partial;
-        messages.add(ValidationMessage.error(
-            'Verify that all connected devices have been paired with this computer in Xcode.\n'
-            'If all devices have been paired, libimobiledevice and ideviceinstaller may require updating.\n'
-            'To update, run:\n'
-            '  brew update\n'
-            '  brew uninstall --ignore-dependencies libimobiledevice\n'
-            '  brew uninstall --ignore-dependencies usbmuxd\n'
-            '  brew install --HEAD usbmuxd\n'
-            '  brew unlink usbmuxd\n'
-            '  brew link usbmuxd\n'
-            '  brew install --HEAD libimobiledevice\n'
-            '  brew install ideviceinstaller'
-        ));
-      } else if (!await hasIDeviceInstaller) {
-        brewStatus = ValidationType.partial;
-        messages.add(ValidationMessage.error(
-          'ideviceinstaller is not installed; this is used to discover connected iOS devices.\n'
-          'To install, run:\n'
-          '  brew install --HEAD usbmuxd\n'
-          '  brew link usbmuxd\n'
-          '  brew install --HEAD libimobiledevice\n'
-          '  brew install ideviceinstaller'
-        ));
-      }
-
-      // Check ios-deploy is installed at meets version requirements.
-      if (await hasIosDeploy) {
-        messages.add(ValidationMessage('ios-deploy ${await iosDeployVersionText}'));
-      }
-      if (!await _iosDeployIsInstalledAndMeetsVersionCheck) {
-        brewStatus = ValidationType.partial;
-        if (await hasIosDeploy) {
-          messages.add(ValidationMessage.error(
-            'ios-deploy out of date ($iosDeployMinimumVersion is required). To upgrade:\n'
-            '  brew upgrade ios-deploy'
-          ));
-        } else {
-          messages.add(ValidationMessage.error(
-            'ios-deploy not installed. To install:\n'
-            '  brew install ios-deploy'
-          ));
-        }
-      }
-
-    } else {
-      brewStatus = ValidationType.missing;
+    if (!iMobileDevice.isInstalled) {
+      checksFailed += 3;
+      packageManagerStatus = ValidationType.partial;
       messages.add(ValidationMessage.error(
-          'Brew not installed; use this to install tools for iOS device development.\n'
-              'Download brew at https://brew.sh/.'
+        'libimobiledevice and ideviceinstaller are not installed. To install with Brew, run:\n'
+        '  brew update\n'
+        '  brew install --HEAD usbmuxd\n'
+        '  brew link usbmuxd\n'
+        '  brew install --HEAD libimobiledevice\n'
+        '  brew install ideviceinstaller'
+      ));
+    } else if (!await iMobileDevice.isWorking) {
+      checksFailed += 2;
+      packageManagerStatus = ValidationType.partial;
+      messages.add(ValidationMessage.error(
+        'Verify that all connected devices have been paired with this computer in Xcode.\n'
+        'If all devices have been paired, libimobiledevice and ideviceinstaller may require updating.\n'
+        'To update with Brew, run:\n'
+        '  brew update\n'
+        '  brew uninstall --ignore-dependencies libimobiledevice\n'
+        '  brew uninstall --ignore-dependencies usbmuxd\n'
+        '  brew install --HEAD usbmuxd\n'
+        '  brew unlink usbmuxd\n'
+        '  brew link usbmuxd\n'
+        '  brew install --HEAD libimobiledevice\n'
+        '  brew install ideviceinstaller'
+      ));
+    } else if (!await hasIDeviceInstaller) {
+      checksFailed += 1;
+      packageManagerStatus = ValidationType.partial;
+      messages.add(ValidationMessage.error(
+        'ideviceinstaller is not installed; this is used to discover connected iOS devices.\n'
+        'To install with Brew, run:\n'
+        '  brew install --HEAD usbmuxd\n'
+        '  brew link usbmuxd\n'
+        '  brew install --HEAD libimobiledevice\n'
+        '  brew install ideviceinstaller'
+      ));
+    }
+
+    final bool iHasIosDeploy = await hasIosDeploy;
+
+    // Check ios-deploy is installed at meets version requirements.
+    if (iHasIosDeploy) {
+      messages.add(
+        ValidationMessage('ios-deploy ${await iosDeployVersionText}'));
+    }
+    if (!await _iosDeployIsInstalledAndMeetsVersionCheck) {
+      packageManagerStatus = ValidationType.partial;
+      if (iHasIosDeploy) {
+        messages.add(ValidationMessage.error(
+          'ios-deploy out of date ($iosDeployMinimumVersion is required). To upgrade with Brew:\n'
+          '  brew upgrade ios-deploy'
+        ));
+      } else {
+        checksFailed += 1;
+        messages.add(ValidationMessage.error(
+          'ios-deploy not installed. To install with Brew:\n'
+          '  brew install ios-deploy'
+        ));
+      }
+    }
+
+    // If one of the checks for the packages failed, we may need brew so that we can install
+    // the necessary packages. If they're all there, however, we don't even need it.
+    if (checksFailed == totalChecks)
+      packageManagerStatus = ValidationType.missing;
+    if (checksFailed > 0 && !hasHomebrew) {
+      messages.add(ValidationMessage.error(
+        'Brew can be used to install tools for iOS device development.\n'
+        'Download brew at https://brew.sh/.'
       ));
     }
 
     return ValidationResult(
-        <ValidationType>[xcodeStatus, brewStatus].reduce(_mergeValidationTypes),
+        <ValidationType>[xcodeStatus, packageManagerStatus].reduce(_mergeValidationTypes),
         messages,
         statusInfo: xcodeVersionInfo
     );
diff --git a/packages/flutter_tools/test/ios/ios_workflow_test.dart b/packages/flutter_tools/test/ios/ios_workflow_test.dart
index fe3a4e9..1004131 100644
--- a/packages/flutter_tools/test/ios/ios_workflow_test.dart
+++ b/packages/flutter_tools/test/ios/ios_workflow_test.dart
@@ -21,6 +21,7 @@
 void main() {
   group('iOS Workflow validation', () {
     MockIMobileDevice iMobileDevice;
+    MockIMobileDevice iMobileDeviceUninstalled;
     MockXcode xcode;
     MockProcessManager processManager;
     MockCocoaPods cocoaPods;
@@ -28,6 +29,7 @@
 
     setUp(() {
       iMobileDevice = MockIMobileDevice();
+      iMobileDeviceUninstalled = MockIMobileDevice(isInstalled: false);
       xcode = MockXcode();
       processManager = MockProcessManager();
       cocoaPods = MockCocoaPods();
@@ -45,11 +47,13 @@
       final IOSWorkflowTestTarget workflow = IOSWorkflowTestTarget(
         hasHomebrew: false,
         hasIosDeploy: false,
+        hasIDeviceInstaller: false,
+        iosDeployVersionText: '0.0.0',
       );
       final ValidationResult result = await workflow.validate();
       expect(result.type, ValidationType.missing);
     }, overrides: <Type, Generator>{
-      IMobileDevice: () => iMobileDevice,
+      IMobileDevice: () => iMobileDeviceUninstalled,
       Xcode: () => xcode,
       CocoaPods: () => cocoaPods,
     });
@@ -110,7 +114,7 @@
       CocoaPods: () => cocoaPods,
     });
 
-    testUsingContext('Emits partial status when homebrew not installed', () async {
+    testUsingContext('Emits installed status when homebrew not installed, but not needed', () async {
       when(xcode.isInstalled).thenReturn(true);
       when(xcode.versionText)
           .thenReturn('Xcode 8.2.1\nBuild version 8C1002\n');
@@ -119,7 +123,7 @@
       when(xcode.isSimctlInstalled).thenReturn(true);
       final IOSWorkflowTestTarget workflow = IOSWorkflowTestTarget(hasHomebrew: false);
       final ValidationResult result = await workflow.validate();
-      expect(result.type, ValidationType.partial);
+      expect(result.type, ValidationType.installed);
     }, overrides: <Type, Generator>{
       IMobileDevice: () => iMobileDevice,
       Xcode: () => xcode,