Support running apk with more than one activity (#18716)

diff --git a/packages/flutter_tools/lib/src/application_package.dart b/packages/flutter_tools/lib/src/application_package.dart
index b568d78..ff52975 100644
--- a/packages/flutter_tools/lib/src/application_package.dart
+++ b/packages/flutter_tools/lib/src/application_package.dart
@@ -60,8 +60,16 @@
       return null;
     }
 
-    final List<String> aaptArgs = <String>[aaptPath, 'dump', 'badging', applicationBinary];
-    final ApkManifestData data = ApkManifestData.parseFromAaptBadging(runCheckedSync(aaptArgs));
+     final List<String> aaptArgs = <String>[
+       aaptPath,
+      'dump',
+      'xmltree',
+      applicationBinary,
+      'AndroidManifest.xml',
+    ];
+
+    final ApkManifestData data = ApkManifestData
+        .parseFromXmlDump(runCheckedSync(aaptArgs));
 
     if (data == null) {
       printError('Unable to read manifest info from $applicationBinary.');
@@ -116,9 +124,12 @@
     for (xml.XmlElement category in document.findAllElements('category')) {
       if (category.getAttribute('android:name') == 'android.intent.category.LAUNCHER') {
         final xml.XmlElement activity = category.parent.parent;
-        final String activityName = activity.getAttribute('android:name');
-        launchActivity = '$packageId/$activityName';
-        break;
+        final String enabled = activity.getAttribute('android:enabled');
+        if (enabled == null || enabled == 'true') {
+          final String activityName = activity.getAttribute('android:name');
+          launchActivity = '$packageId/$activityName';
+          break;
+        }
       }
     }
 
@@ -349,34 +360,133 @@
   }
 }
 
