Include screen information with `unified_analytics` events and bump `unified_analytics` to 7.0.0 (#8514)

diff --git a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart
index 6e31105..1cd77d5 100644
--- a/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart
+++ b/packages/devtools_app/lib/src/shared/analytics/_analytics_web.dart
@@ -56,6 +56,7 @@
   // than a fixed list of fields. See
   // https://github.com/flutter/devtools/pull/3281#discussion_r692376353.
   external factory GtagEventDevTools({
+    String? screen,
     String? event_category,
     String? event_label, // Event e.g., gaScreenViewEvent, gaSelectEvent, etc.
     String? send_to, // UA ID of target GA property to receive event data.
@@ -110,11 +111,15 @@
     int? root_set_count, // metric10
     int? row_count, // metric11
     int? inspector_tree_controller_id, // metric12
+    // Deep Link screen metrics. See [DeepLinkScreenMetrics].
     String? android_app_id, //metric13
     String? ios_bundle_id, //metric14
+    // Inspector screen metrics. See [InspectorScreenMetrics].
+    bool? is_v2_inspector, // metric15
   });
 
   factory GtagEventDevTools._create({
+    required String screen,
     required String event_category,
     required String event_label,
     String? send_to,
@@ -123,6 +128,7 @@
     ScreenAnalyticsMetrics? screenMetrics,
   }) {
     return GtagEventDevTools(
+      screen: screen,
       event_category: event_category,
       event_label: event_label,
       send_to: send_to,
@@ -189,9 +195,14 @@
       ios_bundle_id: screenMetrics is DeepLinkScreenMetrics
           ? screenMetrics.iosBundleId
           : null,
+      // [InspectorScreenMetrics]
+      is_v2_inspector:
+          screenMetrics is InspectorScreenMetrics ? screenMetrics.isV2 : null,
     );
   }
 
+  external String? get screen;
+
   // Custom dimensions:
   external String? get user_app;
   external String? get user_build;
@@ -222,10 +233,12 @@
   external int? get inspector_tree_controller_id;
   external String? get android_app_id;
   external String? get ios_bundle_id;
+  external bool? get is_v2_inspector;
 }
 
 extension type GtagExceptionDevTools._(JSObject _) implements GtagException {
   external factory GtagExceptionDevTools({
+    String? screen,
     String? description,
     bool fatal,
 
@@ -274,8 +287,11 @@
     int? root_set_count, // metric10
     int? row_count, // metric11
     int? inspector_tree_controller_id, // metric12
+    // Deep Link screen metrics. See [DeepLinkScreenMetrics].
     String? android_app_id, //metric13
     String? ios_bundle_id, //metric14
+    // Inspector screen metrics. See [InspectorScreenMetrics].
+    bool? is_v2_inspector, // metric15
   });
 
   factory GtagExceptionDevTools._create(
@@ -347,6 +363,9 @@
       ios_bundle_id: screenMetrics is DeepLinkScreenMetrics
           ? screenMetrics.iosBundleId
           : null,
+      // [InspectorScreenMetrics]
+      is_v2_inspector:
+          screenMetrics is InspectorScreenMetrics ? screenMetrics.isV2 : null,
     );
   }
 
@@ -380,6 +399,7 @@
   external int? get inspector_tree_controller_id;
   external String? get android_app_id;
   external String? get ios_bundle_id;
+  external bool? get is_v2_inspector;
 }
 
 /// Whether google analytics are enabled.
@@ -419,18 +439,16 @@
   return shouldShow;
 }
 
-void screen(
-  String screenName, [
-  int value = 0,
-]) {
+void screen(String screenName, [int value = 0]) {
   _log.fine('Event: Screen(screenName:$screenName, value:$value)');
   final gtagEvent = GtagEventDevTools._create(
+    screen: screenName,
     event_category: gac.screenViewEvent,
     event_label: gac.init,
     value: value,
     send_to: gaDevToolsPropertyId(),
   );
-  _sendEventForScreen(screenName, gtagEvent);
+  _sendEvent(gtagEvent);
 }
 
 String _operationKey(String screenName, String timedOperation) {
@@ -570,13 +588,14 @@
     'durationMicros:$durationMicros)',
   );
   final gtagEvent = GtagEventDevTools._create(
+    screen: screenName,
     event_category: gac.timingEvent,
     event_label: timedOperation,
     value: durationMicros,
     send_to: gaDevToolsPropertyId(),
     screenMetrics: screenMetrics,
   );
-  _sendEventForScreen(screenName, gtagEvent);
+  _sendEvent(gtagEvent);
 }
 
 /// Sends an analytics event to signal that something in DevTools was selected.
