Trigger re-layout when resizing CPU flame chart (#9915)
diff --git a/packages/devtools_app/lib/src/shared/charts/flame_chart.dart b/packages/devtools_app/lib/src/shared/charts/flame_chart.dart
index bff073a..c33243e 100644
--- a/packages/devtools_app/lib/src/shared/charts/flame_chart.dart
+++ b/packages/devtools_app/lib/src/shared/charts/flame_chart.dart
@@ -269,6 +269,9 @@
       verticalControllerGroup.resetScroll();
       zoomController.reset();
       verticalExtentDelegate.recompute();
+    } else if (widget.containerWidth != oldWidget.containerWidth) {
+      initFlameChartElements();
+      verticalExtentDelegate.recompute();
     }
     FocusScope.of(context).requestFocus(focusNode);
     super.didUpdateWidget(oldWidget);
diff --git a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
index 8c84a48..a147f4c 100644
--- a/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
+++ b/packages/devtools_app/release_notes/NEXT_RELEASE_NOTES.md
@@ -27,7 +27,9 @@
 
 ## CPU profiler updates
 
-TODO: Remove this section if there are not any updates.
+* Fixed a bug where resizing the CPU flame chart changes the timing values
+  across the top of the chart.
+  [#9915](https://github.com/flutter/devtools/pull/9915)
 
 ## Memory updates
 
@@ -40,7 +42,7 @@
 
 ## Network profiler updates
 
-- Fixed exported response status in HAR files so that they parse as integers
+* Fixed exported response status in HAR files so that they parse as integers
   instead of strings. [#9900](https://github.com/flutter/devtools/pull/9900)
 
 ## Logging updates
diff --git a/packages/devtools_app/test/shared/charts/flame_chart_test.dart b/packages/devtools_app/test/shared/charts/flame_chart_test.dart
index e250a77..228484c 100644
--- a/packages/devtools_app/test/shared/charts/flame_chart_test.dart
+++ b/packages/devtools_app/test/shared/charts/flame_chart_test.dart
@@ -3,6 +3,7 @@
 // found in the LICENSE file or at https://developers.google.com/open-source/licenses/bsd.
 
 import 'package:devtools_app/devtools_app.dart';
+import 'package:devtools_app/src/screens/profiler/cpu_profile_transformer.dart';
 import 'package:devtools_app/src/screens/profiler/cpu_profiler_controller.dart';
 import 'package:devtools_app/src/screens/profiler/panes/cpu_flame_chart.dart';
 import 'package:devtools_app/src/shared/charts/flame_chart.dart';
@@ -624,6 +625,56 @@
         );
       });
     });
+
+    testWidgets('re-lays out elements when container width changes', (
+      WidgetTester tester,
+    ) async {
+      final transformer = CpuProfileTransformer();
+      final cpuProfileData = CpuProfileData.fromJson(cpuProfileResponseJson);
+      await tester.runAsync(() async {
+        await transformer.processData(cpuProfileData, processId: 'test');
+      });
+
+      flameChart = CpuProfileFlameChart(
+        data: cpuProfileData,
+        width: 1000.0,
+        height: 1000.0,
+        selectionNotifier: ValueNotifier<CpuStackFrame?>(null),
+        searchMatchesNotifier: controller.searchMatches,
+        activeSearchMatchNotifier: controller.activeSearchMatch,
+        onDataSelected: (_) {},
+      );
+
+      await pumpFlameChart(tester);
+      expect(find.byWidget(flameChart), findsOneWidget);
+      final FlameChartState state = tester.state(find.byWidget(flameChart));
+
+      // Find first row that has nodes.
+      final rowWithNodes = state.rows.firstWhere((row) => row.nodes.isNotEmpty);
+      final node = rowWithNodes.nodes[0];
+      final initialNodeWidth = node.rect.width;
+      expect(initialNodeWidth, greaterThan(0.0));
+
+      // Update the flame chart with a new width.
+      flameChart = CpuProfileFlameChart(
+        data: cpuProfileData,
+        width: 2000.0,
+        height: 1000.0,
+        selectionNotifier: ValueNotifier<CpuStackFrame?>(null),
+        searchMatchesNotifier: controller.searchMatches,
+        activeSearchMatchNotifier: controller.activeSearchMatch,
+        onDataSelected: (_) {},
+      );
+      await pumpFlameChart(tester);
+      await tester.pumpAndSettle();
+
+      final updatedRowWithNodes = state.rows.firstWhere(
+        (row) => row.nodes.isNotEmpty,
+      );
+      final updatedNode = updatedRowWithNodes.nodes[0];
+      expect(updatedNode.rect.width, isNot(equals(initialNodeWidth)));
+      expect(updatedNode.rect.width, greaterThan(initialNodeWidth));
+    });
   });
 
   group('ScrollingFlameChartRow', () {