+class _Entry {
+  _Element parent;
+  int level;
+}
+
+class _Element extends _Entry {
+  List<_Entry> children;
+  String name;
+
+  _Element.fromLine(String line, _Element parent) {
+    //      E: application (line=29)
+    final List<String> parts = line.trimLeft().split(' ');
+    name = parts[1];
+    level = line.length - line.trimLeft().length;
+    this.parent = parent;
+    children = <_Entry>[];
+  }
+
+  void addChild(_Entry child) {
+    children.add(child);
+  }
+
+  _Attribute firstAttribute(String name) {
+    return children.firstWhere(
+        (_Entry e) => e is _Attribute && e.key.startsWith(name),
+        orElse: () => null,
+    );
+  }
+
+  _Element firstElement(String name) {
+    return children.firstWhere(
+        (_Entry e) => e is _Element && e.name.startsWith(name),
+        orElse: () => null,
+    );
+  }
+
+  Iterable<_Entry> allElements(String name) {
+    return children.where(
+            (_Entry e) => e is _Element && e.name.startsWith(name));
+  }
+}
+
+class _Attribute extends _Entry {
+  String key;
+  String value;
+
+  _Attribute.fromLine(String line, _Element parent) {
+    //     A: android:label(0x01010001)="hello_world" (Raw: "hello_world")
+    const String attributePrefix = 'A: ';
+    final List<String> keyVal = line
+        .substring(line.indexOf(attributePrefix) + attributePrefix.length)
+        .split('=');
+    key = keyVal[0];
+    value = keyVal[1];
+    level = line.length - line.trimLeft().length;
+    this.parent = parent;
+  }
+}
+
 class ApkManifestData {
   ApkManifestData._(this._data);
 
-  static ApkManifestData parseFromAaptBadging(String data) {
+  static ApkManifestData parseFromXmlDump(String data) {
     if (data == null || data.trim().isEmpty)
       return null;
 
-    // package: name='io.flutter.gallery' versionCode='1' versionName='0.0.1' platformBuildVersionName='NMR1'
-    // launchable-activity: name='io.flutter.app.FlutterActivity'  label='' icon=''
-    final Map<String, Map<String, String>> map = <String, Map<String, String>>{};
+    final List<String> lines = data.split('\n');
+    assert(lines.length > 3);
 
-    final RegExp keyValueRegex = new RegExp(r"(\S+?)='(.*?)'");
+    final _Element manifest = new _Element.fromLine(lines[1], null);
+    _Element currentElement = manifest;
 
-    for (String line in data.split('\n')) {
-      final int index = line.indexOf(':');
-      if (index != -1) {
-        final String name = line.substring(0, index);
-        line = line.substring(index + 1).trim();
+    for (String line in lines.skip(2)) {
+      final String trimLine = line.trimLeft();
+      final int level = line.length - trimLine.length;
 
-        final Map<String, String> entries = <String, String>{};
-        map[name] = entries;
+      // Handle level out
+      while(level <= currentElement.level) {
+        currentElement = currentElement.parent;
+      }
 
-        for (Match m in keyValueRegex.allMatches(line)) {
-          entries[m.group(1)] = m.group(2);
+      if (level > currentElement.level) {
+        switch (trimLine[0]) {
+          case 'A':
+            currentElement
+                .addChild(new _Attribute.fromLine(line, currentElement));
+            break;
+          case 'E':
+            final _Element element = new _Element.fromLine(line, currentElement);
+            currentElement.addChild(element);
+            currentElement = element;
         }
       }
     }
 
+    final _Element application = manifest.firstElement('application');
+    assert(application != null);
+
+    final Iterable<_Entry> activities = application.allElements('activity');
+
+    _Element launchActivity;
+    for (_Element activity in activities) {
+      final _Attribute enabled = activity.firstAttribute('android:enabled');
+      if (enabled == null || enabled.value.contains('0xffffffff')) {
+        launchActivity = activity;
+        break;
+      }
+    }
+
+    final _Attribute package = manifest.firstAttribute('package');
+    // "io.flutter.examples.hello_world" (Raw: "io.flutter.examples.hello_world")
+    final String packageName = package.value.substring(1, package.value.indexOf('" '));
+
+    if (launchActivity == null) {
+      printError('Error running $packageName. Default activity not found');
+      return null;
+    }
+
+    final _Attribute nameAttribute = launchActivity.firstAttribute('android:name');
+    // "io.flutter.examples.hello_world.MainActivity" (Raw: "io.flutter.examples.hello_world.MainActivity")
+    final String activityName = nameAttribute
+        .value.substring(1, nameAttribute.value.indexOf('" '));
+
+    final Map<String, Map<String, String>> map = <String, Map<String, String>>{};
+    map['package'] = <String, String>{'name': packageName};
+    map['launchable-activity'] = <String, String>{'name': activityName};
+
     return new ApkManifestData._(map);
   }
 
diff --git a/packages/flutter_tools/test/application_package_test.dart b/packages/flutter_tools/test/application_package_test.dart
index d4e4ded..da5b17a 100644
--- a/packages/flutter_tools/test/application_package_test.dart
+++ b/packages/flutter_tools/test/application_package_test.dart
@@ -18,13 +18,24 @@
 
 void main() {
   group('ApkManifestData', () {
-    testUsingContext('parse sdk', () {
-      final ApkManifestData data =
-          ApkManifestData.parseFromAaptBadging(_aaptData);
+    test('Select explicity enabled activity', () {
+      final ApkManifestData data = ApkManifestData.parseFromXmlDump(_aaptDataWithExplicitEnabledActivity);
       expect(data, isNotNull);
-      expect(data.packageName, 'io.flutter.gallery');
-      expect(data.launchableActivityName, 'io.flutter.app.FlutterActivity');
-      expect(data.data['application']['label'], 'Flutter Gallery');
+      expect(data.packageName, 'io.flutter.examples.hello_world');
+      expect(data.launchableActivityName, 'io.flutter.examples.hello_world.MainActivity2');
+    });
+    test('Select default enabled activity', () {
+      final ApkManifestData data = ApkManifestData.parseFromXmlDump(_aaptDataWithDefaultEnabledActivity);
+      expect(data, isNotNull);
+      expect(data.packageName, 'io.flutter.examples.hello_world');
+      expect(data.launchableActivityName, 'io.flutter.examples.hello_world.MainActivity2');
+    });
+    testUsingContext('Error on no enabled activity', () {
+      final ApkManifestData data = ApkManifestData.parseFromXmlDump(_aaptDataWithNoEnabledActivity);
+      expect(data, isNull);
+      final BufferLogger logger = context[Logger];
+      expect(
+          logger.errorText, 'Error running io.flutter.examples.hello_world. Default activity not found\n');
     });
   });
 
@@ -152,33 +163,6 @@
   });
 }
 
-const String _aaptData = '''
-package: name='io.flutter.gallery' versionCode='1' versionName='0.0.1' platformBuildVersionName='NMR1'
-sdkVersion:'14'
-targetSdkVersion:'21'
-uses-permission: name='android.permission.INTERNET'
-application-label:'Flutter Gallery'
-application-icon-160:'res/mipmap-mdpi-v4/ic_launcher.png'
-application-icon-240:'res/mipmap-hdpi-v4/ic_launcher.png'
-application-icon-320:'res/mipmap-xhdpi-v4/ic_launcher.png'
-application-icon-480:'res/mipmap-xxhdpi-v4/ic_launcher.png'
-application-icon-640:'res/mipmap-xxxhdpi-v4/ic_launcher.png'
-application: label='Flutter Gallery' icon='res/mipmap-mdpi-v4/ic_launcher.png'
-application-debuggable
-launchable-activity: name='io.flutter.app.FlutterActivity'  label='' icon=''
-feature-group: label=''
-  uses-feature: name='android.hardware.screen.portrait'
-  uses-implied-feature: name='android.hardware.screen.portrait' reason='one or more activities have specified a portrait orientation'
-  uses-feature: name='android.hardware.touchscreen'
-  uses-implied-feature: name='android.hardware.touchscreen' reason='default feature for all apps'
-main
-supports-screens: 'small' 'normal' 'large' 'xlarge'
-supports-any-density: 'true'
-locales: '--_--'
-densities: '160' '240' '320' '480' '640'
-native-code: 'armeabi-v7a'
-''';
-
 final Map<String, String> _swiftBuildSettings = <String, String>{
   'ARCHS': 'arm64',
   'ASSETCATALOG_COMPILER_APPICON_NAME': 'AppIcon',
@@ -192,6 +176,118 @@
   'SWIFT_VERSION': '3.0',
 };
 
+const String _aaptDataWithExplicitEnabledActivity =
+'''N: android=http://schemas.android.com/apk/res/android
+  E: manifest (line=7)
+    A: android:versionCode(0x0101021b)=(type 0x10)0x1
+    A: android:versionName(0x0101021c)="0.0.1" (Raw: "0.0.1")
+    A: package="io.flutter.examples.hello_world" (Raw: "io.flutter.examples.hello_world")
+    E: uses-sdk (line=12)
+      A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
+      A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1b
+    E: uses-permission (line=21)
+      A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
+    E: application (line=29)
+      A: android:label(0x01010001)="hello_world" (Raw: "hello_world")
+      A: android:icon(0x01010002)=@0x7f010000
+      A: android:name(0x01010003)="io.flutter.app.FlutterApplication" (Raw: "io.flutter.app.FlutterApplication")
+      A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
+      E: activity (line=34)
+        A: android:theme(0x01010000)=@0x1030009
+        A: android:name(0x01010003)="io.flutter.examples.hello_world.MainActivity" (Raw: "io.flutter.examples.hello_world.MainActivity")
+        A: android:enabled(0x0101000e)=(type 0x12)0x0
+        A: android:launchMode(0x0101001d)=(type 0x10)0x1
+        A: android:configChanges(0x0101001f)=(type 0x11)0x400035b4
+        A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
+        A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
+        E: intent-filter (line=42)
+          E: action (line=43)
+            A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
+          E: category (line=45)
+            A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
+      E: activity (line=48)
+        A: android:theme(0x01010000)=@0x1030009
+        A: android:label(0x01010001)="app2" (Raw: "app2")
+        A: android:name(0x01010003)="io.flutter.examples.hello_world.MainActivity2" (Raw: "io.flutter.examples.hello_world.MainActivity2")
+        A: android:enabled(0x0101000e)=(type 0x12)0xffffffff
+        E: intent-filter (line=53)
+          E: action (line=54)
+            A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
+          E: category (line=56)
+            A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")''';
+
+
+const String _aaptDataWithDefaultEnabledActivity =
+'''N: android=http://schemas.android.com/apk/res/android
+  E: manifest (line=7)
+    A: android:versionCode(0x0101021b)=(type 0x10)0x1
+    A: android:versionName(0x0101021c)="0.0.1" (Raw: "0.0.1")
+    A: package="io.flutter.examples.hello_world" (Raw: "io.flutter.examples.hello_world")
+    E: uses-sdk (line=12)
+      A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
+      A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1b
+    E: uses-permission (line=21)
+      A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
+    E: application (line=29)
+      A: android:label(0x01010001)="hello_world" (Raw: "hello_world")
+      A: android:icon(0x01010002)=@0x7f010000
+      A: android:name(0x01010003)="io.flutter.app.FlutterApplication" (Raw: "io.flutter.app.FlutterApplication")
+      A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
+      E: activity (line=34)
+        A: android:theme(0x01010000)=@0x1030009
+        A: android:name(0x01010003)="io.flutter.examples.hello_world.MainActivity" (Raw: "io.flutter.examples.hello_world.MainActivity")
+        A: android:enabled(0x0101000e)=(type 0x12)0x0
+        A: android:launchMode(0x0101001d)=(type 0x10)0x1
+        A: android:configChanges(0x0101001f)=(type 0x11)0x400035b4
+        A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
+        A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
+        E: intent-filter (line=42)
+          E: action (line=43)
+            A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
+          E: category (line=45)
+            A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")
+      E: activity (line=48)
+        A: android:theme(0x01010000)=@0x1030009
+        A: android:label(0x01010001)="app2" (Raw: "app2")
+        A: android:name(0x01010003)="io.flutter.examples.hello_world.MainActivity2" (Raw: "io.flutter.examples.hello_world.MainActivity2")
+        E: intent-filter (line=53)
+          E: action (line=54)
+            A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
+          E: category (line=56)
+            A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")''';
+
+
+const String _aaptDataWithNoEnabledActivity =
+'''N: android=http://schemas.android.com/apk/res/android
+  E: manifest (line=7)
+    A: android:versionCode(0x0101021b)=(type 0x10)0x1
+    A: android:versionName(0x0101021c)="0.0.1" (Raw: "0.0.1")
+    A: package="io.flutter.examples.hello_world" (Raw: "io.flutter.examples.hello_world")
+    E: uses-sdk (line=12)
+      A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
+      A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1b
+    E: uses-permission (line=21)
+      A: android:name(0x01010003)="android.permission.INTERNET" (Raw: "android.permission.INTERNET")
+    E: application (line=29)
+      A: android:label(0x01010001)="hello_world" (Raw: "hello_world")
+      A: android:icon(0x01010002)=@0x7f010000
+      A: android:name(0x01010003)="io.flutter.app.FlutterApplication" (Raw: "io.flutter.app.FlutterApplication")
+      A: android:debuggable(0x0101000f)=(type 0x12)0xffffffff
+      E: activity (line=34)
+        A: android:theme(0x01010000)=@0x1030009
+        A: android:name(0x01010003)="io.flutter.examples.hello_world.MainActivity" (Raw: "io.flutter.examples.hello_world.MainActivity")
+        A: android:enabled(0x0101000e)=(type 0x12)0x0
+        A: android:launchMode(0x0101001d)=(type 0x10)0x1
+        A: android:configChanges(0x0101001f)=(type 0x11)0x400035b4
+        A: android:windowSoftInputMode(0x0101022b)=(type 0x11)0x10
+        A: android:hardwareAccelerated(0x010102d3)=(type 0x12)0xffffffff
+        E: intent-filter (line=42)
+          E: action (line=43)
+            A: android:name(0x01010003)="android.intent.action.MAIN" (Raw: "android.intent.action.MAIN")
+          E: category (line=45)
+            A: android:name(0x01010003)="android.intent.category.LAUNCHER" (Raw: "android.intent.category.LAUNCHER")''';
+
+
 class MockIosWorkFlow extends Mock implements IOSWorkflow {
   @override
   String getPlistValueFromFile(String path, String key) {