@@ -595,6 +614,7 @@
     'nonInteraction:$nonInteraction)',
   );
   final gtagEvent = GtagEventDevTools._create(
+    screen: screenName,
     event_category: gac.selectEvent,
     event_label: selectedItem,
     value: value,
@@ -603,7 +623,7 @@
     screenMetrics:
         screenMetricsProvider != null ? screenMetricsProvider() : null,
   );
-  _sendEventForScreen(screenName, gtagEvent);
+  _sendEvent(gtagEvent);
 }
 
 /// Sends an analytics event to signal that something in DevTools was viewed.
@@ -620,6 +640,7 @@
     'item:$item)',
   );
   final gtagEvent = GtagEventDevTools._create(
+    screen: screenName,
     event_category: gac.impressionEvent,
     event_label: item,
     non_interaction: true,
@@ -627,7 +648,7 @@
     screenMetrics:
         screenMetricsProvider != null ? screenMetricsProvider() : null,
   );
-  _sendEventForScreen(screenName, gtagEvent);
+  _sendEvent(gtagEvent);
 }
 
 String? _lastGaError;
@@ -879,9 +900,9 @@
   jsHookupListenerForGA();
 }
 
-void _sendEventForScreen(String screenName, GtagEventDevTools gtagEvent) {
+void _sendEvent(GtagEventDevTools gtagEvent) {
   GTag.event(
-    screenName,
+    gtagEvent.screen!,
     gaEventProvider: () => gtagEvent,
   );
   final uaEvent = _uaEventFromGtagEvent(gtagEvent);
@@ -892,6 +913,7 @@
   // Any dimensions or metrics that have a null value will be removed from
   // the event data in the [ua.Event.devtoolsEvent] constructor.
   return ua.Event.devtoolsEvent(
+    screen: gtagEvent.screen!,
     eventCategory: gtagEvent.event_category!,
     label: gtagEvent.event_label!,
     value: gtagEvent.value,
@@ -912,21 +934,24 @@
     // all of the below metrics will be non-null at the same time, it is okay to
     // include all the metrics here. The [ua.Event.devtoolsEvent] constructor
     // will remove any entries with a null value from the sent event parameters.
-    uiDurationMicros: gtagEvent.ui_duration_micros,
-    rasterDurationMicros: gtagEvent.raster_duration_micros,
-    shaderCompilationDurationMicros:
-        gtagEvent.shader_compilation_duration_micros,
-    traceEventCount: gtagEvent.trace_event_count,
-    cpuSampleCount: gtagEvent.cpu_sample_count,
-    cpuStackDepth: gtagEvent.cpu_stack_depth,
-    heapDiffObjectsBefore: gtagEvent.heap_diff_objects_before,
-    heapDiffObjectsAfter: gtagEvent.heap_diff_objects_after,
-    heapObjectsTotal: gtagEvent.heap_objects_total,
-    rootSetCount: gtagEvent.root_set_count,
-    rowCount: gtagEvent.row_count,
-    inspectorTreeControllerId: gtagEvent.inspector_tree_controller_id,
-    androidAppId: gtagEvent.android_app_id,
-    iosBundleId: gtagEvent.ios_bundle_id,
+    additionalMetrics: _DevToolsEventMetrics(
+      uiDurationMicros: gtagEvent.ui_duration_micros,
+      rasterDurationMicros: gtagEvent.raster_duration_micros,
+      shaderCompilationDurationMicros:
+          gtagEvent.shader_compilation_duration_micros,
+      traceEventCount: gtagEvent.trace_event_count,
+      cpuSampleCount: gtagEvent.cpu_sample_count,
+      cpuStackDepth: gtagEvent.cpu_stack_depth,
+      heapDiffObjectsBefore: gtagEvent.heap_diff_objects_before,
+      heapDiffObjectsAfter: gtagEvent.heap_diff_objects_after,
+      heapObjectsTotal: gtagEvent.heap_objects_total,
+      rootSetCount: gtagEvent.root_set_count,
+      rowCount: gtagEvent.row_count,
+      inspectorTreeControllerId: gtagEvent.inspector_tree_controller_id,
+      isV2Inspector: gtagEvent.is_v2_inspector,
+      androidAppId: gtagEvent.android_app_id,
+      iosBundleId: gtagEvent.ios_bundle_id,
+    ),
   );
 }
 
@@ -969,3 +994,68 @@
     },
   );
 }
