Add Android embedding version analytics (#44043)

diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart
index d6aeeb0..cf2689c 100644
--- a/packages/flutter_tools/lib/src/commands/packages.dart
+++ b/packages/flutter_tools/lib/src/commands/packages.dart
@@ -87,6 +87,8 @@
       usageValues[CustomDimensions.commandPackagesNumberPlugins] = '0';
     }
     usageValues[CustomDimensions.commandPackagesProjectModule] = '${rootProject.isModule}';
+    usageValues[CustomDimensions.commandPackagesAndroidEmbeddingVersion] =
+        rootProject.android.getEmbeddingVersion().toString().split('.').last;
     return usageValues;
   }
 
diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart
index fd6dc53..6bd40df 100644
--- a/packages/flutter_tools/lib/src/commands/run.dart
+++ b/packages/flutter_tools/lib/src/commands/run.dart
@@ -250,6 +250,7 @@
       CustomDimensions.commandRunModeName: modeName,
       CustomDimensions.commandRunProjectModule: '${FlutterProject.current().isModule}',
       CustomDimensions.commandRunProjectHostLanguage: hostLanguage.join(','),
+      CustomDimensions.commandRunAndroidEmbeddingVersion: androidProject.getEmbeddingVersion().toString().split('.').last,
     };
   }
 
diff --git a/packages/flutter_tools/lib/src/plugins.dart b/packages/flutter_tools/lib/src/plugins.dart
index da994b4..613400c 100644
--- a/packages/flutter_tools/lib/src/plugins.dart
+++ b/packages/flutter_tools/lib/src/plugins.dart
@@ -5,7 +5,6 @@
 import 'dart:async';
 
 import 'package:mustache/mustache.dart' as mustache;
-import 'package:xml/xml.dart' as xml;
 import 'package:yaml/yaml.dart';
 
 import 'android/gradle.dart';
@@ -364,30 +363,10 @@
 
 /// Returns the version of the Android embedding that the current
 /// [project] is using.
-String _getAndroidEmbeddingVersion(FlutterProject project) {
+AndroidEmbeddingVersion _getAndroidEmbeddingVersion(FlutterProject project) {
   assert(project.android != null);
 
-  final File androidManifest = project.android.appManifestFile;
-  if (androidManifest == null || !androidManifest.existsSync()) {
-    return '1';
-  }
-  xml.XmlDocument document;
-  try {
-    document = xml.parse(androidManifest.readAsStringSync());
-  } on xml.XmlParserException {
-    throwToolExit('Error parsing ${project.android.appManifestFile} '
-                  'Please ensure that the android manifest is a valid XML document and try again.');
-  } on FileSystemException {
-    throwToolExit('Error reading ${project.android.appManifestFile} even though it exists. '
-                  'Please ensure that you have read permission to this file and try again.');
-  }
-  for (xml.XmlElement metaData in document.findAllElements('meta-data')) {
-    final String name = metaData.getAttribute('android:name');
-    if (name == 'flutterEmbedding') {
-      return metaData.getAttribute('android:value');
-    }
-  }
-  return '1';
+  return project.android.getEmbeddingVersion();
 }
 
 Future<void> _writeAndroidPluginRegistrant(FlutterProject project, List<Plugin> plugins) async {
@@ -412,9 +391,9 @@
     'GeneratedPluginRegistrant.java',
   );
   String templateContent;
-  final String appEmbeddingVersion = _getAndroidEmbeddingVersion(project);
+  final AndroidEmbeddingVersion appEmbeddingVersion = _getAndroidEmbeddingVersion(project);
   switch (appEmbeddingVersion) {
-    case '2':
+    case AndroidEmbeddingVersion.v2:
       templateContext['needsShim'] = false;
       // If a plugin is using an embedding version older than 2.0 and the app is using 2.0,
       // then add  shim for the old plugins.
@@ -425,8 +404,9 @@
         }
       }
       templateContent = _androidPluginRegistryTemplateNewEmbedding;
-    break;
-    case '1':
+      break;
+    case AndroidEmbeddingVersion.v1:
+    default:
       for (Map<String, dynamic> plugin in androidPlugins) {
         if (!plugin['supportsEmbeddingV1'] && plugin['supportsEmbeddingV2']) {
           throwToolExit(
@@ -437,9 +417,7 @@
         }
       }
       templateContent = _androidPluginRegistryTemplateOldEmbedding;
-    break;
-    default:
-      throwToolExit('Unsupported Android embedding');
+      break;
   }
   printTrace('Generating $registryPath');
   _renderTemplateToFile(
diff --git a/packages/flutter_tools/lib/src/project.dart b/packages/flutter_tools/lib/src/project.dart
index 5bc5c77..f8e8576 100644
--- a/packages/flutter_tools/lib/src/project.dart
+++ b/packages/flutter_tools/lib/src/project.dart
@@ -5,6 +5,7 @@
 import 'dart:async';
 
 import 'package:meta/meta.dart';
+import 'package:xml/xml.dart' as xml;
 import 'package:yaml/yaml.dart';
 
 import 'android/gradle_utils.dart' as gradle;
@@ -642,6 +643,43 @@
       overwriteExisting: true,
     );
   }
