Add to app measurement (#33458)

diff --git a/packages/flutter_tools/test/commands/create_test.dart b/packages/flutter_tools/test/commands/create_test.dart
index 4b1dd0f..b5453cb 100644
--- a/packages/flutter_tools/test/commands/create_test.dart
+++ b/packages/flutter_tools/test/commands/create_test.dart
@@ -14,13 +14,16 @@
 import 'package:flutter_tools/src/commands/create.dart';
 import 'package:flutter_tools/src/dart/sdk.dart';
 import 'package:flutter_tools/src/project.dart';
+import 'package:flutter_tools/src/usage.dart';
 import 'package:flutter_tools/src/version.dart';
+
 import 'package:mockito/mockito.dart';
 import 'package:process/process.dart';
 
 import '../src/common.dart';
 import '../src/context.dart';
 
+
 const String frameworkRevision = '12345678';
 const String frameworkChannel = 'omega';
 final Generator _kNoColorTerminalPlatform = () => FakePlatform.fromPlatform(const LocalPlatform())..stdoutSupportsAnsi = false;
@@ -927,8 +930,71 @@
     HttpClientFactory: () =>
         () => MockHttpClient(404, result: 'not found'),
   });
+
+  group('usageValues', () {
+    testUsingContext('set template type as usage value', () async {
+      Cache.flutterRoot = '../..';
+
+      final CreateCommand command = CreateCommand();
+      final CommandRunner<void> runner = createTestCommandRunner(command);
+
+      await runner.run(<String>['create', '--no-pub', '--template=module', projectDir.path]);
+      expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'module'));
+
+      await runner.run(<String>['create', '--no-pub', '--template=app', projectDir.path]);
+      expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'app'));
+
+      await runner.run(<String>['create', '--no-pub', '--template=package', projectDir.path]);
+      expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'package'));
+
+      await runner.run(<String>['create', '--no-pub', '--template=plugin', projectDir.path]);
+      expect(await command.usageValues, containsPair(kCommandCreateProjectType, 'plugin'));
+
+    }, timeout: allowForCreateFlutterProject);
+
+    testUsingContext('set iOS host language type as usage value', () async {
+      Cache.flutterRoot = '../..';
+
+      final CreateCommand command = CreateCommand();
+      final CommandRunner<void> runner = createTestCommandRunner(command);
+
+      await runner.run(<String>['create', '--no-pub', '--template=app', projectDir.path]);
+      expect(await command.usageValues, containsPair(kCommandCreateIosLanguage, 'objc'));
+
+      await runner.run(<String>[
+        'create',
+        '--no-pub',
+        '--template=app',
+        '--ios-language=swift',
+        projectDir.path,
+      ]);
+      expect(await command.usageValues, containsPair(kCommandCreateIosLanguage, 'swift'));
+
+    }, timeout: allowForCreateFlutterProject);
+
+    testUsingContext('set Android host language type as usage value', () async {
+      Cache.flutterRoot = '../..';
+
+      final CreateCommand command = CreateCommand();
+      final CommandRunner<void> runner = createTestCommandRunner(command);
+
+      await runner.run(<String>['create', '--no-pub', '--template=app', projectDir.path]);
+      expect(await command.usageValues, containsPair(kCommandCreateAndroidLanguage, 'java'));
+
+      await runner.run(<String>[
+        'create',
+        '--no-pub',
+        '--template=app',
+        '--android-language=kotlin',
+        projectDir.path,
+      ]);
+      expect(await command.usageValues, containsPair(kCommandCreateAndroidLanguage, 'kotlin'));
+
+    }, timeout: allowForCreateFlutterProject);
+  });
 }
 
+
 Future<void> _createProject(
   Directory dir,
   List<String> createArgs,
diff --git a/packages/flutter_tools/test/commands/packages_test.dart b/packages/flutter_tools/test/commands/packages_test.dart
index 94dfbae..e3b6119 100644
--- a/packages/flutter_tools/test/commands/packages_test.dart
+++ b/packages/flutter_tools/test/commands/packages_test.dart
@@ -10,6 +10,7 @@
 import 'package:flutter_tools/src/base/utils.dart';
 import 'package:flutter_tools/src/cache.dart';
 import 'package:flutter_tools/src/commands/packages.dart';
+import 'package:flutter_tools/src/usage.dart';
 import 'package:process/process.dart';
 
 import '../src/common.dart';
@@ -57,7 +58,7 @@
       return projectPath;
     }
 
