From 2acd0007d6b9fa3bb488222c9ba55c33494b42c5 Mon Sep 17 00:00:00 2001 From: Lau Ching Jun Date: Tue, 18 May 2021 20:29:03 -0700 Subject: [PATCH] Refactor CustomDimensions in analytics to be type safe (#82531) --- .../lib/src/commands/assemble.dart | 14 +- .../lib/src/commands/build_aar.dart | 20 +- .../lib/src/commands/build_apk.dart | 24 +- .../lib/src/commands/build_appbundle.dart | 21 +- .../lib/src/commands/build_bundle.dart | 12 +- .../lib/src/commands/create.dart | 12 +- .../lib/src/commands/packages.dart | 22 +- .../flutter_tools/lib/src/commands/run.dart | 21 +- .../lib/src/reporting/custom_dimensions.dart | 370 ++++++++++++++++++ .../lib/src/reporting/disabled_usage.dart | 4 +- .../lib/src/reporting/events.dart | 63 ++- .../lib/src/reporting/reporting.dart | 1 + .../lib/src/reporting/usage.dart | 114 ++---- .../lib/src/runner/flutter_command.dart | 12 +- .../hermetic/create_usage_test.dart | 21 +- .../commands.shard/hermetic/pub_get_test.dart | 30 +- .../commands.shard/hermetic/run_test.dart | 4 +- .../permeable/build_aar_test.dart | 9 +- .../permeable/build_apk_test.dart | 27 +- .../permeable/build_appbundle_test.dart | 19 +- .../permeable/build_bundle_test.dart | 10 +- .../permeable/packages_test.dart | 19 +- .../test/general.shard/analytics_test.dart | 4 +- .../android/android_gradle_builder_test.dart | 10 +- .../android/gradle_errors_test.dart | 24 +- .../android/gradle_find_bundle_test.dart | 6 +- .../test/general.shard/ios/mac_test.dart | 8 +- .../general.shard/reporting/events_test.dart | 12 +- .../general.shard/resident_runner_test.dart | 65 ++- .../resident_web_runner_test.dart | 8 +- .../runner/flutter_command_test.dart | 6 +- .../general.shard/runner/runner_test.dart | 4 +- 32 files changed, 625 insertions(+), 371 deletions(-) create mode 100644 packages/flutter_tools/lib/src/reporting/custom_dimensions.dart diff --git a/packages/flutter_tools/lib/src/commands/assemble.dart b/packages/flutter_tools/lib/src/commands/assemble.dart index d908ec3e93f..14d9bc4dc59 100644 --- a/packages/flutter_tools/lib/src/commands/assemble.dart +++ b/packages/flutter_tools/lib/src/commands/assemble.dart @@ -140,20 +140,20 @@ class AssembleCommand extends FlutterCommand { String get name => 'assemble'; @override - Future> get usageValues async { + Future get usageValues async { final FlutterProject flutterProject = FlutterProject.current(); if (flutterProject == null) { - return const {}; + return const CustomDimensions(); } try { - return { - CustomDimensions.commandBuildBundleTargetPlatform: environment.defines[kTargetPlatform], - CustomDimensions.commandBuildBundleIsModule: '${flutterProject.isModule}', - }; + return CustomDimensions( + commandBuildBundleTargetPlatform: environment.defines[kTargetPlatform], + commandBuildBundleIsModule: flutterProject.isModule, + ); } on Exception { // We've failed to send usage. } - return const {}; + return const CustomDimensions(); } @override diff --git a/packages/flutter_tools/lib/src/commands/build_aar.dart b/packages/flutter_tools/lib/src/commands/build_aar.dart index 8d904a99961..4a3d2776f5a 100644 --- a/packages/flutter_tools/lib/src/commands/build_aar.dart +++ b/packages/flutter_tools/lib/src/commands/build_aar.dart @@ -75,21 +75,25 @@ class BuildAarCommand extends BuildSubCommand { }; @override - Future> get usageValues async { - final Map usage = {}; + Future get usageValues async { final FlutterProject flutterProject = _getProject(); if (flutterProject == null) { - return usage; + return const CustomDimensions(); } + + String projectType; if (flutterProject.manifest.isModule) { - usage[CustomDimensions.commandBuildAarProjectType] = 'module'; + projectType = 'module'; } else if (flutterProject.manifest.isPlugin) { - usage[CustomDimensions.commandBuildAarProjectType] = 'plugin'; + projectType = 'plugin'; } else { - usage[CustomDimensions.commandBuildAarProjectType] = 'app'; + projectType = 'app'; } - usage[CustomDimensions.commandBuildAarTargetPlatform] = stringsArg('target-platform').join(','); - return usage; + + return CustomDimensions( + commandBuildAarProjectType: projectType, + commandBuildAarTargetPlatform: stringsArg('target-platform').join(','), + ); } @override diff --git a/packages/flutter_tools/lib/src/commands/build_apk.dart b/packages/flutter_tools/lib/src/commands/build_apk.dart index 6143965ccb7..f81f29252e1 100644 --- a/packages/flutter_tools/lib/src/commands/build_apk.dart +++ b/packages/flutter_tools/lib/src/commands/build_apk.dart @@ -68,25 +68,25 @@ class BuildApkCommand extends BuildSubCommand { ' * https://developer.android.com/studio/build/configure-apk-splits#configure-abi-split'; @override - Future> get usageValues async { - final Map usage = {}; - - usage[CustomDimensions.commandBuildApkTargetPlatform] = - stringsArg('target-platform').join(','); - usage[CustomDimensions.commandBuildApkSplitPerAbi] = - boolArg('split-per-abi').toString(); + Future get usageValues async { + String buildMode; if (boolArg('release')) { - usage[CustomDimensions.commandBuildApkBuildMode] = 'release'; + buildMode = 'release'; } else if (boolArg('debug')) { - usage[CustomDimensions.commandBuildApkBuildMode] = 'debug'; + buildMode = 'debug'; } else if (boolArg('profile')) { - usage[CustomDimensions.commandBuildApkBuildMode] = 'profile'; + buildMode = 'profile'; } else { // The build defaults to release. - usage[CustomDimensions.commandBuildApkBuildMode] = 'release'; + buildMode = 'release'; } - return usage; + + return CustomDimensions( + commandBuildApkTargetPlatform: stringsArg('target-platform').join(','), + commandBuildApkBuildMode: buildMode, + commandBuildApkSplitPerAbi: boolArg('split-per-abi'), + ); } @override diff --git a/packages/flutter_tools/lib/src/commands/build_appbundle.dart b/packages/flutter_tools/lib/src/commands/build_appbundle.dart index d074e28bc8b..4eb512db661 100644 --- a/packages/flutter_tools/lib/src/commands/build_appbundle.dart +++ b/packages/flutter_tools/lib/src/commands/build_appbundle.dart @@ -82,23 +82,24 @@ class BuildAppBundleCommand extends BuildSubCommand { 'suitable for deploying to app stores. \n app bundle improves your app size'; @override - Future> get usageValues async { - final Map usage = {}; - - usage[CustomDimensions.commandBuildAppBundleTargetPlatform] = - stringsArg('target-platform').join(','); + Future get usageValues async { + String buildMode; if (boolArg('release')) { - usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'release'; + buildMode = 'release'; } else if (boolArg('debug')) { - usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'debug'; + buildMode = 'debug'; } else if (boolArg('profile')) { - usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'profile'; + buildMode = 'profile'; } else { // The build defaults to release. - usage[CustomDimensions.commandBuildAppBundleBuildMode] = 'release'; + buildMode = 'release'; } - return usage; + + return CustomDimensions( + commandBuildAppBundleTargetPlatform: stringsArg('target-platform').join(','), + commandBuildAppBundleBuildMode: buildMode, + ); } @override diff --git a/packages/flutter_tools/lib/src/commands/build_bundle.dart b/packages/flutter_tools/lib/src/commands/build_bundle.dart index f1a16907270..b19fcc70a8e 100644 --- a/packages/flutter_tools/lib/src/commands/build_bundle.dart +++ b/packages/flutter_tools/lib/src/commands/build_bundle.dart @@ -69,16 +69,16 @@ class BuildBundleCommand extends BuildSubCommand { ' iOS runtimes.'; @override - Future> get usageValues async { + Future get usageValues async { final String projectDir = globals.fs.file(targetFile).parent.parent.path; final FlutterProject flutterProject = FlutterProject.fromDirectory(globals.fs.directory(projectDir)); if (flutterProject == null) { - return const {}; + return const CustomDimensions(); } - return { - CustomDimensions.commandBuildBundleTargetPlatform: stringArg('target-platform'), - CustomDimensions.commandBuildBundleIsModule: '${flutterProject.isModule}', - }; + return CustomDimensions( + commandBuildBundleTargetPlatform: stringArg('target-platform'), + commandBuildBundleIsModule: flutterProject.isModule, + ); } @override diff --git a/packages/flutter_tools/lib/src/commands/create.dart b/packages/flutter_tools/lib/src/commands/create.dart index ffc29ce739e..e30c10f9cdf 100644 --- a/packages/flutter_tools/lib/src/commands/create.dart +++ b/packages/flutter_tools/lib/src/commands/create.dart @@ -79,12 +79,12 @@ class CreateCommand extends CreateBase { String get invocation => '${runner.executableName} $name '; @override - Future> get usageValues async { - return { - CustomDimensions.commandCreateProjectType: stringArg('template'), - CustomDimensions.commandCreateAndroidLanguage: stringArg('android-language'), - CustomDimensions.commandCreateIosLanguage: stringArg('ios-language'), - }; + Future get usageValues async { + return CustomDimensions( + commandCreateProjectType: stringArg('template'), + commandCreateAndroidLanguage: stringArg('android-language'), + commandCreateIosLanguage: stringArg('ios-language'), + ); } // Lazy-initialize the net utilities with values from the context. diff --git a/packages/flutter_tools/lib/src/commands/packages.dart b/packages/flutter_tools/lib/src/commands/packages.dart index 02a7ccc9d5d..8a6bd96cb7c 100644 --- a/packages/flutter_tools/lib/src/commands/packages.dart +++ b/packages/flutter_tools/lib/src/commands/packages.dart @@ -81,13 +81,15 @@ class PackagesGetCommand extends FlutterCommand { /// The pub packages usage values are incorrect since these are calculated/sent /// before pub get completes. This needs to be performed after dependency resolution. @override - Future> get usageValues async { - final Map usageValues = {}; + Future get usageValues async { final String workingDirectory = argResults.rest.length == 1 ? argResults.rest[0] : null; final String target = findProjectRoot(globals.fs, workingDirectory); if (target == null) { - return usageValues; + return const CustomDimensions(); } + + int numberPlugins; + final FlutterProject rootProject = FlutterProject.fromDirectory(globals.fs.directory(target)); // Do not send plugin analytics if pub has not run before. final bool hasPlugins = rootProject.flutterPluginsDependenciesFile.existsSync() @@ -97,14 +99,16 @@ class PackagesGetCommand extends FlutterCommand { // Do not fail pub get if package config files are invalid before pub has // had a chance to run. final List plugins = await findPlugins(rootProject, throwOnError: false); - usageValues[CustomDimensions.commandPackagesNumberPlugins] = plugins.length.toString(); + numberPlugins = plugins.length; } else { - usageValues[CustomDimensions.commandPackagesNumberPlugins] = '0'; + numberPlugins = 0; } - usageValues[CustomDimensions.commandPackagesProjectModule] = '${rootProject.isModule}'; - usageValues[CustomDimensions.commandPackagesAndroidEmbeddingVersion] = - rootProject.android.getEmbeddingVersion().toString().split('.').last; - return usageValues; + + return CustomDimensions( + commandPackagesNumberPlugins: numberPlugins, + commandPackagesProjectModule: rootProject.isModule, + commandPackagesAndroidEmbeddingVersion: rootProject.android.getEmbeddingVersion().toString().split('.').last, + ); } Future _runPubGet(String directory, FlutterProject flutterProject) async { diff --git a/packages/flutter_tools/lib/src/commands/run.dart b/packages/flutter_tools/lib/src/commands/run.dart index c66ca4b903f..c747b999c6e 100644 --- a/packages/flutter_tools/lib/src/commands/run.dart +++ b/packages/flutter_tools/lib/src/commands/run.dart @@ -357,7 +357,7 @@ class RunCommand extends RunCommandBase { } @override - Future> get usageValues async { + Future get usageValues async { String deviceType, deviceOsVersion; bool isEmulator; bool anyAndroidDevices = false; @@ -410,16 +410,15 @@ class RunCommand extends RunCommandBase { final BuildInfo buildInfo = await getBuildInfo(); final String modeName = buildInfo.modeName; - return { - CustomDimensions.commandRunIsEmulator: '$isEmulator', - CustomDimensions.commandRunTargetName: deviceType, - CustomDimensions.commandRunTargetOsVersion: deviceOsVersion, - CustomDimensions.commandRunModeName: modeName, - CustomDimensions.commandRunProjectModule: '${FlutterProject.current().isModule}', - CustomDimensions.commandRunProjectHostLanguage: hostLanguage.join(','), - if (androidEmbeddingVersion != null) - CustomDimensions.commandRunAndroidEmbeddingVersion: androidEmbeddingVersion, - }; + return CustomDimensions( + commandRunIsEmulator: isEmulator, + commandRunTargetName: deviceType, + commandRunTargetOsVersion: deviceOsVersion, + commandRunModeName: modeName, + commandRunProjectModule: FlutterProject.current().isModule, + commandRunProjectHostLanguage: hostLanguage.join(','), + commandRunAndroidEmbeddingVersion: androidEmbeddingVersion, + ); } @override diff --git a/packages/flutter_tools/lib/src/reporting/custom_dimensions.dart b/packages/flutter_tools/lib/src/reporting/custom_dimensions.dart new file mode 100644 index 00000000000..f2cb658f8ec --- /dev/null +++ b/packages/flutter_tools/lib/src/reporting/custom_dimensions.dart @@ -0,0 +1,370 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +part of reporting; + +/// The collection of custom dimensions understood by the analytics backend. +/// When adding to this list, first ensure that the custom dimension is +/// defined in the backend, or will be defined shortly after the relevant PR +/// lands. +@immutable +class CustomDimensions { + const CustomDimensions({ + this.sessionHostOsDetails, + this.sessionChannelName, + this.commandRunIsEmulator, + this.commandRunTargetName, + this.hotEventReason, + this.hotEventFinalLibraryCount, + this.hotEventSyncedLibraryCount, + this.hotEventSyncedClassesCount, + this.hotEventSyncedProceduresCount, + this.hotEventSyncedBytes, + this.hotEventInvalidatedSourcesCount, + this.hotEventTransferTimeInMs, + this.hotEventOverallTimeInMs, + this.commandRunProjectType, + this.commandRunProjectHostLanguage, + this.commandCreateAndroidLanguage, + this.commandCreateIosLanguage, + this.commandRunProjectModule, + this.commandCreateProjectType, + this.commandPackagesNumberPlugins, + this.commandPackagesProjectModule, + this.commandRunTargetOsVersion, + this.commandRunModeName, + this.commandBuildBundleTargetPlatform, + this.commandBuildBundleIsModule, + this.commandResult, + this.hotEventTargetPlatform, + this.hotEventSdkName, + this.hotEventEmulator, + this.hotEventFullRestart, + this.commandHasTerminal, + this.enabledFlutterFeatures, + this.localTime, + this.commandBuildAarTargetPlatform, + this.commandBuildAarProjectType, + this.buildEventCommand, + this.buildEventSettings, + this.commandBuildApkTargetPlatform, + this.commandBuildApkBuildMode, + this.commandBuildApkSplitPerAbi, + this.commandBuildAppBundleTargetPlatform, + this.commandBuildAppBundleBuildMode, + this.buildEventError, + this.commandResultEventMaxRss, + this.commandRunAndroidEmbeddingVersion, + this.commandPackagesAndroidEmbeddingVersion, + this.nullSafety, + this.fastReassemble, + this.nullSafeMigratedLibraries, + this.nullSafeTotalLibraries, + }); + + final String? sessionHostOsDetails; // cd1 + final String? sessionChannelName; // cd2 + final bool? commandRunIsEmulator; // cd3 + final String? commandRunTargetName; // cd4 + final String? hotEventReason; // cd5 + final int? hotEventFinalLibraryCount; // cd6 + final int? hotEventSyncedLibraryCount; // cd7 + final int? hotEventSyncedClassesCount; // cd8 + final int? hotEventSyncedProceduresCount; // cd9 + final int? hotEventSyncedBytes; // cd10 + final int? hotEventInvalidatedSourcesCount; // cd11 + final int? hotEventTransferTimeInMs; // cd12 + final int? hotEventOverallTimeInMs; // cd13 + final String? commandRunProjectType; // cd14 + final String? commandRunProjectHostLanguage; // cd15 + final String? commandCreateAndroidLanguage; // cd16 + final String? commandCreateIosLanguage; // cd17 + final bool? commandRunProjectModule; // cd18 + final String? commandCreateProjectType; // cd19 + final int? commandPackagesNumberPlugins; // cd20 + final bool? commandPackagesProjectModule; // cd21 + final String? commandRunTargetOsVersion; // cd22 + final String? commandRunModeName; // cd23 + final String? commandBuildBundleTargetPlatform; // cd24 + final bool? commandBuildBundleIsModule; // cd25 + final String? commandResult; // cd26 + final String? hotEventTargetPlatform; // cd27 + final String? hotEventSdkName; // cd28 + final bool? hotEventEmulator; // cd29 + final bool? hotEventFullRestart; // cd30 + final bool? commandHasTerminal; // cd31 + final String? enabledFlutterFeatures; // cd32 + final String? localTime; // cd33 + final String? commandBuildAarTargetPlatform; // cd34 + final String? commandBuildAarProjectType; // cd35 + final String? buildEventCommand; // cd36 + final String? buildEventSettings; // cd37 + final String? commandBuildApkTargetPlatform; // cd38 + final String? commandBuildApkBuildMode; // cd39 + final bool? commandBuildApkSplitPerAbi; // cd40 + final String? commandBuildAppBundleTargetPlatform; // cd41 + final String? commandBuildAppBundleBuildMode; // cd42 + final String? buildEventError; // cd43 + final int? commandResultEventMaxRss; // cd44 + final String? commandRunAndroidEmbeddingVersion; // cd45 + final String? commandPackagesAndroidEmbeddingVersion; // cd46 + final bool? nullSafety; // cd47 + final bool? fastReassemble; // cd48 + final int? nullSafeMigratedLibraries; // cd49 + final int? nullSafeTotalLibraries; // cd50 + + /// Convert to a map that will be used to upload to the analytics backend. + Map toMap() => { + if (sessionHostOsDetails != null) cdKey(CustomDimensionsEnum.sessionHostOsDetails): sessionHostOsDetails.toString(), + if (sessionChannelName != null) cdKey(CustomDimensionsEnum.sessionChannelName): sessionChannelName.toString(), + if (commandRunIsEmulator != null) cdKey(CustomDimensionsEnum.commandRunIsEmulator): commandRunIsEmulator.toString(), + if (commandRunTargetName != null) cdKey(CustomDimensionsEnum.commandRunTargetName): commandRunTargetName.toString(), + if (hotEventReason != null) cdKey(CustomDimensionsEnum.hotEventReason): hotEventReason.toString(), + if (hotEventFinalLibraryCount != null) cdKey(CustomDimensionsEnum.hotEventFinalLibraryCount): hotEventFinalLibraryCount.toString(), + if (hotEventSyncedLibraryCount != null) cdKey(CustomDimensionsEnum.hotEventSyncedLibraryCount): hotEventSyncedLibraryCount.toString(), + if (hotEventSyncedClassesCount != null) cdKey(CustomDimensionsEnum.hotEventSyncedClassesCount): hotEventSyncedClassesCount.toString(), + if (hotEventSyncedProceduresCount != null) cdKey(CustomDimensionsEnum.hotEventSyncedProceduresCount): hotEventSyncedProceduresCount.toString(), + if (hotEventSyncedBytes != null) cdKey(CustomDimensionsEnum.hotEventSyncedBytes): hotEventSyncedBytes.toString(), + if (hotEventInvalidatedSourcesCount != null) cdKey(CustomDimensionsEnum.hotEventInvalidatedSourcesCount): hotEventInvalidatedSourcesCount.toString(), + if (hotEventTransferTimeInMs != null) cdKey(CustomDimensionsEnum.hotEventTransferTimeInMs): hotEventTransferTimeInMs.toString(), + if (hotEventOverallTimeInMs != null) cdKey(CustomDimensionsEnum.hotEventOverallTimeInMs): hotEventOverallTimeInMs.toString(), + if (commandRunProjectType != null) cdKey(CustomDimensionsEnum.commandRunProjectType): commandRunProjectType.toString(), + if (commandRunProjectHostLanguage != null) cdKey(CustomDimensionsEnum.commandRunProjectHostLanguage): commandRunProjectHostLanguage.toString(), + if (commandCreateAndroidLanguage != null) cdKey(CustomDimensionsEnum.commandCreateAndroidLanguage): commandCreateAndroidLanguage.toString(), + if (commandCreateIosLanguage != null) cdKey(CustomDimensionsEnum.commandCreateIosLanguage): commandCreateIosLanguage.toString(), + if (commandRunProjectModule != null) cdKey(CustomDimensionsEnum.commandRunProjectModule): commandRunProjectModule.toString(), + if (commandCreateProjectType != null) cdKey(CustomDimensionsEnum.commandCreateProjectType): commandCreateProjectType.toString(), + if (commandPackagesNumberPlugins != null) cdKey(CustomDimensionsEnum.commandPackagesNumberPlugins): commandPackagesNumberPlugins.toString(), + if (commandPackagesProjectModule != null) cdKey(CustomDimensionsEnum.commandPackagesProjectModule): commandPackagesProjectModule.toString(), + if (commandRunTargetOsVersion != null) cdKey(CustomDimensionsEnum.commandRunTargetOsVersion): commandRunTargetOsVersion.toString(), + if (commandRunModeName != null) cdKey(CustomDimensionsEnum.commandRunModeName): commandRunModeName.toString(), + if (commandBuildBundleTargetPlatform != null) cdKey(CustomDimensionsEnum.commandBuildBundleTargetPlatform): commandBuildBundleTargetPlatform.toString(), + if (commandBuildBundleIsModule != null) cdKey(CustomDimensionsEnum.commandBuildBundleIsModule): commandBuildBundleIsModule.toString(), + if (commandResult != null) cdKey(CustomDimensionsEnum.commandResult): commandResult.toString(), + if (hotEventTargetPlatform != null) cdKey(CustomDimensionsEnum.hotEventTargetPlatform): hotEventTargetPlatform.toString(), + if (hotEventSdkName != null) cdKey(CustomDimensionsEnum.hotEventSdkName): hotEventSdkName.toString(), + if (hotEventEmulator != null) cdKey(CustomDimensionsEnum.hotEventEmulator): hotEventEmulator.toString(), + if (hotEventFullRestart != null) cdKey(CustomDimensionsEnum.hotEventFullRestart): hotEventFullRestart.toString(), + if (commandHasTerminal != null) cdKey(CustomDimensionsEnum.commandHasTerminal): commandHasTerminal.toString(), + if (enabledFlutterFeatures != null) cdKey(CustomDimensionsEnum.enabledFlutterFeatures): enabledFlutterFeatures.toString(), + if (localTime != null) cdKey(CustomDimensionsEnum.localTime): localTime.toString(), + if (commandBuildAarTargetPlatform != null) cdKey(CustomDimensionsEnum.commandBuildAarTargetPlatform): commandBuildAarTargetPlatform.toString(), + if (commandBuildAarProjectType != null) cdKey(CustomDimensionsEnum.commandBuildAarProjectType): commandBuildAarProjectType.toString(), + if (buildEventCommand != null) cdKey(CustomDimensionsEnum.buildEventCommand): buildEventCommand.toString(), + if (buildEventSettings != null) cdKey(CustomDimensionsEnum.buildEventSettings): buildEventSettings.toString(), + if (commandBuildApkTargetPlatform != null) cdKey(CustomDimensionsEnum.commandBuildApkTargetPlatform): commandBuildApkTargetPlatform.toString(), + if (commandBuildApkBuildMode != null) cdKey(CustomDimensionsEnum.commandBuildApkBuildMode): commandBuildApkBuildMode.toString(), + if (commandBuildApkSplitPerAbi != null) cdKey(CustomDimensionsEnum.commandBuildApkSplitPerAbi): commandBuildApkSplitPerAbi.toString(), + if (commandBuildAppBundleTargetPlatform != null) cdKey(CustomDimensionsEnum.commandBuildAppBundleTargetPlatform): commandBuildAppBundleTargetPlatform.toString(), + if (commandBuildAppBundleBuildMode != null) cdKey(CustomDimensionsEnum.commandBuildAppBundleBuildMode): commandBuildAppBundleBuildMode.toString(), + if (buildEventError != null) cdKey(CustomDimensionsEnum.buildEventError): buildEventError.toString(), + if (commandResultEventMaxRss != null) cdKey(CustomDimensionsEnum.commandResultEventMaxRss): commandResultEventMaxRss.toString(), + if (commandRunAndroidEmbeddingVersion != null) cdKey(CustomDimensionsEnum.commandRunAndroidEmbeddingVersion): commandRunAndroidEmbeddingVersion.toString(), + if (commandPackagesAndroidEmbeddingVersion != null) cdKey(CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion): commandPackagesAndroidEmbeddingVersion.toString(), + if (nullSafety != null) cdKey(CustomDimensionsEnum.nullSafety): nullSafety.toString(), + if (fastReassemble != null) cdKey(CustomDimensionsEnum.fastReassemble): fastReassemble.toString(), + if (nullSafeMigratedLibraries != null) cdKey(CustomDimensionsEnum.nullSafeMigratedLibraries): nullSafeMigratedLibraries.toString(), + if (nullSafeTotalLibraries != null) cdKey(CustomDimensionsEnum.nullSafeTotalLibraries): nullSafeTotalLibraries.toString(), + }; + + /// Merge the values of two [CustomDimensions] into one. If a value is defined + /// in both instances, the value in [other] will override the value in this. + CustomDimensions merge(CustomDimensions? other) { + if (other == null) { + return this; + } + + return CustomDimensions( + sessionHostOsDetails: other.sessionHostOsDetails ?? sessionHostOsDetails, + sessionChannelName: other.sessionChannelName ?? sessionChannelName, + commandRunIsEmulator: other.commandRunIsEmulator ?? commandRunIsEmulator, + commandRunTargetName: other.commandRunTargetName ?? commandRunTargetName, + hotEventReason: other.hotEventReason ?? hotEventReason, + hotEventFinalLibraryCount: other.hotEventFinalLibraryCount ?? hotEventFinalLibraryCount, + hotEventSyncedLibraryCount: other.hotEventSyncedLibraryCount ?? hotEventSyncedLibraryCount, + hotEventSyncedClassesCount: other.hotEventSyncedClassesCount ?? hotEventSyncedClassesCount, + hotEventSyncedProceduresCount: other.hotEventSyncedProceduresCount ?? hotEventSyncedProceduresCount, + hotEventSyncedBytes: other.hotEventSyncedBytes ?? hotEventSyncedBytes, + hotEventInvalidatedSourcesCount: other.hotEventInvalidatedSourcesCount ?? hotEventInvalidatedSourcesCount, + hotEventTransferTimeInMs: other.hotEventTransferTimeInMs ?? hotEventTransferTimeInMs, + hotEventOverallTimeInMs: other.hotEventOverallTimeInMs ?? hotEventOverallTimeInMs, + commandRunProjectType: other.commandRunProjectType ?? commandRunProjectType, + commandRunProjectHostLanguage: other.commandRunProjectHostLanguage ?? commandRunProjectHostLanguage, + commandCreateAndroidLanguage: other.commandCreateAndroidLanguage ?? commandCreateAndroidLanguage, + commandCreateIosLanguage: other.commandCreateIosLanguage ?? commandCreateIosLanguage, + commandRunProjectModule: other.commandRunProjectModule ?? commandRunProjectModule, + commandCreateProjectType: other.commandCreateProjectType ?? commandCreateProjectType, + commandPackagesNumberPlugins: other.commandPackagesNumberPlugins ?? commandPackagesNumberPlugins, + commandPackagesProjectModule: other.commandPackagesProjectModule ?? commandPackagesProjectModule, + commandRunTargetOsVersion: other.commandRunTargetOsVersion ?? commandRunTargetOsVersion, + commandRunModeName: other.commandRunModeName ?? commandRunModeName, + commandBuildBundleTargetPlatform: other.commandBuildBundleTargetPlatform ?? commandBuildBundleTargetPlatform, + commandBuildBundleIsModule: other.commandBuildBundleIsModule ?? commandBuildBundleIsModule, + commandResult: other.commandResult ?? commandResult, + hotEventTargetPlatform: other.hotEventTargetPlatform ?? hotEventTargetPlatform, + hotEventSdkName: other.hotEventSdkName ?? hotEventSdkName, + hotEventEmulator: other.hotEventEmulator ?? hotEventEmulator, + hotEventFullRestart: other.hotEventFullRestart ?? hotEventFullRestart, + commandHasTerminal: other.commandHasTerminal ?? commandHasTerminal, + enabledFlutterFeatures: other.enabledFlutterFeatures ?? enabledFlutterFeatures, + localTime: other.localTime ?? localTime, + commandBuildAarTargetPlatform: other.commandBuildAarTargetPlatform ?? commandBuildAarTargetPlatform, + commandBuildAarProjectType: other.commandBuildAarProjectType ?? commandBuildAarProjectType, + buildEventCommand: other.buildEventCommand ?? buildEventCommand, + buildEventSettings: other.buildEventSettings ?? buildEventSettings, + commandBuildApkTargetPlatform: other.commandBuildApkTargetPlatform ?? commandBuildApkTargetPlatform, + commandBuildApkBuildMode: other.commandBuildApkBuildMode ?? commandBuildApkBuildMode, + commandBuildApkSplitPerAbi: other.commandBuildApkSplitPerAbi ?? commandBuildApkSplitPerAbi, + commandBuildAppBundleTargetPlatform: other.commandBuildAppBundleTargetPlatform ?? commandBuildAppBundleTargetPlatform, + commandBuildAppBundleBuildMode: other.commandBuildAppBundleBuildMode ?? commandBuildAppBundleBuildMode, + buildEventError: other.buildEventError ?? buildEventError, + commandResultEventMaxRss: other.commandResultEventMaxRss ?? commandResultEventMaxRss, + commandRunAndroidEmbeddingVersion: other.commandRunAndroidEmbeddingVersion ?? commandRunAndroidEmbeddingVersion, + commandPackagesAndroidEmbeddingVersion: other.commandPackagesAndroidEmbeddingVersion ?? commandPackagesAndroidEmbeddingVersion, + nullSafety: other.nullSafety ?? nullSafety, + fastReassemble: other.fastReassemble ?? fastReassemble, + nullSafeMigratedLibraries: other.nullSafeMigratedLibraries ?? nullSafeMigratedLibraries, + nullSafeTotalLibraries: other.nullSafeTotalLibraries ?? nullSafeTotalLibraries, + ); + } + + static CustomDimensions fromMap(Map map) => CustomDimensions( + sessionHostOsDetails: _extractString(map, CustomDimensionsEnum.sessionHostOsDetails), + sessionChannelName: _extractString(map, CustomDimensionsEnum.sessionChannelName), + commandRunIsEmulator: _extractBool(map, CustomDimensionsEnum.commandRunIsEmulator), + commandRunTargetName: _extractString(map, CustomDimensionsEnum.commandRunTargetName), + hotEventReason: _extractString(map, CustomDimensionsEnum.hotEventReason), + hotEventFinalLibraryCount: _extractInt(map, CustomDimensionsEnum.hotEventFinalLibraryCount), + hotEventSyncedLibraryCount: _extractInt(map, CustomDimensionsEnum.hotEventSyncedLibraryCount), + hotEventSyncedClassesCount: _extractInt(map, CustomDimensionsEnum.hotEventSyncedClassesCount), + hotEventSyncedProceduresCount: _extractInt(map, CustomDimensionsEnum.hotEventSyncedProceduresCount), + hotEventSyncedBytes: _extractInt(map, CustomDimensionsEnum.hotEventSyncedBytes), + hotEventInvalidatedSourcesCount: _extractInt(map, CustomDimensionsEnum.hotEventInvalidatedSourcesCount), + hotEventTransferTimeInMs: _extractInt(map, CustomDimensionsEnum.hotEventTransferTimeInMs), + hotEventOverallTimeInMs: _extractInt(map, CustomDimensionsEnum.hotEventOverallTimeInMs), + commandRunProjectType: _extractString(map, CustomDimensionsEnum.commandRunProjectType), + commandRunProjectHostLanguage: _extractString(map, CustomDimensionsEnum.commandRunProjectHostLanguage), + commandCreateAndroidLanguage: _extractString(map, CustomDimensionsEnum.commandCreateAndroidLanguage), + commandCreateIosLanguage: _extractString(map, CustomDimensionsEnum.commandCreateIosLanguage), + commandRunProjectModule: _extractBool(map, CustomDimensionsEnum.commandRunProjectModule), + commandCreateProjectType: _extractString(map, CustomDimensionsEnum.commandCreateProjectType), + commandPackagesNumberPlugins: _extractInt(map, CustomDimensionsEnum.commandPackagesNumberPlugins), + commandPackagesProjectModule: _extractBool(map, CustomDimensionsEnum.commandPackagesProjectModule), + commandRunTargetOsVersion: _extractString(map, CustomDimensionsEnum.commandRunTargetOsVersion), + commandRunModeName: _extractString(map, CustomDimensionsEnum.commandRunModeName), + commandBuildBundleTargetPlatform: _extractString(map, CustomDimensionsEnum.commandBuildBundleTargetPlatform), + commandBuildBundleIsModule: _extractBool(map, CustomDimensionsEnum.commandBuildBundleIsModule), + commandResult: _extractString(map, CustomDimensionsEnum.commandResult), + hotEventTargetPlatform: _extractString(map, CustomDimensionsEnum.hotEventTargetPlatform), + hotEventSdkName: _extractString(map, CustomDimensionsEnum.hotEventSdkName), + hotEventEmulator: _extractBool(map, CustomDimensionsEnum.hotEventEmulator), + hotEventFullRestart: _extractBool(map, CustomDimensionsEnum.hotEventFullRestart), + commandHasTerminal: _extractBool(map, CustomDimensionsEnum.commandHasTerminal), + enabledFlutterFeatures: _extractString(map, CustomDimensionsEnum.enabledFlutterFeatures), + localTime: _extractString(map, CustomDimensionsEnum.localTime), + commandBuildAarTargetPlatform: _extractString(map, CustomDimensionsEnum.commandBuildAarTargetPlatform), + commandBuildAarProjectType: _extractString(map, CustomDimensionsEnum.commandBuildAarProjectType), + buildEventCommand: _extractString(map, CustomDimensionsEnum.buildEventCommand), + buildEventSettings: _extractString(map, CustomDimensionsEnum.buildEventSettings), + commandBuildApkTargetPlatform: _extractString(map, CustomDimensionsEnum.commandBuildApkTargetPlatform), + commandBuildApkBuildMode: _extractString(map, CustomDimensionsEnum.commandBuildApkBuildMode), + commandBuildApkSplitPerAbi: _extractBool(map, CustomDimensionsEnum.commandBuildApkSplitPerAbi), + commandBuildAppBundleTargetPlatform: _extractString(map, CustomDimensionsEnum.commandBuildAppBundleTargetPlatform), + commandBuildAppBundleBuildMode: _extractString(map, CustomDimensionsEnum.commandBuildAppBundleBuildMode), + buildEventError: _extractString(map, CustomDimensionsEnum.buildEventError), + commandResultEventMaxRss: _extractInt(map, CustomDimensionsEnum.commandResultEventMaxRss), + commandRunAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandRunAndroidEmbeddingVersion), + commandPackagesAndroidEmbeddingVersion: _extractString(map, CustomDimensionsEnum.commandPackagesAndroidEmbeddingVersion), + nullSafety: _extractBool(map, CustomDimensionsEnum.nullSafety), + fastReassemble: _extractBool(map, CustomDimensionsEnum.fastReassemble), + nullSafeMigratedLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeMigratedLibraries), + nullSafeTotalLibraries: _extractInt(map, CustomDimensionsEnum.nullSafeTotalLibraries), + ); + + static bool? _extractBool(Map map, CustomDimensionsEnum field) => + map.containsKey(cdKey(field))? map[cdKey(field)] == 'true' : null; + + static String? _extractString(Map map, CustomDimensionsEnum field) => + map.containsKey(cdKey(field))? map[cdKey(field)] : null; + + static int? _extractInt(Map map, CustomDimensionsEnum field) => + map.containsKey(cdKey(field))? int.parse(map[cdKey(field)]!) : null; + + @override + String toString() => toMap().toString(); + + @override + bool operator ==(Object other) { + return other is CustomDimensions && + _mapsEqual(other.toMap(), toMap()); + } + + @override + int get hashCode => + toMap() + .values + .where((String element) => element != null) + .fold(Object().hashCode, + (int value, String element) => value ^ element.hashCode); +} + +/// List of all fields used in CustomDimensions. +/// +/// The index of this enum is used to calculate the key of the fields. Always +/// append to this list when adding new fields, and do not remove or reorder +/// any elements. +enum CustomDimensionsEnum { + sessionHostOsDetails, // cd1 + sessionChannelName, // cd2 + commandRunIsEmulator, // cd3 + commandRunTargetName, // cd4 + hotEventReason, // cd5 + hotEventFinalLibraryCount, // cd6 + hotEventSyncedLibraryCount, // cd7 + hotEventSyncedClassesCount, // cd8 + hotEventSyncedProceduresCount, // cd9 + hotEventSyncedBytes, // cd10 + hotEventInvalidatedSourcesCount, // cd11 + hotEventTransferTimeInMs, // cd12 + hotEventOverallTimeInMs, // cd13 + commandRunProjectType, // cd14 + commandRunProjectHostLanguage, // cd15 + commandCreateAndroidLanguage, // cd16 + commandCreateIosLanguage, // cd17 + commandRunProjectModule, // cd18 + commandCreateProjectType, // cd19 + commandPackagesNumberPlugins, // cd20 + commandPackagesProjectModule, // cd21 + commandRunTargetOsVersion, // cd22 + commandRunModeName, // cd23 + commandBuildBundleTargetPlatform, // cd24 + commandBuildBundleIsModule, // cd25 + commandResult, // cd26 + hotEventTargetPlatform, // cd27 + hotEventSdkName, // cd28 + hotEventEmulator, // cd29 + hotEventFullRestart, // cd30 + commandHasTerminal, // cd31 + enabledFlutterFeatures, // cd32 + localTime, // cd33 + commandBuildAarTargetPlatform, // cd34 + commandBuildAarProjectType, // cd35 + buildEventCommand, // cd36 + buildEventSettings, // cd37 + commandBuildApkTargetPlatform, // cd38 + commandBuildApkBuildMode, // cd39 + commandBuildApkSplitPerAbi, // cd40 + commandBuildAppBundleTargetPlatform, // cd41 + commandBuildAppBundleBuildMode, // cd42 + buildEventError, // cd43 + commandResultEventMaxRss, // cd44 + commandRunAndroidEmbeddingVersion, // cd45 + commandPackagesAndroidEmbeddingVersion, // cd46 + nullSafety, // cd47 + fastReassemble, // cd48 + nullSafeMigratedLibraries, // cd49 + nullSafeTotalLibraries, // cd50 +} + +String cdKey(CustomDimensionsEnum cd) => 'cd${cd.index + 1}'; diff --git a/packages/flutter_tools/lib/src/reporting/disabled_usage.dart b/packages/flutter_tools/lib/src/reporting/disabled_usage.dart index aeda99174b3..661dbd29748 100644 --- a/packages/flutter_tools/lib/src/reporting/disabled_usage.dart +++ b/packages/flutter_tools/lib/src/reporting/disabled_usage.dart @@ -21,7 +21,7 @@ class DisabledUsage implements Usage { String get clientId => ''; @override - void sendCommand(String command, { Map? parameters }) { } + void sendCommand(String command, { CustomDimensions? parameters }) { } @override void sendEvent( @@ -29,7 +29,7 @@ class DisabledUsage implements Usage { String parameter, { String? label, int? value, - Map? parameters, + CustomDimensions? parameters, }) { } @override diff --git a/packages/flutter_tools/lib/src/reporting/events.dart b/packages/flutter_tools/lib/src/reporting/events.dart index 2cfa4308981..5e11d33b240 100644 --- a/packages/flutter_tools/lib/src/reporting/events.dart +++ b/packages/flutter_tools/lib/src/reporting/events.dart @@ -68,32 +68,22 @@ class HotEvent extends UsageEvent { @override void send() { - final Map parameters = _useCdKeys({ - CustomDimensions.hotEventTargetPlatform: targetPlatform, - CustomDimensions.hotEventSdkName: sdkName, - CustomDimensions.hotEventEmulator: emulator.toString(), - CustomDimensions.hotEventFullRestart: fullRestart.toString(), - if (reason != null) - CustomDimensions.hotEventReason: reason!, - if (finalLibraryCount != null) - CustomDimensions.hotEventFinalLibraryCount: finalLibraryCount.toString(), - if (syncedLibraryCount != null) - CustomDimensions.hotEventSyncedLibraryCount: syncedLibraryCount.toString(), - if (syncedClassesCount != null) - CustomDimensions.hotEventSyncedClassesCount: syncedClassesCount.toString(), - if (syncedProceduresCount != null) - CustomDimensions.hotEventSyncedProceduresCount: syncedProceduresCount.toString(), - if (syncedBytes != null) - CustomDimensions.hotEventSyncedBytes: syncedBytes.toString(), - if (invalidatedSourcesCount != null) - CustomDimensions.hotEventInvalidatedSourcesCount: invalidatedSourcesCount.toString(), - if (transferTimeInMs != null) - CustomDimensions.hotEventTransferTimeInMs: transferTimeInMs.toString(), - if (overallTimeInMs != null) - CustomDimensions.hotEventOverallTimeInMs: overallTimeInMs.toString(), - if (fastReassemble != null) - CustomDimensions.fastReassemble: fastReassemble.toString(), - }); + final CustomDimensions parameters = CustomDimensions( + hotEventTargetPlatform: targetPlatform, + hotEventSdkName: sdkName, + hotEventEmulator: emulator, + hotEventFullRestart: fullRestart, + hotEventReason: reason, + hotEventFinalLibraryCount: finalLibraryCount, + hotEventSyncedLibraryCount: syncedLibraryCount, + hotEventSyncedClassesCount: syncedClassesCount, + hotEventSyncedProceduresCount: syncedProceduresCount, + hotEventSyncedBytes: syncedBytes, + hotEventInvalidatedSourcesCount: invalidatedSourcesCount, + hotEventTransferTimeInMs: transferTimeInMs, + hotEventOverallTimeInMs: overallTimeInMs, + fastReassemble: fastReassemble, + ); flutterUsage.sendEvent(category, parameter, parameters: parameters); } } @@ -169,14 +159,11 @@ class BuildEvent extends UsageEvent { @override void send() { - final Map parameters = _useCdKeys({ - if (_command != null) - CustomDimensions.buildEventCommand: _command!, - if (_settings != null) - CustomDimensions.buildEventSettings: _settings!, - if (_eventError != null) - CustomDimensions.buildEventError: _eventError!, - }); + final CustomDimensions parameters = CustomDimensions( + buildEventCommand: _command, + buildEventSettings: _settings, + buildEventError: _eventError, + ); flutterUsage.sendEvent( category, parameter, @@ -290,10 +277,10 @@ class NullSafetyAnalysisEvent implements UsageEvent { } } flutterUsage.sendEvent(kNullSafetyCategory, 'runtime-mode', label: nullSafetyMode.toString()); - flutterUsage.sendEvent(kNullSafetyCategory, 'stats', parameters: { - cdKey(CustomDimensions.nullSafeMigratedLibraries): migrated.toString(), - cdKey(CustomDimensions.nullSafeTotalLibraries): packageConfig.packages.length.toString(), - }); + flutterUsage.sendEvent(kNullSafetyCategory, 'stats', parameters: CustomDimensions( + nullSafeMigratedLibraries: migrated, + nullSafeTotalLibraries: packageConfig.packages.length, + )); if (languageVersion != null) { final String formattedVersion = '${languageVersion.major}.${languageVersion.minor}'; flutterUsage.sendEvent(kNullSafetyCategory, 'language-version', label: formattedVersion); diff --git a/packages/flutter_tools/lib/src/reporting/reporting.dart b/packages/flutter_tools/lib/src/reporting/reporting.dart index 06c4e608a54..16fb3de475e 100644 --- a/packages/flutter_tools/lib/src/reporting/reporting.dart +++ b/packages/flutter_tools/lib/src/reporting/reporting.dart @@ -25,3 +25,4 @@ import 'first_run.dart'; part 'disabled_usage.dart'; part 'events.dart'; part 'usage.dart'; +part 'custom_dimensions.dart'; diff --git a/packages/flutter_tools/lib/src/reporting/usage.dart b/packages/flutter_tools/lib/src/reporting/usage.dart index daa3bdc94b0..d822c7daa08 100644 --- a/packages/flutter_tools/lib/src/reporting/usage.dart +++ b/packages/flutter_tools/lib/src/reporting/usage.dart @@ -6,70 +6,6 @@ part of reporting; const String _kFlutterUA = 'UA-67589403-6'; -/// The collection of custom dimensions understood by the analytics backend. -/// When adding to this list, first ensure that the custom dimension is -/// defined in the backend, or will be defined shortly after the relevant PR -/// lands. -enum CustomDimensions { - sessionHostOsDetails, // cd1 - sessionChannelName, // cd2 - commandRunIsEmulator, // cd3 - commandRunTargetName, // cd4 - hotEventReason, // cd5 - hotEventFinalLibraryCount, // cd6 - hotEventSyncedLibraryCount, // cd7 - hotEventSyncedClassesCount, // cd8 - hotEventSyncedProceduresCount, // cd9 - hotEventSyncedBytes, // cd10 - hotEventInvalidatedSourcesCount, // cd11 - hotEventTransferTimeInMs, // cd12 - hotEventOverallTimeInMs, // cd13 - commandRunProjectType, // cd14 - commandRunProjectHostLanguage, // cd15 - commandCreateAndroidLanguage, // cd16 - commandCreateIosLanguage, // cd17 - commandRunProjectModule, // cd18 - commandCreateProjectType, // cd19 - commandPackagesNumberPlugins, // cd20 - commandPackagesProjectModule, // cd21 - commandRunTargetOsVersion, // cd22 - commandRunModeName, // cd23 - commandBuildBundleTargetPlatform, // cd24 - commandBuildBundleIsModule, // cd25 - commandResult, // cd26 - hotEventTargetPlatform, // cd27 - hotEventSdkName, // cd28 - hotEventEmulator, // cd29 - hotEventFullRestart, // cd30 - commandHasTerminal, // cd31 - enabledFlutterFeatures, // cd32 - localTime, // cd33 - commandBuildAarTargetPlatform, // cd34 - commandBuildAarProjectType, // cd35 - buildEventCommand, // cd36 - buildEventSettings, // cd37 - commandBuildApkTargetPlatform, // cd38 - commandBuildApkBuildMode, // cd39 - commandBuildApkSplitPerAbi, // cd40 - commandBuildAppBundleTargetPlatform, // cd41 - commandBuildAppBundleBuildMode, // cd42 - buildEventError, // cd43 - commandResultEventMaxRss, // cd44 - commandRunAndroidEmbeddingVersion, // cd45 - commandPackagesAndroidEmbeddingVersion, // cd46 - nullSafety, // cd47 - fastReassemble, // cd48 - nullSafeMigratedLibraries, // cd49 - nullSafeTotalLibraries, // cd 50 -} - -String cdKey(CustomDimensions cd) => 'cd${cd.index + 1}'; - -Map _useCdKeys(Map parameters) { - return parameters.map((CustomDimensions k, Object v) => - MapEntry(cdKey(k), v.toString())); -} - abstract class Usage { /// Create a new Usage instance; [versionOverride], [configDirOverride], and /// [logFile] are used for testing. @@ -94,8 +30,8 @@ abstract class Usage { /// Uses the global [Usage] instance to send a 'command' to analytics. static void command(String command, { - Map? parameters, - }) => globals.flutterUsage.sendCommand(command, parameters: parameters == null ? null : _useCdKeys(parameters)); + CustomDimensions? parameters, + }) => globals.flutterUsage.sendCommand(command, parameters: parameters); /// Whether analytics reporting should be suppressed. bool get suppressAnalytics; @@ -119,7 +55,7 @@ abstract class Usage { /// keys are well-defined in [CustomDimensions] above. void sendCommand( String command, { - Map? parameters, + CustomDimensions? parameters, }); /// Sends an 'event' to the underlying analytics implementation. @@ -133,7 +69,7 @@ abstract class Usage { String parameter, { String? label, int? value, - Map? parameters, + CustomDimensions? parameters, }); /// Sends timing information to the underlying analytics implementation. @@ -256,12 +192,12 @@ class _DefaultUsage implements Usage { if (!skipAnalyticsSessionSetup) { // Report a more detailed OS version string than package:usage does by default. analytics.setSessionValue( - cdKey(CustomDimensions.sessionHostOsDetails), + cdKey(CustomDimensionsEnum.sessionHostOsDetails), globals.os.name, ); // Send the branch name as the "channel". analytics.setSessionValue( - cdKey(CustomDimensions.sessionChannelName), + cdKey(CustomDimensionsEnum.sessionChannelName), flutterVersion.getBranchName(redactUnknownBranches: true), ); // For each flutter experimental feature, record a session value in a comma @@ -274,7 +210,7 @@ class _DefaultUsage implements Usage { .map((Feature feature) => feature.configSetting) .join(','); analytics.setSessionValue( - cdKey(CustomDimensions.enabledFlutterFeatures), + cdKey(CustomDimensionsEnum.enabledFlutterFeatures), enabledFeatures, ); @@ -320,16 +256,17 @@ class _DefaultUsage implements Usage { String get clientId => _analytics.clientId; @override - void sendCommand(String command, { Map? parameters }) { + void sendCommand(String command, { CustomDimensions? parameters }) { if (suppressAnalytics) { return; } - final Map paramsWithLocalTime = { - ...?parameters, - cdKey(CustomDimensions.localTime): formatDateTime(_clock.now()), - }; - _analytics.sendScreenView(command, parameters: paramsWithLocalTime); + _analytics.sendScreenView( + command, + parameters: CustomDimensions(localTime: formatDateTime(_clock.now())) + .merge(parameters) + .toMap(), + ); } @override @@ -338,23 +275,20 @@ class _DefaultUsage implements Usage { String parameter, { String? label, int? value, - Map? parameters, + CustomDimensions? parameters, }) { if (suppressAnalytics) { return; } - final Map paramsWithLocalTime = { - ...?parameters, - cdKey(CustomDimensions.localTime): formatDateTime(_clock.now()), - }; - _analytics.sendEvent( category, parameter, label: label, value: value, - parameters: paramsWithLocalTime, + parameters: CustomDimensions(localTime: formatDateTime(_clock.now())) + .merge(parameters) + .toMap(), ); } @@ -516,12 +450,12 @@ class TestUsage implements Usage { void printWelcome() { } @override - void sendCommand(String command, {Map? parameters}) { + void sendCommand(String command, {CustomDimensions? parameters}) { commands.add(TestUsageCommand(command, parameters: parameters)); } @override - void sendEvent(String category, String parameter, {String? label, int? value, Map? parameters}) { + void sendEvent(String category, String parameter, {String? label, int? value, CustomDimensions? parameters}) { events.add(TestUsageEvent(category, parameter, label: label, value: value, parameters: parameters)); } @@ -542,13 +476,13 @@ class TestUsageCommand { const TestUsageCommand(this.command, {this.parameters}); final String command; - final Map? parameters; + final CustomDimensions? parameters; @override bool operator ==(Object other) { return other is TestUsageCommand && other.command == command && - _mapsEqual(other.parameters, parameters); + other.parameters == parameters; } @override @@ -567,7 +501,7 @@ class TestUsageEvent { final String parameter; final String? label; final int? value; - final Map? parameters; + final CustomDimensions? parameters; @override bool operator ==(Object other) { @@ -576,7 +510,7 @@ class TestUsageEvent { other.parameter == parameter && other.label == label && other.value == value && - _mapsEqual(other.parameters, parameters); + other.parameters == parameters; } @override diff --git a/packages/flutter_tools/lib/src/runner/flutter_command.dart b/packages/flutter_tools/lib/src/runner/flutter_command.dart index 3d850642c73..8714d1b6032 100644 --- a/packages/flutter_tools/lib/src/runner/flutter_command.dart +++ b/packages/flutter_tools/lib/src/runner/flutter_command.dart @@ -1063,8 +1063,7 @@ abstract class FlutterCommand extends Command { } /// Additional usage values to be sent with the usage ping. - Future> get usageValues async => - const {}; + Future get usageValues async => const CustomDimensions(); /// Runs this command. /// @@ -1231,12 +1230,9 @@ abstract class FlutterCommand extends Command { setupApplicationPackages(); if (commandPath != null) { - final Map additionalUsageValues = - { - ...?await usageValues, - CustomDimensions.commandHasTerminal: globals.stdio.hasTerminal, - }; - Usage.command(commandPath, parameters: additionalUsageValues); + Usage.command(commandPath, parameters: CustomDimensions( + commandHasTerminal: globals.stdio.hasTerminal, + ).merge(await usageValues)); } return runCommand(); diff --git a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart index 332a56089b2..180014b5ce3 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/create_usage_test.dart @@ -12,7 +12,6 @@ import 'package:flutter_tools/src/convert.dart'; import 'package:flutter_tools/src/doctor.dart'; import 'package:flutter_tools/src/doctor_validator.dart'; import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; -import 'package:flutter_tools/src/reporting/reporting.dart'; import '../../src/context.dart'; import '../../src/test_flutter_command_runner.dart'; @@ -72,16 +71,16 @@ void main() { final CommandRunner runner = createTestCommandRunner(command); await runner.run(['create', '--no-pub', '--template=module', 'testy']); - expect(await command.usageValues, containsPair(CustomDimensions.commandCreateProjectType, 'module')); + expect((await command.usageValues).commandCreateProjectType, 'module'); await runner.run(['create', '--no-pub', '--template=app', 'testy']); - expect(await command.usageValues, containsPair(CustomDimensions.commandCreateProjectType, 'app')); + expect((await command.usageValues).commandCreateProjectType, 'app'); await runner.run(['create', '--no-pub', '--template=package', 'testy']); - expect(await command.usageValues, containsPair(CustomDimensions.commandCreateProjectType, 'package')); + expect((await command.usageValues).commandCreateProjectType, 'package'); await runner.run(['create', '--no-pub', '--template=plugin', 'testy']); - expect(await command.usageValues, containsPair(CustomDimensions.commandCreateProjectType, 'plugin')); + expect((await command.usageValues).commandCreateProjectType, 'plugin'); })); testUsingContext('set iOS host language type as usage value', () => testbed.run(() async { @@ -90,8 +89,7 @@ void main() { await runner.run([ 'create', '--no-pub', '--template=app', 'testy']); - expect(await command.usageValues, - containsPair(CustomDimensions.commandCreateIosLanguage, 'swift')); + expect((await command.usageValues).commandCreateIosLanguage, 'swift'); await runner.run([ 'create', @@ -100,8 +98,7 @@ void main() { '--ios-language=objc', 'testy', ]); - expect(await command.usageValues, - containsPair(CustomDimensions.commandCreateIosLanguage, 'objc')); + expect((await command.usageValues).commandCreateIosLanguage, 'objc'); })); @@ -110,8 +107,7 @@ void main() { final CommandRunner runner = createTestCommandRunner(command); await runner.run(['create', '--no-pub', '--template=app', 'testy']); - expect(await command.usageValues, - containsPair(CustomDimensions.commandCreateAndroidLanguage, 'kotlin')); + expect((await command.usageValues).commandCreateAndroidLanguage, 'kotlin'); await runner.run([ 'create', @@ -120,8 +116,7 @@ void main() { '--android-language=java', 'testy', ]); - expect(await command.usageValues, - containsPair(CustomDimensions.commandCreateAndroidLanguage, 'java')); + expect((await command.usageValues).commandCreateAndroidLanguage, 'java'); })); }); } diff --git a/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart b/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart index 248db5eefb5..6f36128a52e 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/pub_get_test.dart @@ -41,11 +41,11 @@ void main() { await commandRunner.run(['get']); - expect(await command.usageValues, { - CustomDimensions.commandPackagesNumberPlugins: '0', - CustomDimensions.commandPackagesProjectModule: 'false', - CustomDimensions.commandPackagesAndroidEmbeddingVersion: 'v1' - }); + expect(await command.usageValues, const CustomDimensions( + commandPackagesNumberPlugins: 0, + commandPackagesProjectModule: false, + commandPackagesAndroidEmbeddingVersion: 'v1', + )); }, overrides: { Pub: () => pub, ProcessManager: () => FakeProcessManager.any(), @@ -66,11 +66,11 @@ void main() { await commandRunner.run(['get']); - expect(await command.usageValues, { - CustomDimensions.commandPackagesNumberPlugins: '0', - CustomDimensions.commandPackagesProjectModule: 'false', - CustomDimensions.commandPackagesAndroidEmbeddingVersion: 'v1' - }); + expect(await command.usageValues, const CustomDimensions( + commandPackagesNumberPlugins: 0, + commandPackagesProjectModule: false, + commandPackagesAndroidEmbeddingVersion: 'v1', + )); }, overrides: { Pub: () => pub, ProcessManager: () => FakeProcessManager.any(), @@ -86,11 +86,11 @@ void main() { await commandRunner.run(['get']); - expect(await command.usageValues, { - CustomDimensions.commandPackagesNumberPlugins: '0', - CustomDimensions.commandPackagesProjectModule: 'false', - CustomDimensions.commandPackagesAndroidEmbeddingVersion: 'v1' - }); + expect(await command.usageValues, const CustomDimensions( + commandPackagesNumberPlugins: 0, + commandPackagesProjectModule: false, + commandPackagesAndroidEmbeddingVersion: 'v1', + )); }, overrides: { Pub: () => pub, 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 aea0f7fa944..42de6666591 100644 --- a/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart +++ b/packages/flutter_tools/test/commands.shard/hermetic/run_test.dart @@ -368,10 +368,10 @@ void main() { ]), isNull); expect(usage.commands, contains( - const TestUsageCommand('run', parameters: { + TestUsageCommand('run', parameters: CustomDimensions.fromMap({ 'cd3': 'false', 'cd4': 'ios', 'cd22': 'iOS 13', 'cd23': 'debug', 'cd18': 'false', 'cd15': 'swift', 'cd31': 'false', - } + }) ))); }, overrides: { Artifacts: () => artifacts, diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart index 08ee238d841..4685923f087 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_aar_test.dart @@ -55,8 +55,7 @@ void main() { arguments: ['--no-pub', '--template=module']); final BuildAarCommand command = await runCommandIn(projectPath); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildAarProjectType, 'module')); + expect((await command.usageValues).commandBuildAarProjectType, 'module'); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), @@ -67,8 +66,7 @@ void main() { arguments: ['--no-pub', '--template=plugin', '--project-name=aar_test']); final BuildAarCommand command = await runCommandIn(projectPath); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildAarProjectType, 'plugin')); + expect((await command.usageValues).commandBuildAarProjectType, 'plugin'); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), @@ -80,8 +78,7 @@ void main() { final BuildAarCommand command = await runCommandIn(projectPath, arguments: ['--target-platform=android-arm']); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildAarTargetPlatform, 'android-arm')); + expect((await command.usageValues).commandBuildAarTargetPlatform, 'android-arm'); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart index ffdb389f92a..2c496f17ea7 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_apk_test.dart @@ -43,8 +43,7 @@ void main() { arguments: ['--no-pub', '--template=app']); final BuildApkCommand command = await runBuildApkCommand(projectPath); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildApkTargetPlatform, 'android-arm,android-arm64,android-x64')); + expect((await command.usageValues).commandBuildApkTargetPlatform, 'android-arm,android-arm64,android-x64'); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), @@ -56,12 +55,10 @@ void main() { final BuildApkCommand commandWithFlag = await runBuildApkCommand(projectPath, arguments: ['--split-per-abi']); - expect(await commandWithFlag.usageValues, - containsPair(CustomDimensions.commandBuildApkSplitPerAbi, 'true')); + expect((await commandWithFlag.usageValues).commandBuildApkSplitPerAbi, true); final BuildApkCommand commandWithoutFlag = await runBuildApkCommand(projectPath); - expect(await commandWithoutFlag.usageValues, - containsPair(CustomDimensions.commandBuildApkSplitPerAbi, 'false')); + expect((await commandWithoutFlag.usageValues).commandBuildApkSplitPerAbi, false); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), @@ -72,23 +69,19 @@ void main() { arguments: ['--no-pub', '--template=app']); final BuildApkCommand commandDefault = await runBuildApkCommand(projectPath); - expect(await commandDefault.usageValues, - containsPair(CustomDimensions.commandBuildApkBuildMode, 'release')); + expect((await commandDefault.usageValues).commandBuildApkBuildMode, 'release'); final BuildApkCommand commandInRelease = await runBuildApkCommand(projectPath, arguments: ['--release']); - expect(await commandInRelease.usageValues, - containsPair(CustomDimensions.commandBuildApkBuildMode, 'release')); + expect((await commandInRelease.usageValues).commandBuildApkBuildMode, 'release'); final BuildApkCommand commandInDebug = await runBuildApkCommand(projectPath, arguments: ['--debug']); - expect(await commandInDebug.usageValues, - containsPair(CustomDimensions.commandBuildApkBuildMode, 'debug')); + expect((await commandInDebug.usageValues).commandBuildApkBuildMode, 'debug'); final BuildApkCommand commandInProfile = await runBuildApkCommand(projectPath, arguments: ['--profile']); - expect(await commandInProfile.usageValues, - containsPair(CustomDimensions.commandBuildApkBuildMode, 'profile')); + expect((await commandInProfile.usageValues).commandBuildApkBuildMode, 'profile'); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), @@ -315,7 +308,7 @@ void main() { 'build', 'gradle', label: 'gradle-r8-failure', - parameters: {}, + parameters: CustomDimensions(), ), )); expect(processManager, hasNoRemainingExpectations); @@ -368,7 +361,7 @@ void main() { 'build', 'gradle', label: 'app-not-using-android-x', - parameters: {}, + parameters: CustomDimensions(), ), )); expect(processManager, hasNoRemainingExpectations); @@ -414,7 +407,7 @@ void main() { 'build', 'gradle', label: 'app-using-android-x', - parameters: {}, + parameters: CustomDimensions(), ), )); expect(processManager, hasNoRemainingExpectations); diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart index 72cada208c7..0abdec8839a 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_appbundle_test.dart @@ -41,8 +41,7 @@ void main() { arguments: ['--no-pub', '--template=app']); final BuildAppBundleCommand command = await runBuildAppBundleCommand(projectPath); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildAppBundleTargetPlatform, 'android-arm,android-arm64,android-x64')); + expect((await command.usageValues).commandBuildAppBundleTargetPlatform, 'android-arm,android-arm64,android-x64'); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), @@ -53,23 +52,19 @@ void main() { arguments: ['--no-pub', '--template=app']); final BuildAppBundleCommand commandDefault = await runBuildAppBundleCommand(projectPath); - expect(await commandDefault.usageValues, - containsPair(CustomDimensions.commandBuildAppBundleBuildMode, 'release')); + expect((await commandDefault.usageValues).commandBuildAppBundleBuildMode, 'release'); final BuildAppBundleCommand commandInRelease = await runBuildAppBundleCommand(projectPath, arguments: ['--release']); - expect(await commandInRelease.usageValues, - containsPair(CustomDimensions.commandBuildAppBundleBuildMode, 'release')); + expect((await commandInRelease.usageValues).commandBuildAppBundleBuildMode, 'release'); final BuildAppBundleCommand commandInDebug = await runBuildAppBundleCommand(projectPath, arguments: ['--debug']); - expect(await commandInDebug.usageValues, - containsPair(CustomDimensions.commandBuildAppBundleBuildMode, 'debug')); + expect((await commandInDebug.usageValues).commandBuildAppBundleBuildMode, 'debug'); final BuildAppBundleCommand commandInProfile = await runBuildAppBundleCommand(projectPath, arguments: ['--profile']); - expect(await commandInProfile.usageValues, - containsPair(CustomDimensions.commandBuildAppBundleBuildMode, 'profile')); + expect((await commandInProfile.usageValues).commandBuildAppBundleBuildMode, 'profile'); }, overrides: { AndroidBuilder: () => FakeAndroidBuilder(), @@ -163,7 +158,7 @@ void main() { 'build', 'gradle', label: 'app-not-using-android-x', - parameters: {}, + parameters: CustomDimensions(), ), )); }, @@ -203,7 +198,7 @@ void main() { 'build', 'gradle', label: 'app-using-android-x', - parameters: {}, + parameters: CustomDimensions(), ), )); }, diff --git a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart index 8d731848d12..a6648a52966 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/build_bundle_test.dart @@ -15,7 +15,6 @@ import 'package:flutter_tools/src/commands/build_bundle.dart'; import 'package:flutter_tools/src/features.dart'; import 'package:flutter_tools/src/globals_null_migrated.dart' as globals; import 'package:flutter_tools/src/project.dart'; -import 'package:flutter_tools/src/reporting/reporting.dart'; import 'package:meta/meta.dart'; import 'package:test/fake.dart'; @@ -58,8 +57,7 @@ void main() { final BuildBundleCommand command = await runCommandIn(projectPath); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildBundleIsModule, 'true')); + expect((await command.usageValues).commandBuildBundleIsModule, true); }); testUsingContext('bundle getUsage indicate that project is not a module', () async { @@ -68,8 +66,7 @@ void main() { final BuildBundleCommand command = await runCommandIn(projectPath); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildBundleIsModule, 'false')); + expect((await command.usageValues).commandBuildBundleIsModule, false); }); testUsingContext('bundle getUsage indicate the target platform', () async { @@ -78,8 +75,7 @@ void main() { final BuildBundleCommand command = await runCommandIn(projectPath); - expect(await command.usageValues, - containsPair(CustomDimensions.commandBuildBundleTargetPlatform, 'android-arm')); + expect((await command.usageValues).commandBuildBundleTargetPlatform, 'android-arm'); }); testUsingContext('bundle fails to build for Windows if feature is disabled', () async { 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 f8b90a3631d..99ad383d2f8 100644 --- a/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart +++ b/packages/flutter_tools/test/commands.shard/permeable/packages_test.dart @@ -18,7 +18,6 @@ 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/globals_null_migrated.dart' as globals; -import 'package:flutter_tools/src/reporting/reporting.dart'; import '../../src/common.dart'; import '../../src/context.dart'; @@ -240,8 +239,7 @@ void main() { final PackagesCommand command = await runCommandIn(projectPath, 'get'); final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; - expect(await getCommand.usageValues, - containsPair(CustomDimensions.commandPackagesNumberPlugins, '0')); + expect((await getCommand.usageValues).commandPackagesNumberPlugins, 0); }, overrides: { Pub: () => Pub( fileSystem: globals.fs, @@ -263,8 +261,7 @@ void main() { final PackagesCommand command = await runCommandIn(exampleProjectPath, 'get'); final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; - expect(await getCommand.usageValues, - containsPair(CustomDimensions.commandPackagesNumberPlugins, '1')); + expect((await getCommand.usageValues).commandPackagesNumberPlugins, 1); }, overrides: { Pub: () => Pub( fileSystem: globals.fs, @@ -284,8 +281,7 @@ void main() { final PackagesCommand command = await runCommandIn(projectPath, 'get'); final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; - expect(await getCommand.usageValues, - containsPair(CustomDimensions.commandPackagesProjectModule, 'false')); + expect((await getCommand.usageValues).commandPackagesProjectModule, false); }, overrides: { Pub: () => Pub( fileSystem: globals.fs, @@ -305,8 +301,7 @@ void main() { final PackagesCommand command = await runCommandIn(projectPath, 'get'); final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; - expect(await getCommand.usageValues, - containsPair(CustomDimensions.commandPackagesProjectModule, 'true')); + expect((await getCommand.usageValues).commandPackagesProjectModule, true); }, overrides: { Pub: () => Pub( fileSystem: globals.fs, @@ -335,8 +330,7 @@ void main() { final PackagesCommand command = await runCommandIn(projectPath, 'get'); final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; - expect(await getCommand.usageValues, - containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v1')); + expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v1'); }, overrides: { Pub: () => Pub( fileSystem: globals.fs, @@ -356,8 +350,7 @@ void main() { final PackagesCommand command = await runCommandIn(projectPath, 'get'); final PackagesGetCommand getCommand = command.subcommands['get'] as PackagesGetCommand; - expect(await getCommand.usageValues, - containsPair(CustomDimensions.commandPackagesAndroidEmbeddingVersion, 'v2')); + expect((await getCommand.usageValues).commandPackagesAndroidEmbeddingVersion, 'v2'); }, overrides: { Pub: () => Pub( fileSystem: globals.fs, diff --git a/packages/flutter_tools/test/general.shard/analytics_test.dart b/packages/flutter_tools/test/general.shard/analytics_test.dart index 71506745cef..c53da5d877e 100644 --- a/packages/flutter_tools/test/general.shard/analytics_test.dart +++ b/packages/flutter_tools/test/general.shard/analytics_test.dart @@ -111,7 +111,7 @@ void main() { final Usage usage = Usage(runningOnBot: true); usage.sendCommand('test'); - final String featuresKey = cdKey(CustomDimensions.enabledFlutterFeatures); + final String featuresKey = cdKey(CustomDimensionsEnum.enabledFlutterFeatures); expect(globals.fs.file('test').readAsStringSync(), contains('$featuresKey: enable-web')); }, overrides: { @@ -131,7 +131,7 @@ void main() { final Usage usage = Usage(runningOnBot: true); usage.sendCommand('test'); - final String featuresKey = cdKey(CustomDimensions.enabledFlutterFeatures); + final String featuresKey = cdKey(CustomDimensionsEnum.enabledFlutterFeatures); expect( globals.fs.file('test').readAsStringSync(), diff --git a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart index 03f6525556e..f969326e3d5 100644 --- a/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart +++ b/packages/flutter_tools/test/general.shard/android/android_gradle_builder_test.dart @@ -122,7 +122,7 @@ void main() { 'build', 'gradle', label: 'gradle-random-event-label-failure', - parameters: {}, + parameters: CustomDimensions(), ), )); }); @@ -224,7 +224,7 @@ void main() { 'build', 'gradle', label: 'gradle-random-event-label-failure', - parameters: {}, + parameters: CustomDimensions(), ), )); }); @@ -311,7 +311,7 @@ void main() { 'build', 'gradle', label: 'gradle-random-event-label-failure', - parameters: {}, + parameters: CustomDimensions(), ), )); }); @@ -467,7 +467,7 @@ void main() { 'build', 'gradle', label: 'gradle-random-event-label-success', - parameters: {}, + parameters: CustomDimensions(), ), )); expect(processManager, hasNoRemainingExpectations); @@ -675,7 +675,7 @@ void main() { 'build', 'gradle', label: 'gradle-random-event-label-failure', - parameters: {}, + parameters: CustomDimensions(), ), )); expect(processManager, hasNoRemainingExpectations); diff --git a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart index cebd686523e..39d2d5677b8 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_errors_test.dart @@ -355,13 +355,13 @@ Command: /home/android/gradlew assembleRelease .handler(line: '', project: FlutterProject.fromDirectoryTest(globals.fs.currentDirectory)); expect(testUsage.events, contains( - const TestUsageEvent( + TestUsageEvent( 'build', 'gradle', label: 'gradle-android-x-failure', - parameters: { + parameters: CustomDimensions.fromMap({ 'cd43': 'app-not-using-plugins', - }, + }), ), )); @@ -390,13 +390,13 @@ Command: /home/android/gradlew assembleRelease ); expect(testUsage.events, contains( - const TestUsageEvent( + TestUsageEvent( 'build', 'gradle', label: 'gradle-android-x-failure', - parameters: { + parameters: CustomDimensions.fromMap({ 'cd43': 'app-not-using-androidx', - }, + }), ), )); @@ -418,13 +418,13 @@ Command: /home/android/gradlew assembleRelease ); expect(testUsage.events, contains( - const TestUsageEvent( + TestUsageEvent( 'build', 'gradle', label: 'gradle-android-x-failure', - parameters: { + parameters: CustomDimensions.fromMap({ 'cd43': 'using-jetifier', - }, + }), ), )); @@ -453,13 +453,13 @@ Command: /home/android/gradlew assembleRelease ); expect(testUsage.events, contains( - const TestUsageEvent( + TestUsageEvent( 'build', 'gradle', label: 'gradle-android-x-failure', - parameters: { + parameters: CustomDimensions.fromMap({ 'cd43': 'not-using-jetifier', - }, + }), ), )); expect(status, equals(GradleBuildStatus.retryWithAarPlugins)); diff --git a/packages/flutter_tools/test/general.shard/android/gradle_find_bundle_test.dart b/packages/flutter_tools/test/general.shard/android/gradle_find_bundle_test.dart index 49f8df10842..b69c729512d 100644 --- a/packages/flutter_tools/test/general.shard/android/gradle_find_bundle_test.dart +++ b/packages/flutter_tools/test/general.shard/android/gradle_find_bundle_test.dart @@ -326,13 +326,13 @@ void main() { ) ); expect(testUsage.events, contains( - const TestUsageEvent( + TestUsageEvent( 'build', 'gradle', label: 'gradle-expected-file-not-found', - parameters: { + parameters: CustomDimensions.fromMap( { 'cd37': 'androidGradlePluginVersion: 6.7, fileExtension: .aab', - }, + }), ), )); }); diff --git a/packages/flutter_tools/test/general.shard/ios/mac_test.dart b/packages/flutter_tools/test/general.shard/ios/mac_test.dart index 0cd3e90f581..7c6fedb8ea5 100644 --- a/packages/flutter_tools/test/general.shard/ios/mac_test.dart +++ b/packages/flutter_tools/test/general.shard/ios/mac_test.dart @@ -160,10 +160,10 @@ void main() { 'build', 'ios', label: 'xcode-bitcode-failure', - parameters: { - cdKey(CustomDimensions.buildEventCommand): buildCommands.toString(), - cdKey(CustomDimensions.buildEventSettings): buildSettings.toString(), - }, + parameters: CustomDimensions( + buildEventCommand: buildCommands.toString(), + buildEventSettings: buildSettings.toString(), + ), ), )); }); diff --git a/packages/flutter_tools/test/general.shard/reporting/events_test.dart b/packages/flutter_tools/test/general.shard/reporting/events_test.dart index 7e179337960..6ad207915e2 100644 --- a/packages/flutter_tools/test/general.shard/reporting/events_test.dart +++ b/packages/flutter_tools/test/general.shard/reporting/events_test.dart @@ -74,9 +74,9 @@ void main() { expect(usage.events, unorderedEquals([ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'), - const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: { + TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: CustomDimensions.fromMap({ 'cd49': '1', 'cd50': '3', - }), + })), const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'language-version', label: '2.12'), ])); }); @@ -98,9 +98,9 @@ void main() { expect(usage.events, unorderedEquals([ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'), - const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: { + TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: CustomDimensions.fromMap({ 'cd49': '1', 'cd50': '3', - }), + })), ])); }); @@ -119,9 +119,9 @@ void main() { expect(usage.events, unorderedEquals([ const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'runtime-mode', label: 'NullSafetyMode.sound'), - const TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: { + TestUsageEvent(NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', parameters: CustomDimensions.fromMap({ 'cd49': '0', 'cd50': '1', - }), + })), ])); }); } diff --git a/packages/flutter_tools/test/general.shard/resident_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_runner_test.dart index 781e5166017..8a52736fa9d 100644 --- a/packages/flutter_tools/test/general.shard/resident_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_runner_test.dart @@ -550,13 +550,12 @@ void main() { expect(result.fatal, true); expect(result.code, 1); expect((globals.flutterUsage as TestUsage).events, contains( - TestUsageEvent('hot', 'exception', parameters: { - cdKey(CustomDimensions.hotEventTargetPlatform): - getNameForTargetPlatform(TargetPlatform.android_arm), - cdKey(CustomDimensions.hotEventSdkName): 'Android', - cdKey(CustomDimensions.hotEventEmulator): 'false', - cdKey(CustomDimensions.hotEventFullRestart): 'false', - }), + TestUsageEvent('hot', 'exception', parameters: CustomDimensions( + hotEventTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm), + hotEventSdkName: 'Android', + hotEventEmulator: false, + hotEventFullRestart: false, + )), )); expect(fakeVmServiceHost.hasRemainingExpectations, false); }, overrides: { @@ -623,13 +622,12 @@ void main() { expect(result.message, contains('Unable to hot reload application due to an unrecoverable error')); expect((globals.flutterUsage as TestUsage).events, contains( - TestUsageEvent('hot', 'reload-barred', parameters: { - cdKey(CustomDimensions.hotEventTargetPlatform): - getNameForTargetPlatform(TargetPlatform.android_arm), - cdKey(CustomDimensions.hotEventSdkName): 'Android', - cdKey(CustomDimensions.hotEventEmulator): 'false', - cdKey(CustomDimensions.hotEventFullRestart): 'false', - }), + TestUsageEvent('hot', 'reload-barred', parameters: CustomDimensions( + hotEventTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm), + hotEventSdkName: 'Android', + hotEventEmulator: false, + hotEventFullRestart: false, + )), )); expect(fakeVmServiceHost.hasRemainingExpectations, false); }, overrides: { @@ -686,13 +684,12 @@ void main() { expect(result.code, 1); expect((globals.flutterUsage as TestUsage).events, contains( - TestUsageEvent('hot', 'exception', parameters: { - cdKey(CustomDimensions.hotEventTargetPlatform): - getNameForTargetPlatform(TargetPlatform.android_arm), - cdKey(CustomDimensions.hotEventSdkName): 'Android', - cdKey(CustomDimensions.hotEventEmulator): 'false', - cdKey(CustomDimensions.hotEventFullRestart): 'false', - }), + TestUsageEvent('hot', 'exception', parameters: CustomDimensions( + hotEventTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm), + hotEventSdkName: 'Android', + hotEventEmulator: false, + hotEventFullRestart: false, + )), )); expect(fakeVmServiceHost.hasRemainingExpectations, false); }, overrides: { @@ -981,10 +978,7 @@ void main() { final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first; expect(event.category, 'hot'); expect(event.parameter, 'reload'); - expect(event.parameters, containsPair( - cdKey(CustomDimensions.hotEventTargetPlatform), - getNameForTargetPlatform(TargetPlatform.android_arm), - )); + expect(event.parameters.hotEventTargetPlatform, getNameForTargetPlatform(TargetPlatform.android_arm)); }, overrides: { Usage: () => TestUsage(), }), overrides: { @@ -1089,9 +1083,7 @@ void main() { final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first; expect(event.category, 'hot'); expect(event.parameter, 'reload'); - expect(event.parameters, containsPair( - cdKey(CustomDimensions.fastReassemble), 'true', - )); + expect(event.parameters.fastReassemble, true); }, overrides: { FileSystem: () => MemoryFileSystem.test(), Platform: () => FakePlatform(operatingSystem: 'linux'), @@ -1157,9 +1149,7 @@ void main() { final TestUsageEvent event = (globals.flutterUsage as TestUsage).events.first; expect(event.category, 'hot'); expect(event.parameter, 'restart'); - expect(event.parameters, containsPair( - cdKey(CustomDimensions.hotEventTargetPlatform), getNameForTargetPlatform(TargetPlatform.android_arm), - )); + expect(event.parameters.hotEventTargetPlatform, getNameForTargetPlatform(TargetPlatform.android_arm)); expect(fakeVmServiceHost.hasRemainingExpectations, false); }, overrides: { Usage: () => TestUsage(), @@ -1395,13 +1385,12 @@ void main() { expect(result.code, 1); expect((globals.flutterUsage as TestUsage).events, contains( - TestUsageEvent('hot', 'exception', parameters: { - cdKey(CustomDimensions.hotEventTargetPlatform): - getNameForTargetPlatform(TargetPlatform.android_arm), - cdKey(CustomDimensions.hotEventSdkName): 'Android', - cdKey(CustomDimensions.hotEventEmulator): 'false', - cdKey(CustomDimensions.hotEventFullRestart): 'true', - }), + TestUsageEvent('hot', 'exception', parameters: CustomDimensions( + hotEventTargetPlatform: getNameForTargetPlatform(TargetPlatform.android_arm), + hotEventSdkName: 'Android', + hotEventEmulator: false, + hotEventFullRestart: true, + )), )); expect(fakeVmServiceHost.hasRemainingExpectations, false); }, overrides: { diff --git a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart index 4b28bc57d1d..03f9f664ec2 100644 --- a/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart +++ b/packages/flutter_tools/test/general.shard/resident_web_runner_test.dart @@ -580,8 +580,8 @@ void main() { verify(mockResidentCompiler.accept()).called(2); // ensure that analytics are sent. - expect(testUsage.events, const [ - TestUsageEvent('hot', 'restart', parameters: {'cd27': 'web-javascript', 'cd28': '', 'cd29': 'false', 'cd30': 'true', 'cd13': '0'}), + expect(testUsage.events, [ + TestUsageEvent('hot', 'restart', parameters: CustomDimensions.fromMap({'cd27': 'web-javascript', 'cd28': '', 'cd29': 'false', 'cd30': 'true', 'cd13': '0'})), ]); expect(testUsage.timings, const [ TestTimingEvent('hot', 'web-incremental-restart', Duration.zero), @@ -658,8 +658,8 @@ void main() { verify(mockResidentCompiler.accept()).called(2); // ensure that analytics are sent. - expect(testUsage.events, const [ - TestUsageEvent('hot', 'restart', parameters: {'cd27': 'web-javascript', 'cd28': '', 'cd29': 'false', 'cd30': 'true', 'cd13': '0'}), + expect(testUsage.events, [ + TestUsageEvent('hot', 'restart', parameters: CustomDimensions.fromMap({'cd27': 'web-javascript', 'cd28': '', 'cd29': 'false', 'cd30': 'true', 'cd13': '0'})), ]); expect(testUsage.timings, const [ TestTimingEvent('hot', 'web-incremental-restart', Duration.zero), diff --git a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart index 13682419dc3..08fbe8ce1a0 100644 --- a/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/flutter_command_test.dart @@ -483,12 +483,12 @@ void main() { 'runtime-mode', label: 'NullSafetyMode.sound', ), - const TestUsageEvent( + TestUsageEvent( NullSafetyAnalysisEvent.kNullSafetyCategory, 'stats', - parameters: { + parameters: CustomDimensions.fromMap({ 'cd49': '1', 'cd50': '1', - }, + }), ), const TestUsageEvent( NullSafetyAnalysisEvent.kNullSafetyCategory, diff --git a/packages/flutter_tools/test/general.shard/runner/runner_test.dart b/packages/flutter_tools/test/general.shard/runner/runner_test.dart index 5b487ae52a6..2e07984b83c 100644 --- a/packages/flutter_tools/test/general.shard/runner/runner_test.dart +++ b/packages/flutter_tools/test/general.shard/runner/runner_test.dart @@ -282,7 +282,7 @@ class CrashingUsage implements Usage { String get clientId => _impl.clientId; @override - void sendCommand(String command, {Map parameters}) => + void sendCommand(String command, {CustomDimensions parameters}) => _impl.sendCommand(command, parameters: parameters); @override @@ -291,7 +291,7 @@ class CrashingUsage implements Usage { String parameter, { String label, int value, - Map parameters, + CustomDimensions parameters, }) => _impl.sendEvent( category, parameter,