+
+  AndroidEmbeddingVersion getEmbeddingVersion() {
+    if (appManifestFile == null || !appManifestFile.existsSync()) {
+      return AndroidEmbeddingVersion.v1;
+    }
+    xml.XmlDocument document;
+    try {
+      document = xml.parse(appManifestFile.readAsStringSync());
+    } on xml.XmlParserException {
+      throwToolExit('Error parsing $appManifestFile '
+                    'Please ensure that the android manifest is a valid XML document and try again.');
+    } on FileSystemException {
+      throwToolExit('Error reading $appManifestFile even though it exists. '
+                    'Please ensure that you have read permission to this file and try again.');
+    }
+    for (xml.XmlElement metaData in document.findAllElements('meta-data')) {
+      final String name = metaData.getAttribute('android:name');
+      if (name == 'flutterEmbedding') {
+        final String embeddingVersionString = metaData.getAttribute('android:value');
+        if (embeddingVersionString == '1') {
+          return AndroidEmbeddingVersion.v1;
+        }
+        if (embeddingVersionString == '2') {
+          return AndroidEmbeddingVersion.v2;
+        }
+      }
+    }
+    return AndroidEmbeddingVersion.v1;
+  }
+}
+
+/// Iteration of the embedding Java API in the engine used by the Android project.
+enum AndroidEmbeddingVersion {
+  /// V1 APIs based on io.flutter.app.FlutterActivity.
+  v1,
+  /// V2 APIs based on io.flutter.embedding.android.FlutterActivity.
+  v2,
 }
 
 /// Represents the web sub-project of a Flutter project.
diff --git a/packages/flutter_tools/lib/src/reporting/usage.dart b/packages/flutter_tools/lib/src/reporting/usage.dart
index e737439..d352632 100644
--- a/packages/flutter_tools/lib/src/reporting/usage.dart
+++ b/packages/flutter_tools/lib/src/reporting/usage.dart
@@ -55,6 +55,8 @@
   commandBuildAppBundleBuildMode, // cd42
   buildEventError,  // cd43
   commandResultEventMaxRss,  // cd44
+  commandRunAndroidEmbeddingVersion, // cd45
+  commandPackagesAndroidEmbeddingVersion, // cd46
 }
 
 String cdKey(CustomDimensions cd) => 'cd${cd.index + 1}';
diff --git a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart
index a9197ed..3df82bf 100644
--- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart
+++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart
@@ -11,12 +11,14 @@
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/commands/packages.dart';
 import 'package:flutter_tools/src/dart/pub.dart';
+import 'package:flutter_tools/src/features.dart';
 import 'package:flutter_tools/src/reporting/reporting.dart';
 import 'package:process/process.dart';
 
 import '../../src/common.dart';
 import '../../src/context.dart';
 import '../../src/mocks.dart' show MockProcessManager, MockStdio, PromptingProcess;
+import '../../src/testbed.dart';
 
 class AlwaysTrueBotDetector implements BotDetector {
   const AlwaysTrueBotDetector();
@@ -266,6 +268,36 @@
       Pub: () => const Pub(),
     });
 