-    Future<void> runCommandIn(String projectPath, String verb, { List<String> args }) async {
+    Future<PackagesCommand> runCommandIn(String projectPath, String verb, { List<String> args }) async {
       final PackagesCommand command = PackagesCommand();
       final CommandRunner<void> runner = createTestCommandRunner(command);
 
@@ -67,6 +68,7 @@
       commandArgs.add(projectPath);
 
       await runner.run(commandArgs);
+      return command;
     }
 
     void expectExists(String projectPath, String relPath) {
@@ -217,6 +219,39 @@
       expectZeroPluginsInjected(projectPath);
     }, timeout: allowForCreateFlutterProject);
 
+    testUsingContext('set the number of plugins as usage value', () async {
+      final String projectPath = await createProject(tempDir,
+        arguments: <String>['--no-pub', '--template=module']);
+      removeGeneratedFiles(projectPath);
+
+      final PackagesCommand command = await runCommandIn(projectPath, 'get');
+      final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;
+
+      expect(await getCommand.usageValues, containsPair(kCommandPackagesNumberPlugins, '0'));
+    }, timeout: allowForCreateFlutterProject);
+
+    testUsingContext('indicate that the project is not a module 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(kCommandPackagesProjectModule, 'false'));
+    }, timeout: allowForCreateFlutterProject);
+
+    testUsingContext('indicate that the project is a module in usage value', () async {
+      final String projectPath = await createProject(tempDir,
+        arguments: <String>['--no-pub', '--template=module']);
+      removeGeneratedFiles(projectPath);
+
+      final PackagesCommand command = await runCommandIn(projectPath, 'get');
+      final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand;
+
+      expect(await getCommand.usageValues, containsPair(kCommandPackagesProjectModule, 'true'));
+    }, timeout: allowForCreateFlutterProject);
+
     testUsingContext('upgrade fetches packages', () async {
       final String projectPath = await createProject(tempDir,
         arguments: <String>['--no-pub', '--template=module']);
diff --git a/packages/flutter_tools/test/project_test.dart b/packages/flutter_tools/test/project_test.dart
index 9f281ff..6273421 100644
--- a/packages/flutter_tools/test/project_test.dart
+++ b/packages/flutter_tools/test/project_test.dart
@@ -227,6 +227,41 @@
       });
     });
 
+    group('language', () {
+      MockXcodeProjectInterpreter mockXcodeProjectInterpreter;
+      MemoryFileSystem fs;
+      setUp(() {
+        fs = MemoryFileSystem();
+        mockXcodeProjectInterpreter = MockXcodeProjectInterpreter();
+      });
+
+      testInMemory('default host app language', () async {
+        final FlutterProject project = await someProject();
+        expect(project.ios.isSwift, isFalse);
+        expect(project.android.isKotlin, isFalse);
+      });
+
+      testUsingContext('swift and kotlin host app language', () async {
+        final FlutterProject project = await someProject();
+
+        when(mockXcodeProjectInterpreter.getBuildSettings(any, any)).thenReturn(<String, String>{
+          'SWIFT_VERSION': '3.0',
+        });
+        addAndroidGradleFile(project.directory,
+          gradleFileContent: () {
+      return '''
+apply plugin: 'com.android.application'
+apply plugin: 'kotlin-android'
+''';
+        });
+        expect(project.ios.isSwift, isTrue);
+        expect(project.android.isKotlin, isTrue);
+      }, overrides: <Type, Generator>{
+          FileSystem: () => fs,
+          XcodeProjectInterpreter: () => mockXcodeProjectInterpreter,
+      });
+    });
+
     group('product bundle identifier', () {
       MemoryFileSystem fs;
       MockIOSWorkflow mockIOSWorkflow;
@@ -251,7 +286,9 @@
       });
       testWithMocks('from pbxproj file, if no plist', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, 'io.flutter.someProject');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject');
+        });
         expect(project.ios.productBundleIdentifier, 'io.flutter.someProject');
       });
       testWithMocks('from plist, if no variables', () async {
@@ -261,7 +298,9 @@
       });
       testWithMocks('from pbxproj and plist, if default variable', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, 'io.flutter.someProject');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject');
+        });
         when(mockIOSWorkflow.getPlistValueFromFile(any, any)).thenReturn('\$(PRODUCT_BUNDLE_IDENTIFIER)');
         expect(project.ios.productBundleIdentifier, 'io.flutter.someProject');
       });
