[flutter_releases] Flutter stable 2.5.1 Framework Cherrypicks (#90281)

* Fix KeyboardManager's synthesization  (#88967)

This PR fixes KeyboardManager's key event synthesization logic, which were dispatching events with incorrect keys, making subsequent key events crash the app.

* Revert clamping scroll simulation changes (#89885)

* Revert "Removed default page transitions for desktop and web platforms. (#82596)" (#89997)

This reverts commit 43e31977

* 'Update Engine revision to b3af521a050e6ef076778bcaf16e27b2521df8f8 for stable release 2.5.1'

* Update dds 2.0.3 -> 2.0.4

* renew cirrus key (#89988)

Co-authored-by: Tong Mu <dkwingsmt@users.noreply.github.com>
Co-authored-by: Kate Lovett <katelovett@google.com>
Co-authored-by: Darren Austin <darrenaustin@google.com>
Co-authored-by: Christopher Fujino <christopherfujino@gmail.com>
Co-authored-by: keyonghan <54558023+keyonghan@users.noreply.github.com>
diff --git a/.cirrus.yml b/.cirrus.yml
index 2433c6d..977f06c 100644
--- a/.cirrus.yml
+++ b/.cirrus.yml
@@ -12,7 +12,7 @@
   # dependency on precisely how Cirrus is detected by our tools.
   BOT: "true"
 
-gcp_credentials: ENCRYPTED[!0e63b52bd7e4fda1cd7b7bf2b4fe515a27fadbeaced01f5ad8b699b81d3611ed64c5d3271bcd8426dd914ef41cba48a0!]
+gcp_credentials: ENCRYPTED[!48cff44dd32e9cc412d4d381c7fe68d373ca04cf2639f8192d21cb1a9ab5e21129651423a1cf88f3fd7fe2125c1cabd9!]
 
 # LINUX SHARDS
 task:
diff --git a/bin/internal/engine.version b/bin/internal/engine.version
index bd5eece..819e163 100644
--- a/bin/internal/engine.version
+++ b/bin/internal/engine.version
@@ -1 +1 @@
-f0826da7ef2d301eb8f4ead91aaf026aa2b52881
+b3af521a050e6ef076778bcaf16e27b2521df8f8
diff --git a/dev/tools/generate_android_spline_data.dart b/dev/tools/generate_android_spline_data.dart
deleted file mode 100644
index 12e79d5..0000000
--- a/dev/tools/generate_android_spline_data.dart
+++ /dev/null
@@ -1,61 +0,0 @@
-// 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.
-
-const int _nbSamples = 100;
-final List<double> _splinePosition = List<double>.filled(_nbSamples + 1, 0.0);
-final List<double> _splineTime = List<double>.filled(_nbSamples + 1, 0.0);
-const double _startTension = 0.5;
-const double _endTension = 1.0;
-const double _inflexion = 0.35;
-
-// Generate the spline data used in ClampingScrollSimulation.
-//
-// This logic is a translation of the 2-dimensional logic found in
-// https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/widget/Scroller.java.
-//
-// The output of this program should be copied over to [_splinePosition] in
-// flutter/packages/flutter/lib/src/widgets/scroll_simulation.dart.
-void main() {
-  const double p1 = _startTension * _inflexion;
-  const double p2 = 1.0 - _endTension * (1.0 - _inflexion);
-  double xMin = 0.0;
-  double yMin = 0.0;
-  for (int i = 0; i < _nbSamples; i++) {
-    final double alpha = i / _nbSamples;
-    double xMax = 1.0;
-    double x, tx, coef;
-    while (true) {
-      x = xMin + (xMax - xMin) / 2.0;
-      coef = 3.0 * x * (1.0 - x);
-      tx = coef * ((1.0 - x) * p1 + x * p2) + x * x * x;
-      if ((tx - alpha).abs() < 1e-5) {
-        break;
-      }
-      if (tx > alpha) {
-        xMax = x;
-      } else {
-        xMin = x;
-      }
-    }
-    _splinePosition[i] = coef * ((1.0 - x) * _startTension + x) + x * x * x;
-    double yMax = 1.0;
-    double y, dy;
-    while (true) {
-      y = yMin + (yMax - yMin) / 2.0;
-      coef = 3.0 * y * (1.0 - y);
-      dy = coef * ((1.0 - y) * _startTension + y) + y * y * y;
-      if ((dy - alpha).abs() < 1e-5) {
-        break;
-      }
-      if (dy > alpha) {
-        yMax = y;
-      } else {
-        yMin = y;
-      }
-    }
-    _splineTime[i] = coef * ((1.0 - y) * p1 + y * p2) + y * y * y;
-  }
-  _splinePosition[_nbSamples] = _splineTime[_nbSamples] = 1.0;
-  print(_splinePosition);
-}
diff --git a/packages/flutter/lib/src/material/page_transitions_theme.dart b/packages/flutter/lib/src/material/page_transitions_theme.dart
index 695fed9..9cc555c 100644
--- a/packages/flutter/lib/src/material/page_transitions_theme.dart
+++ b/packages/flutter/lib/src/material/page_transitions_theme.dart
@@ -546,9 +546,8 @@
 /// current [PageTransitionsTheme] with `Theme.of(context).pageTransitionsTheme`
 /// and delegates to [buildTransitions].
 ///
-/// If a builder for the current [ThemeData.platform] is not found, then
-/// no animated transition will occur. The new page will just be displayed
-/// immediately.
+/// If a builder with a matching platform is not found, then the
+/// [FadeUpwardsPageTransitionsBuilder] is used.
 ///
 /// See also:
 ///
@@ -564,23 +563,16 @@
   /// Constructs an object that selects a transition based on the platform.
   ///
   /// By default the list of builders is: [FadeUpwardsPageTransitionsBuilder]
-  /// for [TargetPlatform.android] and [TargetPlatform.fuchsia],
-  /// [CupertinoPageTransitionsBuilder] for [TargetPlatform.iOS], and no
-  /// animated transition for other platforms or if the app is running on the
-  /// web.
-  const PageTransitionsTheme({
-    Map<TargetPlatform, PageTransitionsBuilder> builders = kIsWeb ? _defaultWebBuilders : _defaultBuilders,
-  }) : _builders = builders;
+  /// for [TargetPlatform.android], and [CupertinoPageTransitionsBuilder] for
+  /// [TargetPlatform.iOS] and [TargetPlatform.macOS].
+  const PageTransitionsTheme({ Map<TargetPlatform, PageTransitionsBuilder> builders = _defaultBuilders }) : _builders = builders;
 
   static const Map<TargetPlatform, PageTransitionsBuilder> _defaultBuilders = <TargetPlatform, PageTransitionsBuilder>{
-    // Only have default transitions for mobile platforms
     TargetPlatform.android: FadeUpwardsPageTransitionsBuilder(),
     TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
-    TargetPlatform.fuchsia: FadeUpwardsPageTransitionsBuilder(),
-  };
-
-  static const Map<TargetPlatform, PageTransitionsBuilder> _defaultWebBuilders = <TargetPlatform, PageTransitionsBuilder>{
-    // By default no page transitions for web apps.
+    TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(),
+    TargetPlatform.macOS: CupertinoPageTransitionsBuilder(),
+    TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(),
   };
 
   /// The [PageTransitionsBuilder]s supported by this theme.
@@ -603,8 +595,9 @@
     if (CupertinoRouteTransitionMixin.isPopGestureInProgress(route))
       platform = TargetPlatform.iOS;
 
-    final PageTransitionsBuilder? matchingBuilder = builders[platform];
-    return matchingBuilder?.buildTransitions<T>(route, context, animation, secondaryAnimation, child) ?? child;
+    final PageTransitionsBuilder matchingBuilder =
+      builders[platform] ?? const FadeUpwardsPageTransitionsBuilder();
+    return matchingBuilder.buildTransitions<T>(route, context, animation, secondaryAnimation, child);
   }
 
   // Just used to the builders Map to a list with one PageTransitionsBuilder per platform
diff --git a/packages/flutter/lib/src/services/hardware_keyboard.dart b/packages/flutter/lib/src/services/hardware_keyboard.dart
index 03130f7..e782fed 100644
--- a/packages/flutter/lib/src/services/hardware_keyboard.dart
+++ b/packages/flutter/lib/src/services/hardware_keyboard.dart
@@ -881,7 +881,7 @@
     for (final PhysicalKeyboardKey key in physicalKeysPressed.difference(_rawKeyboard.physicalKeysPressed)) {
       _keyEventsSinceLastMessage.add(KeyUpEvent(
         physicalKey: key,
-        logicalKey: _hardwareKeyboard.lookUpLayout(physicalKey)!,
+        logicalKey: _hardwareKeyboard.lookUpLayout(key)!,
         timeStamp: timeStamp,
         synthesized: true,
       ));
@@ -889,7 +889,7 @@
     for (final PhysicalKeyboardKey key in _rawKeyboard.physicalKeysPressed.difference(physicalKeysPressed)) {
       _keyEventsSinceLastMessage.add(KeyDownEvent(
         physicalKey: key,
-        logicalKey: _rawKeyboard.lookUpLayout(physicalKey)!,
+        logicalKey: _rawKeyboard.lookUpLayout(key)!,
         timeStamp: timeStamp,
         synthesized: true,
       ));
diff --git a/packages/flutter/lib/src/widgets/scroll_simulation.dart b/packages/flutter/lib/src/widgets/scroll_simulation.dart
index 70b9047..3e9a1c2 100644
--- a/packages/flutter/lib/src/widgets/scroll_simulation.dart
+++ b/packages/flutter/lib/src/widgets/scroll_simulation.dart
@@ -129,8 +129,6 @@
   }
 }
 
-const double _inflexion = 0.35;
-
 /// An implementation of scroll physics that matches Android.
 ///
 /// See also:
@@ -149,9 +147,10 @@
     required this.velocity,
     this.friction = 0.015,
     Tolerance tolerance = Tolerance.defaultTolerance,
-  }) : super(tolerance: tolerance) {
-    _duration = _splineFlingDuration(velocity);
-    _distance = _splineFlingDistance(velocity);
+  }) : assert(_flingVelocityPenetration(0.0) == _initialVelocityPenetration),
+       super(tolerance: tolerance) {
+    _duration = _flingDuration(velocity);
+    _distance = (velocity * _duration / _initialVelocityPenetration).abs();
   }
 
   /// The position of the particle at the beginning of the simulation.