+    testUsingContext('indicate that Android project reports v1 in usage value', () async {
+      final String projectPath = await createProject(tempDir,
+        arguments: <String>['--no-pub']);
+      removeGeneratedFiles(projectPath);
+
+      final PackagesCommand command = await runCommandIn(projectPath, 'get');
+      final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;
+
+      expect(await getCommand.usageValues,
+             containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v1'));
+    }, overrides: <Type, Generator>{
+      FeatureFlags: () => TestFeatureFlags(isAndroidEmbeddingV2Enabled: false),
+      Pub: () => const Pub(),
+    });
+
+    testUsingContext('indicate that Android project reports v2 in usage value', () async {
+      final String projectPath = await createProject(tempDir,
+        arguments: <String>['--no-pub']);
+      removeGeneratedFiles(projectPath);
+
+      final PackagesCommand command = await runCommandIn(projectPath, 'get');
+      final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;
+
+      expect(await getCommand.usageValues,
+             containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v2'));
+    }, overrides: <Type, Generator>{
+      FeatureFlags: () => TestFeatureFlags(isAndroidEmbeddingV2Enabled: true),
+      Pub: () => const Pub(),
+    });
+
     testUsingContext('upgrade fetches packages', () async {
       final String projectPath = await createProject(tempDir,
         arguments: <String>['--no-pub', '--template=module']);
diff --git a/packages/flutter_tools/test/general.shard/plugins_test.dart b/packages/flutter_tools/test/general.shard/plugins_test.dart
index 59c19c4..0dea334 100644
--- a/packages/flutter_tools/test/general.shard/plugins_test.dart
+++ b/packages/flutter_tools/test/general.shard/plugins_test.dart
@@ -125,22 +125,6 @@
       MockFeatureFlags featureFlags;
       MockXcodeProjectInterpreter xcodeProjectInterpreter;
 
-      const String kAndroidManifestUsingOldEmbedding = '''
-  <manifest>
-      <application>
-      </application>
-  </manifest>
-  ''';
-      const String kAndroidManifestUsingNewEmbedding = '''
-  <manifest>
-      <application>
-          <meta-data
-              android:name="flutterEmbedding"
-              android:value="2" />
-      </application>
-  </manifest>
-  ''';
-
       setUp(() {
         featureFlags = MockFeatureFlags();
         when(featureFlags.isLinuxEnabled).thenReturn(false);
@@ -154,13 +138,7 @@
 
       testUsingContext('Registrant uses old embedding in app project', () async {
         when(flutterProject.isModule).thenReturn(false);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
         await injectPlugins(flutterProject);
 
@@ -179,13 +157,7 @@
 
       testUsingContext('Registrant uses new embedding if app uses new embedding', () async {
         when(flutterProject.isModule).thenReturn(false);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingNewEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
 
         await injectPlugins(flutterProject);
 
@@ -204,13 +176,7 @@
 
       testUsingContext('Registrant uses shim for plugins using old embedding if app uses new embedding', () async {
         when(flutterProject.isModule).thenReturn(false);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingNewEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
 
         final Directory pluginUsingJavaAndNewEmbeddingDir =
           fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
@@ -301,13 +267,7 @@
 
       testUsingContext('exits the tool if an app uses the v1 embedding and a plugin only supports the v2 embedding', () async {
         when(flutterProject.isModule).thenReturn(false);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
         final Directory pluginUsingJavaAndNewEmbeddingDir =
           fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
@@ -352,13 +312,7 @@
 
       testUsingContext('allows app use a plugin that supports v1 and v2 embedding', () async {
         when(flutterProject.isModule).thenReturn(false);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
         final Directory pluginUsingJavaAndNewEmbeddingDir =
           fs.systemTempDirectory.createTempSync('flutter_plugin_using_java_and_new_embedding_dir.');
@@ -406,13 +360,7 @@
 
       testUsingContext('Registrant doesn\'t use new embedding if app doesn\'t use new embedding', () async {
         when(flutterProject.isModule).thenReturn(false);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
         await injectPlugins(flutterProject);
 
@@ -431,13 +379,7 @@
 
       testUsingContext('Registrant uses old embedding in module project', () async {
         when(flutterProject.isModule).thenReturn(true);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
         await injectPlugins(flutterProject);
 
@@ -456,13 +398,7 @@
 
       testUsingContext('Registrant uses new embedding if module uses new embedding', () async {
         when(flutterProject.isModule).thenReturn(true);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingNewEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v2);
 
         await injectPlugins(flutterProject);
 
@@ -481,13 +417,7 @@
 
       testUsingContext('Registrant doesn\'t use new embedding if module doesn\'t use new embedding', () async {
         when(flutterProject.isModule).thenReturn(true);
-
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
+        when(androidProject.getEmbeddingVersion()).thenReturn(AndroidEmbeddingVersion.v1);
 
         await injectPlugins(flutterProject);
 
@@ -522,14 +452,6 @@
         when(flutterProject.isModule).thenReturn(true);
         when(featureFlags.isWebEnabled).thenReturn(true);
 
-        // injectPlugins will crash if there is no AndroidManifest
-        final File androidManifest = flutterProject.directory
-          .childDirectory('android')
-          .childFile('AndroidManifest.xml')
-          ..createSync(recursive: true)
-          ..writeAsStringSync(kAndroidManifestUsingOldEmbedding);
-        when(androidProject.appManifestFile).thenReturn(androidManifest);
-
         final Directory webPluginWithNestedFile =
             fs.systemTempDirectory.createTempSync('web_plugin_with_nested');
         webPluginWithNestedFile.childFile('pubspec.yaml').writeAsStringSync('''