@@ -276,17 +315,23 @@
       });
       testWithMocks('empty surrounded by quotes', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, '', qualifier: '"');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('', qualifier: '"');
+        });
         expect(project.ios.productBundleIdentifier, '');
       });
       testWithMocks('surrounded by double quotes', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, 'io.flutter.someProject', qualifier: '"');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject', qualifier: '"');
+        });
         expect(project.ios.productBundleIdentifier, 'io.flutter.someProject');
       });
       testWithMocks('surrounded by single quotes', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, 'io.flutter.someProject', qualifier: '\'');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject', qualifier: '\'');
+        });
         expect(project.ios.productBundleIdentifier, 'io.flutter.someProject');
       });
     });
@@ -303,22 +348,32 @@
       });
       testInMemory('is populated from iOS bundle identifier', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, 'io.flutter.someProject');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject', qualifier: '\'');
+        });
         expect(project.organizationNames, <String>['io.flutter']);
       });
       testInMemory('is populated from Android application ID', () async {
         final FlutterProject project = await someProject();
-        addAndroidWithApplicationId(project.directory, 'io.flutter.someproject');
+        addAndroidGradleFile(project.directory,
+          gradleFileContent: () {
+            return gradleFileWithApplicationId('io.flutter.someproject');
+          });
         expect(project.organizationNames, <String>['io.flutter']);
       });
       testInMemory('is populated from iOS bundle identifier in plugin example', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.example.directory, 'io.flutter.someProject');
+        addIosProjectFile(project.example.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject', qualifier: '\'');
+        });
         expect(project.organizationNames, <String>['io.flutter']);
       });
       testInMemory('is populated from Android application ID in plugin example', () async {
         final FlutterProject project = await someProject();
-        addAndroidWithApplicationId(project.example.directory, 'io.flutter.someproject');
+        addAndroidGradleFile(project.example.directory,
+          gradleFileContent: () {
+            return gradleFileWithApplicationId('io.flutter.someproject');
+          });
         expect(project.organizationNames, <String>['io.flutter']);
       });
       testInMemory('is populated from Android group in plugin', () async {
@@ -328,14 +383,24 @@
       });
       testInMemory('is singleton, if sources agree', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, 'io.flutter.someProject');
-        addAndroidWithApplicationId(project.directory, 'io.flutter.someproject');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject');
+        });
+        addAndroidGradleFile(project.directory,
+          gradleFileContent: () {
+            return gradleFileWithApplicationId('io.flutter.someproject');
+          });
         expect(project.organizationNames, <String>['io.flutter']);
       });
       testInMemory('is non-singleton, if sources disagree', () async {
         final FlutterProject project = await someProject();
-        addIosWithBundleId(project.directory, 'io.flutter.someProject');
-        addAndroidWithApplicationId(project.directory, 'io.clutter.someproject');
+        addIosProjectFile(project.directory, projectFileContent: () {
+          return projectFileWithBundleId('io.flutter.someProject');
+        });
+        addAndroidGradleFile(project.directory,
+          gradleFileContent: () {
+            return gradleFileWithApplicationId('io.clutter.someproject');
+          });
         expect(
           project.organizationNames,
           <String>['io.flutter', 'io.clutter'],
@@ -475,22 +540,22 @@
   expect(entity.existsSync(), isFalse);
 }
 
-void addIosWithBundleId(Directory directory, String id, {String qualifier}) {
+void addIosProjectFile(Directory directory, {String projectFileContent()}) {
   directory
       .childDirectory('ios')
       .childDirectory('Runner.xcodeproj')
       .childFile('project.pbxproj')
         ..createSync(recursive: true)
-    ..writeAsStringSync(projectFileWithBundleId(id, qualifier: qualifier));
+    ..writeAsStringSync(projectFileContent());
 }
 
-void addAndroidWithApplicationId(Directory directory, String id) {
+void addAndroidGradleFile(Directory directory, { String gradleFileContent() }) {
   directory
       .childDirectory('android')
       .childDirectory('app')
       .childFile('build.gradle')
         ..createSync(recursive: true)
-        ..writeAsStringSync(gradleFileWithApplicationId(id));
+        ..writeAsStringSync(gradleFileContent());
 }
 
 void addAndroidWithGroup(Directory directory, String id) {