+
+final class _DevToolsEventMetrics extends ua.CustomMetrics {
+  _DevToolsEventMetrics({
+    required this.rasterDurationMicros,
+    required this.shaderCompilationDurationMicros,
+    required this.traceEventCount,
+    required this.cpuSampleCount,
+    required this.cpuStackDepth,
+    required this.heapDiffObjectsBefore,
+    required this.heapDiffObjectsAfter,
+    required this.heapObjectsTotal,
+    required this.rootSetCount,
+    required this.rowCount,
+    required this.inspectorTreeControllerId,
+    required this.isV2Inspector,
+    required this.androidAppId,
+    required this.iosBundleId,
+    required this.uiDurationMicros,
+  });
+
+  // [PerformanceScreenMetrics]
+  final int? uiDurationMicros;
+  final int? rasterDurationMicros;
+  final int? shaderCompilationDurationMicros;
+  final int? traceEventCount;
+
+  // [ProfilerScreenMetrics]
+  final int? cpuSampleCount;
+  final int? cpuStackDepth;
+
+  // [MemoryScreenMetrics]
+  final int? heapDiffObjectsBefore;
+  final int? heapDiffObjectsAfter;
+  final int? heapObjectsTotal;
+
+  // [InspectorScreenMetrics]
+  final int? rootSetCount;
+  final int? rowCount;
+  final int? inspectorTreeControllerId;
+  final bool? isV2Inspector;
+
+  // [DeepLinkScreenMetrics]
+  final String? androidAppId;
+  final String? iosBundleId;
+
+  @override
+  Map<String, Object> toMap() => (<String, Object?>{
+        'uiDurationMicros': uiDurationMicros,
+        'rasterDurationMicros': rasterDurationMicros,
+        'shaderCompilationDurationMicros': shaderCompilationDurationMicros,
+        'traceEventCount': traceEventCount,
+        'cpuSampleCount': cpuSampleCount,
+        'cpuStackDepth': cpuStackDepth,
+        'heapDiffObjectsBefore': heapDiffObjectsBefore,
+        'heapDiffObjectsAfter': heapDiffObjectsAfter,
+        'heapObjectsTotal': heapObjectsTotal,
+        'rootSetCount': rootSetCount,
+        'rowCount': rowCount,
+        'inspectorTreeControllerId': inspectorTreeControllerId,
+        'isV2Inspector': isV2Inspector,
+        'androidAppId': androidAppId,
+        'iosBundleId': iosBundleId,
+      }..removeWhere((key, value) => value == null))
+          .cast<String, Object>();
+}
diff --git a/packages/devtools_app/pubspec.yaml b/packages/devtools_app/pubspec.yaml
index ca3bf5f..b28e7db 100644
--- a/packages/devtools_app/pubspec.yaml
+++ b/packages/devtools_app/pubspec.yaml
@@ -24,7 +24,7 @@
   devtools_app_shared: ^0.2.2
   devtools_extensions: ^0.3.0-wip
   devtools_shared: ^10.0.1
-  dtd: ^2.3.0
+  dtd: ^2.4.0
   file: ^7.0.0
   file_selector: ^1.0.0
   fixnum: ^1.1.0
@@ -53,7 +53,7 @@
   stack_trace: ^1.12.0
   stream_channel: ^2.1.1
   string_scanner: ^1.1.0
-  unified_analytics: ^6.1.5
+  unified_analytics: ^7.0.0
   vm_service: ^14.2.5
   vm_service_protos: ^1.0.0
   vm_snapshot_analysis: ^0.7.6
diff --git a/packages/devtools_app/web/devtools_analytics.js b/packages/devtools_app/web/devtools_analytics.js
index f44f93a..cb6ddb0 100644
--- a/packages/devtools_app/web/devtools_analytics.js
+++ b/packages/devtools_app/web/devtools_analytics.js
@@ -44,6 +44,9 @@
       'metric10': 'root_set_count',
       'metric11': 'row_count',
       'metric12': 'inspector_tree_controller_id',
+      'metric13': 'android_app_id',
+      'metric14': 'ios_bundle_id',
+      'metric15': 'is_v2_inspector',
     },
     cookie_flags: 'SameSite=None;Secure',
   });