@@ -166,7 +165,7 @@
   /// The more friction the particle experiences, the sooner it stops.
   final double friction;
 
-  late int _duration;
+  late double _duration;
   late double _distance;
 
   // See DECELERATION_RATE.
@@ -174,184 +173,59 @@
 
   // See computeDeceleration().
   static double _decelerationForFriction(double friction) {
-    return 9.80665 *
-        39.37 *
-        friction *
-        1.0 * // Flutter operates on logical pixels so the DPI should be 1.0.
-        160.0;
+    return friction * 61774.04968;
   }
 
-  // See getSplineDeceleration().
-  double _splineDeceleration(double velocity) {
-    return math.log(_inflexion * velocity.abs() / (friction * _decelerationForFriction(0.84)));
+  // See getSplineFlingDuration(). Returns a value in seconds.
+  double _flingDuration(double velocity) {
+    // See mPhysicalCoeff
+    final double scaledFriction = friction * _decelerationForFriction(0.84);
+
+    // See getSplineDeceleration().
+    final double deceleration = math.log(0.35 * velocity.abs() / scaledFriction);
+
+    return math.exp(deceleration / (_kDecelerationRate - 1.0));
   }
 
-  // See getSplineFlingDuration().
-  int _splineFlingDuration(double velocity) {
-    final double deceleration = _splineDeceleration(velocity);
-    return (1000 * math.exp(deceleration / (_kDecelerationRate - 1.0))).round();
+  // Based on a cubic curve fit to the Scroller.computeScrollOffset() values
+  // produced for an initial velocity of 4000. The value of Scroller.getDuration()
+  // and Scroller.getFinalY() were 686ms and 961 pixels respectively.
+  //
+  // Algebra courtesy of Wolfram Alpha.
+  //
+  // f(x) = scrollOffset, x is time in milliseconds
+  // f(x) = 3.60882×10^-6 x^3 - 0.00668009 x^2 + 4.29427 x - 3.15307
+  // f(x) = 3.60882×10^-6 x^3 - 0.00668009 x^2 + 4.29427 x, so f(0) is 0
+  // f(686ms) = 961 pixels
+  // Scale to f(0 <= t <= 1.0), x = t * 686
+  // f(t) = 1165.03 t^3 - 3143.62 t^2 + 2945.87 t
+  // Scale f(t) so that 0.0 <= f(t) <= 1.0
+  // f(t) = (1165.03 t^3 - 3143.62 t^2 + 2945.87 t) / 961.0
+  //      = 1.2 t^3 - 3.27 t^2 + 3.065 t
+  static const double _initialVelocityPenetration = 3.065;
+  static double _flingDistancePenetration(double t) {
+    return (1.2 * t * t * t) - (3.27 * t * t) + (_initialVelocityPenetration * t);
   }
 
-  // See getSplineFlingDistance().
-  double _splineFlingDistance(double velocity) {
-    final double l = _splineDeceleration(velocity);
-    final double decelMinusOne = _kDecelerationRate - 1.0;
-    return friction *
-        _decelerationForFriction(0.84) *
-        math.exp(_kDecelerationRate / decelMinusOne * l);
+  // The derivative of the _flingDistancePenetration() function.
+  static double _flingVelocityPenetration(double t) {
+    return (3.6 * t * t) - (6.54 * t) + _initialVelocityPenetration;
   }
 
   @override
   double x(double time) {
-    if (time == 0) {
-      return position;
-    }
-    final _NBSample sample = _NBSample(time, _duration);
-    return position + (sample.distanceCoef * _distance) * velocity.sign;
+    final double t = (time / _duration).clamp(0.0, 1.0);
+    return position + _distance * _flingDistancePenetration(t) * velocity.sign;
   }
 
   @override
   double dx(double time) {
-    if (time == 0) {
-      return velocity;
-    }
-    final _NBSample sample = _NBSample(time, _duration);
-    return sample.velocityCoef * _distance / _duration * velocity.sign * 1000.0;
+    final double t = (time / _duration).clamp(0.0, 1.0);
+    return _distance * _flingVelocityPenetration(t) * velocity.sign / _duration;
   }
 
   @override
   bool isDone(double time) {
-    return time * 1000.0 >= _duration;
+    return time >= _duration;
   }
 }
-
-class _NBSample {
-  _NBSample(double time, int duration) {
-    // See computeScrollOffset().
-    final double t = time * 1000.0 / duration;
-    final int index = (_nbSamples * t).clamp(0, _nbSamples).round();
-    _distanceCoef = 1.0;
-    _velocityCoef = 0.0;
-    if (index < _nbSamples) {
-      final double tInf = index / _nbSamples;
-      final double tSup = (index + 1) / _nbSamples;
-      final double dInf = _splinePosition[index];
-      final double dSup = _splinePosition[index + 1];
-      _velocityCoef = (dSup - dInf) / (tSup - tInf);
-      _distanceCoef = dInf + (t - tInf) * _velocityCoef;
-    }
-  }
-
-  late double _velocityCoef;
-  double get velocityCoef => _velocityCoef;
-
-  late double _distanceCoef;
-  double get distanceCoef => _distanceCoef;
-
-  static const int _nbSamples = 100;
-
-  // Generated from dev/tools/generate_android_spline_data.dart.
-  static final List<double> _splinePosition = <double>[
-    0.000022888183591973643,
-    0.028561000304762274,
-    0.05705195792956655,
-    0.08538917797618413,
-    0.11349556286812107,
-    0.14129881694635613,
-    0.16877157254923383,
-    0.19581093511175632,
-    0.22239649722992452,
-    0.24843841866631658,
-    0.2740024733220569,
-    0.298967680744136,
-    0.32333234658228116,
-    0.34709556909569184,
-    0.3702249257894571,
-    0.39272483400399893,
-    0.41456988647721615,
-    0.43582889025419114,
-    0.4564192786416,
-    0.476410299013587,
-    0.4957560715637827,
-    0.5145493169954743,
-    0.5327205670880077,
-    0.5502846891191615,
-    0.5673274324802855,
-    0.583810881323224,
-    0.5997478744397482,
-    0.615194045299478,
-    0.6301165005270208,
-    0.6445484042257972,
-    0.6585198219185201,
-    0.6720397744233084,
-    0.6850997688076114,
-    0.6977281404741683,
-    0.7099506591298411,
-    0.7217749311525871,
-    0.7331784038850426,
-    0.7442308394229518,
-    0.7549087205105974,
-    0.7652471277371271,
-    0.7752251637549381,
-    0.7848768260203478,
-    0.7942056937103814,
-    0.8032299679689082,
-    0.8119428702388629,
-    0.8203713516576219,
-    0.8285187880808974,
-    0.8363794492831295,
-    0.8439768562813565,
-    0.851322799855549,
-    0.8584111051351724,
-    0.8652534074722162,
-    0.8718525580962131,
-    0.8782333271742155,
-    0.8843892099362031,
-    0.8903155590440985,
-    0.8960465359221951,
-    0.9015574505919048,
-    0.9068736766459904,
-    0.9119951682409297,
-    0.9169321898723632,
-    0.9216747065581234,
-    0.9262420604674766,
-    0.9306331858366086,
-    0.9348476990715433,
-    0.9389007110754832,
-    0.9427903495057521,
-    0.9465220679845756,
-    0.9500943036519721,
-    0.9535176728088761,
-    0.9567898524767604,
-    0.959924306623116,
-    0.9629127700159108,
-    0.9657622101750765,
-    0.9684818726275105,
-    0.9710676079044347,
-    0.9735231939498,
-    0.9758514437576309,
-    0.9780599066560445,
-    0.9801485715370128,
-    0.9821149805689633,
-    0.9839677526782791,
-    0.9857085499421516,
-    0.9873347811966005,
-    0.9888547171706613,
-    0.9902689443512227,
-    0.9915771042095881,
-    0.9927840651641069,
-    0.9938913963715834,
-    0.9948987305580712,
-    0.9958114963810524,
-    0.9966274782266875,
-    0.997352148697352,
-    0.9979848677523623,
-    0.9985285021374979,
-    0.9989844084453229,
-    0.9993537595844986,
-    0.999638729860106,
-    0.9998403888004533,
-    0.9999602810470701,
-    1.0,
-  ];
-}
diff --git a/packages/flutter/test/material/page_test.dart b/packages/flutter/test/material/page_test.dart
index 9aa1525..2b1a77b 100644
--- a/packages/flutter/test/material/page_test.dart
+++ b/packages/flutter/test/material/page_test.dart
@@ -3,7 +3,6 @@
 // found in the LICENSE file.
 
 import 'package:flutter/cupertino.dart' show CupertinoPageRoute;
-import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter/rendering.dart';
 import 'package:flutter_test/flutter_test.dart';
@@ -66,10 +65,7 @@
 
     expect(find.text('Page 1'), isOnstage);
     expect(find.text('Page 2'), findsNothing);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.android),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: TargetPlatformVariant.only(TargetPlatform.android));
 
   testWidgets('test page transition', (WidgetTester tester) async {
     final Key page2Key = UniqueKey();
@@ -150,10 +146,7 @@
 
     // Page 1 is back where it started.
     expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
 
   testWidgets('test fullscreen dialog transition', (WidgetTester tester) async {
     await tester.pumpWidget(
@@ -213,10 +206,7 @@
 
     // Page 1 is back where it started.
     expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
 
   testWidgets('test no back gesture on Android', (WidgetTester tester) async {
     await tester.pumpWidget(
@@ -246,10 +236,7 @@
 
     // Page 2 didn't move
     expect(tester.getTopLeft(find.text('Page 2')), Offset.zero);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.android),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: TargetPlatformVariant.only(TargetPlatform.android));
 
   testWidgets('test back gesture', (WidgetTester tester) async {
     await tester.pumpWidget(
@@ -290,10 +277,7 @@
     await tester.pump();
 
     expect(tester.getTopLeft(find.text('Page 2')), const Offset(100.0, 0.0));
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS, TargetPlatform.macOS }));
 
   testWidgets('back gesture while OS changes', (WidgetTester tester) async {
     final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@@ -378,13 +362,13 @@
     expect(find.text('PUSH'), findsNothing);
     expect(find.text('HELLO'), findsOneWidget);
     await tester.pump(const Duration(milliseconds: 20));
-    // As no transitions are specified for macOS the drag should do nothing
-    expect(find.text('PUSH'), findsNothing);
+    expect(find.text('PUSH'), findsOneWidget);
     expect(find.text('HELLO'), findsOneWidget);
     final Offset helloPosition6 = tester.getCenter(find.text('HELLO'));
-    expect(helloPosition5, helloPosition6);
+    expect(helloPosition5.dx, lessThan(helloPosition6.dx));
+    expect(helloPosition5.dy, helloPosition6.dy);
     expect(Theme.of(tester.element(find.text('HELLO'))).platform, TargetPlatform.macOS);
-  }, skip: kIsWeb); // [intended] doesn't apply to the web.
+  });
 
   testWidgets('test no back gesture on fullscreen dialogs', (WidgetTester tester) async {
     await tester.pumpWidget(
@@ -495,10 +479,7 @@
 
     // Page 1 is back where it started.
     expect(widget1InitialTopLeft == widget1TransientTopLeft, true);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('test edge swipe then drop back at starting point works', (WidgetTester tester) async {
     await tester.pumpWidget(
@@ -566,10 +547,7 @@
 
     expect(find.text('Page 1'), isOnstage);
     expect(find.text('Page 2'), findsNothing);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('Back swipe dismiss interrupted by route push', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/28728
@@ -664,10 +642,7 @@
     await tester.pumpAndSettle();
     expect(find.text('route'), findsOneWidget);
     expect(find.text('push'), findsNothing);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('During back swipe the route ignores input', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/39989
@@ -737,10 +712,7 @@
     await tester.pumpAndSettle();
     expect(tester.getTopLeft(find.byKey(pageScaffoldKey)), const Offset(400, 0));
     expect(tester.getTopLeft(find.byKey(homeScaffoldKey)).dx, lessThan(0));
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('After a pop caused by a back-swipe, input reaches the exposed route', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/41024
@@ -811,10 +783,7 @@
     await tester.tap(find.byKey(homeScaffoldKey));
     expect(homeTapCount, 2);
     expect(pageTapCount, 1);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('A MaterialPageRoute should slide out with CupertinoPageTransition when a compatible PageRoute is pushed on top of it', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/44864.
@@ -842,10 +811,7 @@
     // Title of the first route slides to the left.
     expect(titleInitialTopLeft.dy, equals(titleTransientTopLeft.dy));
     expect(titleInitialTopLeft.dx, greaterThan(titleTransientTopLeft.dx));
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('MaterialPage works', (WidgetTester tester) async {
     final LocalKey pageKey = UniqueKey();
diff --git a/packages/flutter/test/material/page_transitions_theme_test.dart b/packages/flutter/test/material/page_transitions_theme_test.dart
index aa56211..2db3f43 100644
--- a/packages/flutter/test/material/page_transitions_theme_test.dart
+++ b/packages/flutter/test/material/page_transitions_theme_test.dart
@@ -11,33 +11,17 @@
   testWidgets('Default PageTransitionsTheme platform', (WidgetTester tester) async {
     await tester.pumpWidget(const MaterialApp(home: Text('home')));
     final PageTransitionsTheme theme = Theme.of(tester.element(find.text('home'))).pageTransitionsTheme;
-
     expect(theme.builders, isNotNull);
-    if (kIsWeb) {
-      // There aren't any default transitions defined for web
-      expect(theme.builders, isEmpty);
-    } else {
-      // There should only be builders for the mobile platforms.
-      for (final TargetPlatform platform in TargetPlatform.values) {
-        switch (platform) {
-          case TargetPlatform.android:
-          case TargetPlatform.iOS:
-          case TargetPlatform.fuchsia:
-            expect(theme.builders[platform], isNotNull,
-                reason: 'theme builder for $platform is null');
-            break;
-          case TargetPlatform.linux:
-          case TargetPlatform.macOS:
-          case TargetPlatform.windows:
-            expect(theme.builders[platform], isNull,
-                reason: 'theme builder for $platform is not null');
-            break;
-        }
+    for (final TargetPlatform platform in TargetPlatform.values) {
+      if (platform == TargetPlatform.fuchsia) {
+        // No builder on Fuchsia.
+        continue;
       }
+      expect(theme.builders[platform], isNotNull, reason: 'theme builder for $platform is null');
     }
   });
 
-  testWidgets('Default PageTransitionsTheme builds a CupertinoPageTransition', (WidgetTester tester) async {
+  testWidgets('Default PageTransitionsTheme builds a CupertionPageTransition', (WidgetTester tester) async {
     final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
       '/': (BuildContext context) => Material(
         child: TextButton(
@@ -61,10 +45,7 @@
     await tester.pumpAndSettle();
     expect(find.text('page b'), findsOneWidget);
     expect(find.byType(CupertinoPageTransition), findsOneWidget);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.iOS),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('Default PageTransitionsTheme builds a _FadeUpwardsPageTransition for android', (WidgetTester tester) async {
     final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@@ -97,10 +78,7 @@
     await tester.pumpAndSettle();
     expect(find.text('page b'), findsOneWidget);
     expect(findFadeUpwardsPageTransition(), findsOneWidget);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.android),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: TargetPlatformVariant.only(TargetPlatform.android));
 
   testWidgets('PageTransitionsTheme override builds a _OpenUpwardsPageTransition', (WidgetTester tester) async {
     final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@@ -140,10 +118,7 @@
     await tester.pumpAndSettle();
     expect(find.text('page b'), findsOneWidget);
     expect(findOpenUpwardsPageTransition(), findsOneWidget);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.android),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: TargetPlatformVariant.only(TargetPlatform.android));
 
   testWidgets('PageTransitionsTheme override builds a _ZoomPageTransition', (WidgetTester tester) async {
     final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
@@ -183,10 +158,7 @@
     await tester.pumpAndSettle();
     expect(find.text('page b'), findsOneWidget);
     expect(findZoomPageTransition(), findsOneWidget);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.android),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: TargetPlatformVariant.only(TargetPlatform.android));
 
   testWidgets('_ZoomPageTransition only cause child widget built once', (WidgetTester tester) async {
     // Regression test for https://github.com/flutter/flutter/issues/58345
@@ -232,8 +204,5 @@
     await tester.tap(find.text('pop'));
     await tester.pumpAndSettle();
     expect(builtCount, 1);
-  },
-    variant: TargetPlatformVariant.only(TargetPlatform.android),
-    skip: kIsWeb, // [intended] no default transitions on the web.
-  );
+  }, variant: TargetPlatformVariant.only(TargetPlatform.android));
 }
diff --git a/packages/flutter/test/material/text_field_test.dart b/packages/flutter/test/material/text_field_test.dart
index e16d93f..488c041 100644
--- a/packages/flutter/test/material/text_field_test.dart
+++ b/packages/flutter/test/material/text_field_test.dart
@@ -1491,13 +1491,13 @@
     // Wait for context menu to be built.
     await tester.pumpAndSettle();
     final RenderBox container = tester.renderObject(find.descendant(
-      of: find.byType(Overlay),
+      of: find.byType(FadeTransition),
       matching: find.byType(SizedBox),
     ).first);
     expect(container.size, Size.zero);
   }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.android, TargetPlatform.fuchsia, TargetPlatform.linux, TargetPlatform.windows }));
 
-  testWidgets('Swapping controllers should update selection', (WidgetTester tester) async {
+  testWidgets('Sawping controllers should update selection', (WidgetTester tester) async {
     TextEditingController controller = TextEditingController(text: 'readonly');
     final OverlayEntry entry = OverlayEntry(
       builder: (BuildContext context) {
diff --git a/packages/flutter/test/services/hardware_keyboard_test.dart b/packages/flutter/test/services/hardware_keyboard_test.dart
index 7b41927..5ea1356 100644
--- a/packages/flutter/test/services/hardware_keyboard_test.dart
+++ b/packages/flutter/test/services/hardware_keyboard_test.dart
@@ -4,6 +4,7 @@
 
 import 'dart:ui' as ui;
 
+import 'package:flutter/foundation.dart';
 import 'package:flutter/services.dart';
 import 'package:flutter/widgets.dart';
 import 'package:flutter_test/flutter_test.dart';
@@ -67,6 +68,34 @@
       equals(<KeyboardLockMode>{}));
   }, variant: KeySimulatorTransitModeVariant.keyDataThenRawKeyData());
 
+  testWidgets('KeyboardManager synthesizes modifier keys in rawKeyData mode', (WidgetTester tester) async {
+    final List<KeyEvent> events = <KeyEvent>[];
+    HardwareKeyboard.instance.addHandler((KeyEvent event) {
+      events.add(event);
+      return false;
+    });
+    // While ShiftLeft is held (the event of which was skipped), press keyA.
+    final Map<String, dynamic> rawMessage = kIsWeb ? (
+      KeyEventSimulator.getKeyData(
+        LogicalKeyboardKey.keyA,
+        platform: 'web',
+      )..['metaState'] = RawKeyEventDataWeb.modifierShift
+    ) : (
+      KeyEventSimulator.getKeyData(
+        LogicalKeyboardKey.keyA,
+        platform: 'android',
+      )..['metaState'] = RawKeyEventDataAndroid.modifierLeftShift | RawKeyEventDataAndroid.modifierShift
+    );
+    tester.binding.keyEventManager.handleRawKeyMessage(rawMessage);
+    expect(events, hasLength(2));
+    expect(events[0].physicalKey, PhysicalKeyboardKey.shiftLeft);
+    expect(events[0].logicalKey, LogicalKeyboardKey.shiftLeft);
+    expect(events[0].synthesized, true);
+    expect(events[1].physicalKey, PhysicalKeyboardKey.keyA);
+    expect(events[1].logicalKey, LogicalKeyboardKey.keyA);
+    expect(events[1].synthesized, false);
+  });
+
   testWidgets('Dispatch events to all handlers', (WidgetTester tester) async {
     final FocusNode focusNode = FocusNode();
     final List<int> logs = <int>[];
diff --git a/packages/flutter/test/widgets/heroes_test.dart b/packages/flutter/test/widgets/heroes_test.dart
index 69601a9..a4fb5ed 100644
--- a/packages/flutter/test/widgets/heroes_test.dart
+++ b/packages/flutter/test/widgets/heroes_test.dart
@@ -1836,7 +1836,7 @@
     expect(find.byKey(firstKey), isInCard);
     expect(find.byKey(secondKey), isOnstage);
     expect(find.byKey(secondKey), isInCard);
-  }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb);
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('Heroes can transition on gesture in one frame', (WidgetTester tester) async {
     transitionFromUserGestures = true;
@@ -1879,7 +1879,7 @@
     expect(find.byKey(firstKey), isOnstage);
     expect(find.byKey(firstKey), isInCard);
     expect(find.byKey(secondKey), findsNothing);
-  }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb);
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('Heroes animate should hide destination hero and display original hero in case of dismissed', (WidgetTester tester) async {
     transitionFromUserGestures = true;
@@ -1915,7 +1915,7 @@
     expect(find.byKey(firstKey), findsNothing);
     expect(find.byKey(secondKey), isOnstage);
     expect(find.byKey(secondKey), isInCard);
-  }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb);
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('Handles transitions when a non-default initial route is set', (WidgetTester tester) async {
     await tester.pumpWidget(MaterialApp(
diff --git a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
index 3a4492b..e0a578f 100644
--- a/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
+++ b/packages/flutter/test/widgets/list_wheel_scroll_view_test.dart
@@ -1232,7 +1232,7 @@
       await tester.fling(
         find.byType(ListWheelScrollView),
         const Offset(0.0, -50.0),
-        100.0,
+        800.0,
       );
 
       // At this moment, the ballistics is started but 50px is still inside the
diff --git a/packages/flutter/test/widgets/page_transitions_test.dart b/packages/flutter/test/widgets/page_transitions_test.dart
index 9a939a5..5c777bc 100644
--- a/packages/flutter/test/widgets/page_transitions_test.dart
+++ b/packages/flutter/test/widgets/page_transitions_test.dart
@@ -2,7 +2,6 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-import 'package:flutter/foundation.dart';
 import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 
@@ -197,7 +196,7 @@
     settingsOffset = tester.getTopLeft(find.text('Settings'));
     expect(settingsOffset.dx, greaterThan(100.0));
     expect(settingsOffset.dy, 100.0);
-  }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb);
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets("Check back gesture doesn't start during transitions", (WidgetTester tester) async {
     final GlobalKey containerKey1 = GlobalKey();
@@ -240,7 +239,7 @@
 
     expect(find.text('Home'), isOnstage);
     expect(find.text('Settings'), findsNothing);
-  }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb);
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   // Tests bug https://github.com/flutter/flutter/issues/6451
   testWidgets('Check back gesture with a persistent bottom sheet showing', (WidgetTester tester) async {
@@ -294,7 +293,7 @@
 
     // Sheet did not call setState (since the gesture did nothing).
     expect(sheet.setStateCalled, isFalse);
-  }, variant: TargetPlatformVariant.only(TargetPlatform.iOS), skip: kIsWeb);
+  }, variant: const TargetPlatformVariant(<TargetPlatform>{ TargetPlatform.iOS,  TargetPlatform.macOS }));
 
   testWidgets('Test completed future', (WidgetTester tester) async {
     final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
diff --git a/packages/flutter/test/widgets/scroll_simulation_test.dart b/packages/flutter/test/widgets/scroll_simulation_test.dart
index 99738be..69958f9 100644
--- a/packages/flutter/test/widgets/scroll_simulation_test.dart
+++ b/packages/flutter/test/widgets/scroll_simulation_test.dart
@@ -23,21 +23,4 @@
     checkInitialConditions(75.0, 614.2093);
     checkInitialConditions(5469.0, 182.114534);
   });
-
-  test('ClampingScrollSimulation velocity eventually reaches zero', () {
-    void checkFinalConditions(double position, double velocity) {
-      final ClampingScrollSimulation simulation = ClampingScrollSimulation(position: position, velocity: velocity);
-      expect(simulation.dx(10.0), equals(0.0));
-    }
-
-    checkFinalConditions(51.0, 2000.0);
-    checkFinalConditions(584.0, 2617.294734);
-    checkFinalConditions(345.0, 1982.785934);
-    checkFinalConditions(0.0, 1831.366634);
-    checkFinalConditions(-156.2, 1541.57665);
-    checkFinalConditions(4.0, 1139.250439);
-    checkFinalConditions(4534.0, 1073.553798);
-    checkFinalConditions(75.0, 614.2093);
-    checkFinalConditions(5469.0, 182.114534);
-  });
 }
diff --git a/packages/flutter/test/widgets/scrollable_fling_test.dart b/packages/flutter/test/widgets/scrollable_fling_test.dart
index be08e95..1d34b11 100644
--- a/packages/flutter/test/widgets/scrollable_fling_test.dart
+++ b/packages/flutter/test/widgets/scrollable_fling_test.dart
@@ -44,6 +44,11 @@
     expect(getCurrentOffset(), dragOffset);
     await tester.pump(const Duration(seconds: 5));
     final double androidResult = getCurrentOffset();
+    // Regression test for https://github.com/flutter/flutter/issues/83632
+    // Before changing these values, ensure the fling results in a distance that
+    // makes sense. See issue for more context.
+    expect(androidResult, greaterThan(394.0));
+    expect(androidResult, lessThan(395.0));
 
     await pumpTest(tester, TargetPlatform.linux);
     await tester.fling(find.byType(ListView), const Offset(0.0, -dragOffset), 1000.0);
@@ -147,6 +152,6 @@
     expect(log, equals(<String>['tap 21']));
     await tester.tap(find.byType(Scrollable));
     await tester.pump(const Duration(milliseconds: 50));
-    expect(log, equals(<String>['tap 21', 'tap 49']));
+    expect(log, equals(<String>['tap 21', 'tap 48']));
   });
 }
diff --git a/packages/flutter/test/widgets/scrollable_semantics_test.dart b/packages/flutter/test/widgets/scrollable_semantics_test.dart
index f79e52f..75d5c44 100644
--- a/packages/flutter/test/widgets/scrollable_semantics_test.dart
+++ b/packages/flutter/test/widgets/scrollable_semantics_test.dart
@@ -233,7 +233,7 @@
 
     expect(semantics, includesNodeWith(
       scrollExtentMin: 0.0,
-      scrollPosition: 394.3,
+      scrollPosition: 380.2,
       scrollExtentMax: 520.0,
       actions: <SemanticsAction>[
         SemanticsAction.scrollUp,
@@ -282,7 +282,7 @@
 
     expect(semantics, includesNodeWith(
       scrollExtentMin: 0.0,
-      scrollPosition: 394.3,
+      scrollPosition: 380.2,
       scrollExtentMax: double.infinity,
       actions: <SemanticsAction>[
         SemanticsAction.scrollUp,
@@ -294,7 +294,7 @@
 
     expect(semantics, includesNodeWith(
       scrollExtentMin: 0.0,
-      scrollPosition: 788.6,
+      scrollPosition: 760.4,
       scrollExtentMax: double.infinity,
       actions: <SemanticsAction>[
         SemanticsAction.scrollUp,
diff --git a/packages/flutter/test/widgets/scrollable_test.dart b/packages/flutter/test/widgets/scrollable_test.dart
index 082fe70..567535f 100644
--- a/packages/flutter/test/widgets/scrollable_test.dart
+++ b/packages/flutter/test/widgets/scrollable_test.dart
@@ -918,8 +918,8 @@
     expect(find.byKey(const ValueKey<String>('Box 0')), findsNothing);
     expect(find.byKey(const ValueKey<String>('Box 52')), findsOneWidget);
 
-    expect(expensiveWidgets, 40);
-    expect(cheapWidgets, 21);
+    expect(expensiveWidgets, 38);
+    expect(cheapWidgets, 20);
   });
 
   testWidgets('Can recommendDeferredLoadingForContext - override heuristic', (WidgetTester tester) async {
@@ -961,9 +961,9 @@
     expect(find.byKey(const ValueKey<String>('Box 0')), findsNothing);
     expect(find.byKey(const ValueKey<String>('Cheap box 52')), findsOneWidget);
 
-    expect(expensiveWidgets, 17);
-    expect(cheapWidgets, 44);
-    expect(physics.count, 44 + 17);
+    expect(expensiveWidgets, 18);
+    expect(cheapWidgets, 40);
+    expect(physics.count, 40 + 18);
   });
 
   testWidgets('Can recommendDeferredLoadingForContext - override heuristic and always return true', (WidgetTester tester) async {
@@ -1004,7 +1004,7 @@
     expect(find.byKey(const ValueKey<String>('Cheap box 52')), findsOneWidget);
 
     expect(expensiveWidgets, 0);
-    expect(cheapWidgets, 61);
+    expect(cheapWidgets, 58);
   });
 
   testWidgets('ensureVisible does not move PageViews', (WidgetTester tester) async {
diff --git a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart
index de366e5..23adcee 100644
--- a/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart
+++ b/packages/flutter/test/widgets/slivers_appbar_floating_pinned_test.dart
@@ -151,7 +151,7 @@
     );
     expect(semantics, hasSemantics(expectedSemantics, ignoreTransform: true, ignoreId: true, ignoreRect: true));
 
-    await tester.fling(find.text('Tile 2'), const Offset(0, -600), 1950);
+    await tester.fling(find.text('Tile 2'), const Offset(0, -600), 2000);
     await tester.pumpAndSettle();
 
     expectedSemantics = TestSemantics.root(
diff --git a/packages/flutter_tools/pubspec.yaml b/packages/flutter_tools/pubspec.yaml
index 311a89a..70b7ca5 100644
--- a/packages/flutter_tools/pubspec.yaml
+++ b/packages/flutter_tools/pubspec.yaml
@@ -10,7 +10,7 @@
   archive: 3.1.2
   args: 2.2.0
   browser_launcher: 1.0.0
-  dds: 2.0.3
+  dds: 2.0.4
   dwds: 11.2.0
   completion: 1.0.0
   coverage: 1.0.3
@@ -104,4 +104,4 @@
   # Exclude this package from the hosted API docs.
   nodoc: true
 
-# PUBSPEC CHECKSUM: 28f3
+# PUBSPEC CHECKSUM: bbf4