upgrade to 9a721c456d4a6418c60f2512cbb54ee420b9c69b
diff --git a/framework/lib/src/cupertino/bottom_tab_bar.dart b/framework/lib/src/cupertino/bottom_tab_bar.dart
index 286cd02..d970962 100644
--- a/framework/lib/src/cupertino/bottom_tab_bar.dart
+++ b/framework/lib/src/cupertino/bottom_tab_bar.dart
@@ -15,7 +15,7 @@
 const double _kTabBarHeight = 50.0;
 
 const Color _kDefaultTabBarBorderColor = CupertinoDynamicColor.withBrightness(
-  color: Color(0x4C000000),
+  color: Color(0x4D000000),
   darkColor: Color(0x29000000),
 );
 const Color _kDefaultTabBarInactiveColor = CupertinoColors.inactiveGray;
diff --git a/framework/lib/src/cupertino/context_menu.dart b/framework/lib/src/cupertino/context_menu.dart
index 15788df..1fca184 100644
--- a/framework/lib/src/cupertino/context_menu.dart
+++ b/framework/lib/src/cupertino/context_menu.dart
@@ -8,6 +8,7 @@
 import 'package:flute/foundation.dart';
 import 'package:flute/gestures.dart' show kMinFlingVelocity;
 import 'package:flute/scheduler.dart';
+import 'package:flute/services.dart' show HapticFeedback;
 import 'package:flute/widgets.dart';
 
 import 'colors.dart';
@@ -137,6 +138,7 @@
     super.key,
     required this.actions,
     required Widget this.child,
+    this.enableHapticFeedback = false,
     @Deprecated(
       'Use CupertinoContextMenu.builder instead. '
       'This feature was deprecated after v3.4.0-34.1.pre.',
@@ -157,6 +159,7 @@
     super.key,
     required this.actions,
     required this.builder,
+    this.enableHapticFeedback = false,
   }) : assert(actions.isNotEmpty),
        child = null,
        previewBuilder = null;
@@ -388,6 +391,13 @@
   /// This parameter cannot be null or empty.
   final List<Widget> actions;
 
+  /// If true, clicking on the [CupertinoContextMenuAction]s will
+  /// produce haptic feedback.
+  ///
+  /// Uses [HapticFeedback.heavyImpact] when activated.
+  /// Defaults to false.
+  final bool enableHapticFeedback;
+
   /// A function that returns an alternative widget to show when the
   /// [CupertinoContextMenu] is open.
   ///
@@ -481,6 +491,15 @@
     _openController.addStatusListener(_onDecoyAnimationStatusChange);
   }
 
+  void _listenerCallback() {
+    if (_openController.status != AnimationStatus.reverse &&
+        _openController.value >= _midpoint &&
+        widget.enableHapticFeedback) {
+      HapticFeedback.heavyImpact();
+      _openController.removeListener(_listenerCallback);
+    }
+  }
+
   // Determine the _ContextMenuLocation based on the location of the original
   // child in the screen.
   //
@@ -583,24 +602,28 @@
   }
 
   void _onTap() {
+    _openController.removeListener(_listenerCallback);
     if (_openController.isAnimating && _openController.value < _midpoint) {
       _openController.reverse();
     }
   }
 
   void _onTapCancel() {
+    _openController.removeListener(_listenerCallback);
     if (_openController.isAnimating && _openController.value < _midpoint) {
       _openController.reverse();
     }
   }
 
   void _onTapUp(TapUpDetails details) {
+    _openController.removeListener(_listenerCallback);
     if (_openController.isAnimating && _openController.value < _midpoint) {
       _openController.reverse();
     }
   }
 
   void _onTapDown(TapDownDetails details) {
+    _openController.addListener(_listenerCallback);
     setState(() {
       _childHidden = true;
     });
@@ -1370,27 +1393,24 @@
     );
 
     return SafeArea(
-      child: Padding(
-        padding: const EdgeInsets.all(_kPadding),
-        child: Align(
-          alignment: Alignment.topLeft,
-          child: GestureDetector(
-            onPanEnd: _onPanEnd,
-            onPanStart: _onPanStart,
-            onPanUpdate: _onPanUpdate,
-            child: AnimatedBuilder(
-              animation: _moveController,
-              builder: _buildAnimation,
-              child: widget.orientation == Orientation.portrait
-                ? Column(
-                  crossAxisAlignment: CrossAxisAlignment.start,
-                  children: children,
-                )
-                : Row(
-                  crossAxisAlignment: CrossAxisAlignment.start,
-                  children: children,
-                ),
-            ),
+      child: Align(
+        alignment: Alignment.topLeft,
+        child: GestureDetector(
+          onPanEnd: _onPanEnd,
+          onPanStart: _onPanStart,
+          onPanUpdate: _onPanUpdate,
+          child: AnimatedBuilder(
+            animation: _moveController,
+            builder: _buildAnimation,
+            child: widget.orientation == Orientation.portrait
+              ? Column(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: children,
+              )
+              : Row(
+                crossAxisAlignment: CrossAxisAlignment.start,
+                children: children,
+              ),
           ),
         ),
       ),
@@ -1414,12 +1434,13 @@
   final _ContextMenuLocation _contextMenuLocation;
   final Orientation _orientation;
 
+  static const double _kMenuWidth = 250.0;
+
   // Get the children, whose order depends on orientation and
   // contextMenuLocation.
   List<Widget> getChildren(BuildContext context) {
-    final Widget menu = Flexible(
-      fit: FlexFit.tight,
-      flex: 2,
+    final Widget menu = SizedBox(
+      width: _kMenuWidth,
       child: IntrinsicHeight(
         child: ClipRRect(
           borderRadius: const BorderRadius.all(Radius.circular(13.0)),
@@ -1432,9 +1453,12 @@
                   decoration: BoxDecoration(
                     border: Border(
                       top: BorderSide(
-                        color: CupertinoDynamicColor.resolve(_borderColor, context),
-                        width: 0.5,
-                      )
+                        color: CupertinoDynamicColor.resolve(
+                          _borderColor,
+                          context,
+                        ),
+                        width: 0.4,
+                      ),
                     ),
                   ),
                   position: DecorationPosition.foreground,
diff --git a/framework/lib/src/cupertino/context_menu_action.dart b/framework/lib/src/cupertino/context_menu_action.dart
index 0f011ea..b01d277 100644
--- a/framework/lib/src/cupertino/context_menu_action.dart
+++ b/framework/lib/src/cupertino/context_menu_action.dart
@@ -48,18 +48,18 @@
 
 class _CupertinoContextMenuActionState extends State<CupertinoContextMenuAction> {
   static const Color _kBackgroundColor = CupertinoDynamicColor.withBrightness(
-    color: Color(0xFFEEEEEE),
+    color: Color(0xFFF1F1F1),
     darkColor: Color(0xFF212122),
   );
   static const Color _kBackgroundColorPressed = CupertinoDynamicColor.withBrightness(
     color: Color(0xFFDDDDDD),
     darkColor: Color(0xFF3F3F40),
   );
-  static const double _kButtonHeight = 56.0;
+  static const double _kButtonHeight = 43;
   static const TextStyle _kActionSheetActionStyle = TextStyle(
     fontFamily: '.SF UI Text',
     inherit: false,
-    fontSize: 20.0,
+    fontSize: 16.0,
     fontWeight: FontWeight.w400,
     color: CupertinoColors.black,
     textBaseline: TextBaseline.alphabetic,
@@ -125,9 +125,11 @@
                   ? CupertinoDynamicColor.resolve(_kBackgroundColorPressed, context)
                   : CupertinoDynamicColor.resolve(_kBackgroundColor, context),
               ),
-              padding: const EdgeInsets.symmetric(
-                vertical: 16.0,
-                horizontal: 10.0,
+              padding: const EdgeInsets.only(
+                top: 8,
+                bottom: 8,
+                left: 15.5,
+                right: 17.5,
               ),
               child: DefaultTextStyle(
                 style: _textStyle,
@@ -141,6 +143,7 @@
                       Icon(
                         widget.trailingIcon,
                         color: _textStyle.color,
+                        size: 21.0,
                       ),
                   ],
                 ),
diff --git a/framework/lib/src/foundation/binding.dart b/framework/lib/src/foundation/binding.dart
index ac6d4ac..97e30cb 100644
--- a/framework/lib/src/foundation/binding.dart
+++ b/framework/lib/src/foundation/binding.dart
@@ -138,7 +138,7 @@
   /// First calls [initInstances] to have bindings initialize their
   /// instance pointers and other state, then calls
   /// [initServiceExtensions] to have bindings initialize their
-  /// observatory service extensions, if any.
+  /// VM service extensions, if any.
   BindingBase() {
     developer.Timeline.startSync('Framework initialization');
     assert(() {
diff --git a/framework/lib/src/gestures/converter.dart b/framework/lib/src/gestures/converter.dart
index 6aa7741..db86594 100644
--- a/framework/lib/src/gestures/converter.dart
+++ b/framework/lib/src/gestures/converter.dart
@@ -278,6 +278,8 @@
                 scale: datum.scale,
               );
             case ui.PointerSignalKind.unknown:
+            default: // ignore: no_default_cases, to allow adding a new [PointerSignalKind] - PointerStylusAuxiliaryAction
+            // TODO(louisehsu): remove after landing engine PR https://github.com/flutter/engine/pull/39637
               // This branch should already have 'unknown' filtered out, but
               // we don't want to return anything or miss if someone adds a new
               // enumeration to PointerSignalKind.
diff --git a/framework/lib/src/gestures/recognizer.dart b/framework/lib/src/gestures/recognizer.dart
index 0a30fbf..d55b2b3 100644
--- a/framework/lib/src/gestures/recognizer.dart
+++ b/framework/lib/src/gestures/recognizer.dart
@@ -78,10 +78,9 @@
   /// {@endtemplate}
   GestureRecognizer({
     this.debugOwner,
-    Set<PointerDeviceKind>? supportedDevices,
+    this.supportedDevices,
     AllowedButtonsFilter? allowedButtonsFilter,
-  }) : _supportedDevices = supportedDevices,
-       _allowedButtonsFilter = allowedButtonsFilter ?? _defaultButtonAcceptBehavior;
+  }) : _allowedButtonsFilter = allowedButtonsFilter ?? _defaultButtonAcceptBehavior;
 
   /// The recognizer's owner.
   ///
@@ -97,7 +96,7 @@
   /// `supportedDevices` in the constructor, or the currently deprecated `kind`.
   /// These cannot both be set. If both are null, events from all device kinds will be
   /// tracked and recognized.
-  final Set<PointerDeviceKind>? _supportedDevices;
+  Set<PointerDeviceKind>? supportedDevices;
 
   /// {@template flutter.gestures.multidrag._allowedButtonsFilter}
   /// Called when interaction starts. This limits the dragging behavior
@@ -209,8 +208,8 @@
   /// Checks whether or not a pointer is allowed to be tracked by this recognizer.
   @protected
   bool isPointerAllowed(PointerDownEvent event) {
-    return (_supportedDevices == null ||
-            _supportedDevices!.contains(event.kind)) &&
+    return (supportedDevices == null ||
+            supportedDevices!.contains(event.kind)) &&
         _allowedButtonsFilter(event.buttons);
   }
 
@@ -223,7 +222,7 @@
   /// Checks whether or not a pointer pan/zoom is allowed to be tracked by this recognizer.
   @protected
   bool isPointerPanZoomAllowed(PointerPanZoomStartEvent event) {
-    return _supportedDevices == null || _supportedDevices!.contains(event.kind);
+    return supportedDevices == null || supportedDevices!.contains(event.kind);
   }
 
   /// For a given pointer ID, returns the device kind associated with it.
diff --git a/framework/lib/src/material/about.dart b/framework/lib/src/material/about.dart
index dea95b4..0b26bd2 100644
--- a/framework/lib/src/material/about.dart
+++ b/framework/lib/src/material/about.dart
@@ -889,7 +889,11 @@
                   // A Scrollbar is built-in below.
                   behavior: ScrollConfiguration.of(context).copyWith(scrollbars: false),
                   child: Scrollbar(
-                    child: ListView(padding: padding, children: listWidgets),
+                    child: ListView(
+                      primary: true,
+                      padding: padding,
+                      children: listWidgets,
+                    ),
                   ),
                 ),
               ),
diff --git a/framework/lib/src/material/animated_icons/animated_icons_data.dart b/framework/lib/src/material/animated_icons/animated_icons_data.dart
index 6efca7d..9cd3595 100644
--- a/framework/lib/src/material/animated_icons/animated_icons_data.dart
+++ b/framework/lib/src/material/animated_icons/animated_icons_data.dart
@@ -25,6 +25,9 @@
 ///
 ///  * [Icons], for the list of available static Material Icons.
 abstract class AnimatedIcons {
+  // This class is not meant to be instantiated or extended; this constructor
+  // prevents instantiation and extension.
+  AnimatedIcons._();
 
   /// The Material Design add to event icon animation.
   ///
diff --git a/framework/lib/src/material/app_bar.dart b/framework/lib/src/material/app_bar.dart
index 884b05f..638ed8a 100644
--- a/framework/lib/src/material/app_bar.dart
+++ b/framework/lib/src/material/app_bar.dart
@@ -172,10 +172,7 @@
 class AppBar extends StatefulWidget implements PreferredSizeWidget {
   /// Creates a Material Design app bar.
   ///
-  /// The arguments [primary], [toolbarOpacity], [bottomOpacity],
-  /// [backwardsCompatibility], and [automaticallyImplyLeading] must
-  /// not be null. Additionally, if [elevation] is specified, it must
-  /// be non-negative.
+  /// If [elevation] is specified, it must be non-negative.
   ///
   /// Typically used in the [Scaffold.appBar] property.
   AppBar({
@@ -194,11 +191,6 @@
     this.shape,
     this.backgroundColor,
     this.foregroundColor,
-    @Deprecated(
-      'This property is no longer used, please use systemOverlayStyle instead. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    this.brightness,
     this.iconTheme,
     this.actionsIconTheme,
     this.primary = true,
@@ -209,11 +201,6 @@
     this.bottomOpacity = 1.0,
     this.toolbarHeight,
     this.leadingWidth,
-    @Deprecated(
-      'This property is obsolete and is false by default. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    this.backwardsCompatibility,
     this.toolbarTextStyle,
     this.titleTextStyle,
     this.systemOverlayStyle,
@@ -499,7 +486,7 @@
   /// If null, then the [AppBarTheme.backgroundColor] is used. If that value is also
   /// null, then [AppBar] uses the overall theme's [ColorScheme.primary] if the
   /// overall theme's brightness is [Brightness.light], and [ColorScheme.surface]
-  /// if the overall theme's [brightness] is [Brightness.dark].
+  /// if the overall theme's brightness is [Brightness.dark].
   ///
   /// If this color is a [MaterialStateColor] it will be resolved against
   /// [MaterialState.scrolledUnder] when the content of the app's
@@ -525,7 +512,7 @@
   /// value is also null, then [AppBar] uses the overall theme's
   /// [ColorScheme.onPrimary] if the overall theme's brightness is
   /// [Brightness.light], and [ColorScheme.onSurface] if the overall
-  /// theme's [brightness] is [Brightness.dark].
+  /// theme's brightness is [Brightness.dark].
   ///
   /// This color is used to configure [DefaultTextStyle] that contains
   /// the toolbar's children, and the default [IconTheme] widgets that
@@ -543,38 +530,6 @@
   ///    is light or dark.
   final Color? foregroundColor;
 
-  /// {@template flutter.material.appbar.brightness}
-  /// This property is deprecated, please use [systemOverlayStyle] instead.
-  ///
-  /// Determines the brightness of the [SystemUiOverlayStyle]: for
-  /// [Brightness.dark], [SystemUiOverlayStyle.light] is used and for
-  /// [Brightness.light], [SystemUiOverlayStyle.dark] is used.
-  ///
-  /// If this value is null then [AppBarTheme.brightness] is used
-  /// and if that's null then overall theme's brightness is used.
-  ///
-  /// The AppBar is built within a `AnnotatedRegion<SystemUiOverlayStyle>`
-  /// which causes [SystemChrome.setSystemUIOverlayStyle] to be called
-  /// automatically. Apps should not enclose the AppBar with
-  /// their own [AnnotatedRegion].
-  /// {@endtemplate}
-  ///
-  /// See also:
-  ///
-  ///  * [Theme.of], which returns the current overall Material theme as
-  ///    a [ThemeData].
-  ///  * [ThemeData.colorScheme], the thirteen colors that most Material widget
-  ///    default colors are based on.
-  ///  * [ColorScheme.brightness], which indicates if the overall [Theme]
-  ///    is light or dark.
-  ///  * [backwardsCompatibility], which forces AppBar to use this
-  ///    obsolete property.
-  @Deprecated(
-    'This property is no longer used, please use systemOverlayStyle instead. '
-    'This feature was deprecated after v2.4.0-0.0.pre.',
-  )
-  final Brightness? brightness;
-
   /// {@template flutter.material.appbar.iconTheme}
   /// The color, opacity, and size to use for toolbar icons.
   ///
@@ -688,28 +643,6 @@
   /// {@endtemplate}
   final double? leadingWidth;
 
-  /// {@template flutter.material.appbar.backwardsCompatibility}
-  /// This property is deprecated and is false by default.
-  ///
-  /// If true, preserves the original defaults for the [backgroundColor],
-  /// [iconTheme], [actionsIconTheme] properties, and the original use of
-  /// the [brightness] property.
-  ///
-  /// If this property is null, then [AppBarTheme.backwardsCompatibility] of
-  /// [ThemeData.appBarTheme] is used. If that is also null, the default
-  /// value is false.
-  ///
-  /// This is a temporary property and it has been deprecated. App
-  /// developers are encouraged to opt into the new features by
-  /// leaving it default (false) and using the [foregroundColor] and
-  /// [systemOverlayStyle] properties as needed.
-  /// {@endtemplate}
-  @Deprecated(
-    'This property is obsolete and is false by default. '
-    'This feature was deprecated after v2.4.0-0.0.pre.',
-  )
-  final bool? backwardsCompatibility;
-
   /// {@template flutter.material.appbar.toolbarTextStyle}
   /// The default text style for the AppBar's [leading], and
   /// [actions] widgets, but not its [title].
@@ -748,8 +681,6 @@
   /// {@template flutter.material.appbar.systemOverlayStyle}
   /// Specifies the style to use for the system overlays that overlap the AppBar.
   ///
-  /// This property is only used if [backwardsCompatibility] is false (the default).
-  ///
   /// If this property is null, then [AppBarTheme.systemOverlayStyle] of
   /// [ThemeData.appBarTheme] is used. If that is also null, an appropriate
   /// [SystemUiOverlayStyle] is calculated based on the [backgroundColor].
@@ -900,18 +831,13 @@
     final bool useCloseButton = parentRoute is PageRoute<dynamic> && parentRoute.fullscreenDialog;
 
     final double toolbarHeight = widget.toolbarHeight ?? appBarTheme.toolbarHeight ?? kToolbarHeight;
-    final bool backwardsCompatibility = widget.backwardsCompatibility ?? appBarTheme.backwardsCompatibility ?? false;
 
-    final Color backgroundColor = backwardsCompatibility
-      ? widget.backgroundColor
-        ?? appBarTheme.backgroundColor
-        ?? theme.primaryColor
-      : _resolveColor(
-          states,
-          widget.backgroundColor,
-          appBarTheme.backgroundColor,
-          defaults.backgroundColor!,
-        );
+    final Color backgroundColor = _resolveColor(
+      states,
+      widget.backgroundColor,
+      appBarTheme.backgroundColor,
+      defaults.backgroundColor!,
+    );
 
     final Color foregroundColor = widget.foregroundColor
       ?? appBarTheme.foregroundColor
@@ -928,13 +854,9 @@
         ?? elevation
       : elevation;
 
-    IconThemeData overallIconTheme = backwardsCompatibility
-      ? widget.iconTheme
-        ?? appBarTheme.iconTheme
-        ?? theme.primaryIconTheme
-      : widget.iconTheme
-        ?? appBarTheme.iconTheme
-        ?? defaults.iconTheme!.copyWith(color: foregroundColor);
+    IconThemeData overallIconTheme = widget.iconTheme
+      ?? appBarTheme.iconTheme
+      ?? defaults.iconTheme!.copyWith(color: foregroundColor);
 
     final Color? actionForegroundColor = widget.foregroundColor
       ?? appBarTheme.foregroundColor;
@@ -945,21 +867,13 @@
       ?? defaults.actionsIconTheme?.copyWith(color: actionForegroundColor)
       ?? overallIconTheme;
 
-    TextStyle? toolbarTextStyle = backwardsCompatibility
-      ? widget.toolbarTextStyle
-        ?? appBarTheme.toolbarTextStyle
-        ?? theme.primaryTextTheme.bodyMedium
-      : widget.toolbarTextStyle
-        ?? appBarTheme.toolbarTextStyle
-        ?? defaults.toolbarTextStyle?.copyWith(color: foregroundColor);
+    TextStyle? toolbarTextStyle = widget.toolbarTextStyle
+      ?? appBarTheme.toolbarTextStyle
+      ?? defaults.toolbarTextStyle?.copyWith(color: foregroundColor);
 
-    TextStyle? titleTextStyle = backwardsCompatibility
-      ? widget.titleTextStyle
-        ?? appBarTheme.titleTextStyle
-        ?? theme.primaryTextTheme.titleLarge
-      : widget.titleTextStyle
-        ?? appBarTheme.titleTextStyle
-        ?? defaults.titleTextStyle?.copyWith(color: foregroundColor);
+    TextStyle? titleTextStyle = widget.titleTextStyle
+      ?? appBarTheme.titleTextStyle
+      ?? defaults.titleTextStyle?.copyWith(color: foregroundColor);
 
     if (widget.toolbarOpacity != 1.0) {
       final double opacity = const Interval(0.25, 1.0, curve: Curves.fastOutSlowIn).transform(widget.toolbarOpacity);
@@ -1211,21 +1125,15 @@
       );
     }
 
-    final SystemUiOverlayStyle overlayStyle = backwardsCompatibility
-      ? _systemOverlayStyleForBrightness(
-          widget.brightness
-          ?? appBarTheme.brightness
-          ?? ThemeData.estimateBrightnessForColor(backgroundColor),
-        )
-      : widget.systemOverlayStyle
-        ?? appBarTheme.systemOverlayStyle
-        ?? defaults.systemOverlayStyle
-        ?? _systemOverlayStyleForBrightness(
-          ThemeData.estimateBrightnessForColor(backgroundColor),
-          // Make the status bar transparent for M3 so the elevation overlay
-          // color is picked up by the statusbar.
-          theme.useMaterial3 ? const Color(0x00000000) : null,
-        );
+    final SystemUiOverlayStyle overlayStyle = widget.systemOverlayStyle
+      ?? appBarTheme.systemOverlayStyle
+      ?? defaults.systemOverlayStyle
+      ?? _systemOverlayStyleForBrightness(
+        ThemeData.estimateBrightnessForColor(backgroundColor),
+        // Make the status bar transparent for M3 so the elevation overlay
+        // color is picked up by the statusbar.
+        theme.useMaterial3 ? const Color(0x00000000) : null,
+      );
 
     return Semantics(
       container: true,
@@ -1269,7 +1177,6 @@
     required this.forceElevated,
     required this.backgroundColor,
     required this.foregroundColor,
-    required this.brightness,
     required this.iconTheme,
     required this.actionsIconTheme,
     required this.primary,
@@ -1288,7 +1195,6 @@
     required this.shape,
     required this.toolbarHeight,
     required this.leadingWidth,
-    required this.backwardsCompatibility,
     required this.toolbarTextStyle,
     required this.titleTextStyle,
     required this.systemOverlayStyle,
@@ -1309,7 +1215,6 @@
   final bool forceElevated;
   final Color? backgroundColor;
   final Color? foregroundColor;
-  final Brightness? brightness;
   final IconThemeData? iconTheme;
   final IconThemeData? actionsIconTheme;
   final bool primary;
@@ -1324,7 +1229,6 @@
   final ShapeBorder? shape;
   final double? toolbarHeight;
   final double? leadingWidth;
-  final bool? backwardsCompatibility;
   final TextStyle? toolbarTextStyle;
   final TextStyle? titleTextStyle;
   final SystemUiOverlayStyle? systemOverlayStyle;
@@ -1385,7 +1289,6 @@
         surfaceTintColor: surfaceTintColor,
         backgroundColor: backgroundColor,
         foregroundColor: foregroundColor,
-        brightness: brightness,
         iconTheme: iconTheme,
         actionsIconTheme: actionsIconTheme,
         primary: primary,
@@ -1397,7 +1300,6 @@
         bottomOpacity: pinned ? 1.0 : clampDouble(visibleMainHeight / _bottomHeight, 0.0, 1.0),
         toolbarHeight: toolbarHeight,
         leadingWidth: leadingWidth,
-        backwardsCompatibility: backwardsCompatibility,
         toolbarTextStyle: toolbarTextStyle,
         titleTextStyle: titleTextStyle,
         systemOverlayStyle: systemOverlayStyle,
@@ -1420,7 +1322,6 @@
         || shadowColor != oldDelegate.shadowColor
         || backgroundColor != oldDelegate.backgroundColor
         || foregroundColor != oldDelegate.foregroundColor
-        || brightness != oldDelegate.brightness
         || iconTheme != oldDelegate.iconTheme
         || actionsIconTheme != oldDelegate.actionsIconTheme
         || primary != oldDelegate.primary
@@ -1437,7 +1338,6 @@
         || forceElevated != oldDelegate.forceElevated
         || toolbarHeight != oldDelegate.toolbarHeight
         || leadingWidth != oldDelegate.leadingWidth
-        || backwardsCompatibility != oldDelegate.backwardsCompatibility
         || toolbarTextStyle != oldDelegate.toolbarTextStyle
         || titleTextStyle != oldDelegate.titleTextStyle
         || systemOverlayStyle != oldDelegate.systemOverlayStyle
@@ -1555,11 +1455,6 @@
     this.forceElevated = false,
     this.backgroundColor,
     this.foregroundColor,
-    @Deprecated(
-      'This property is no longer used, please use systemOverlayStyle instead. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    this.brightness,
     this.iconTheme,
     this.actionsIconTheme,
     this.primary = true,
@@ -1577,11 +1472,6 @@
     this.shape,
     this.toolbarHeight = kToolbarHeight,
     this.leadingWidth,
-    @Deprecated(
-      'This property is obsolete and is false by default. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    this.backwardsCompatibility,
     this.toolbarTextStyle,
     this.titleTextStyle,
     this.systemOverlayStyle,
@@ -1865,15 +1755,6 @@
   /// This property is used to configure an [AppBar].
   final Color? foregroundColor;
 
-  /// {@macro flutter.material.appbar.brightness}
-  ///
-  /// This property is used to configure an [AppBar].
-  @Deprecated(
-    'This property is no longer used, please use systemOverlayStyle instead. '
-    'This feature was deprecated after v2.4.0-0.0.pre.',
-  )
-  final Brightness? brightness;
-
   /// {@macro flutter.material.appbar.iconTheme}
   ///
   /// This property is used to configure an [AppBar].
@@ -2035,15 +1916,6 @@
   /// This property is used to configure an [AppBar].
   final double? leadingWidth;
 
-  /// {@macro flutter.material.appbar.backwardsCompatibility}
-  ///
-  /// This property is used to configure an [AppBar].
-  @Deprecated(
-    'This property is obsolete and is false by default. '
-    'This feature was deprecated after v2.4.0-0.0.pre.',
-  )
-  final bool? backwardsCompatibility;
-
   /// {@macro flutter.material.appbar.toolbarTextStyle}
   ///
   /// This property is used to configure an [AppBar].
@@ -2149,7 +2021,6 @@
           forceElevated: widget.forceElevated,
           backgroundColor: widget.backgroundColor,
           foregroundColor: widget.foregroundColor,
-          brightness: widget.brightness,
           iconTheme: widget.iconTheme,
           actionsIconTheme: widget.actionsIconTheme,
           primary: widget.primary,
@@ -2167,7 +2038,6 @@
           showOnScreenConfiguration: _showOnScreenConfiguration,
           toolbarHeight: widget.toolbarHeight,
           leadingWidth: widget.leadingWidth,
-          backwardsCompatibility: widget.backwardsCompatibility,
           toolbarTextStyle: widget.toolbarTextStyle,
           titleTextStyle: widget.titleTextStyle,
           systemOverlayStyle: widget.systemOverlayStyle,
diff --git a/framework/lib/src/material/app_bar_theme.dart b/framework/lib/src/material/app_bar_theme.dart
index 0229bcd..dae83c0 100644
--- a/framework/lib/src/material/app_bar_theme.dart
+++ b/framework/lib/src/material/app_bar_theme.dart
@@ -27,11 +27,6 @@
 class AppBarTheme with Diagnosticable {
   /// Creates a theme that can be used for [ThemeData.appBarTheme].
   const AppBarTheme({
-    @Deprecated(
-      'This property is no longer used, please use systemOverlayStyle instead. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    this.brightness,
     Color? color,
     Color? backgroundColor,
     this.foregroundColor,
@@ -48,53 +43,12 @@
     this.toolbarTextStyle,
     this.titleTextStyle,
     this.systemOverlayStyle,
-    @Deprecated(
-      'This property is obsolete and is false by default. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    this.backwardsCompatibility,
   }) : assert(
          color == null || backgroundColor == null,
          'The color and backgroundColor parameters mean the same thing. Only specify one.',
        ),
        backgroundColor = backgroundColor ?? color;
 
-  /// This property is deprecated, please use [systemOverlayStyle] instead.
-  ///
-  /// Overrides the default value of the obsolete [AppBar.brightness]
-  /// property which implicitly defines [AppBar.systemOverlayStyle] in
-  /// all descendant [AppBar] widgets.
-  ///
-  /// See also:
-  ///
-  ///  * [systemOverlayStyle], which overrides the default value of
-  ///    [AppBar.systemOverlayStyle] in all descendant [AppBar] widgets.
-  ///  * [AppBar.backwardsCompatibility], which forces [AppBar] to depend
-  ///    on this obsolete property.
-  @Deprecated(
-    'This property is no longer used, please use systemOverlayStyle instead. '
-    'This feature was deprecated after v2.4.0-0.0.pre.',
-  )
-  final Brightness? brightness;
-
-  /// This property is deprecated, please use [backgroundColor] instead.
-  ///
-  /// Obsolete property that overrides the default value of
-  /// [AppBar.backgroundColor] in all descendant [AppBar] widgets.
-  ///
-  /// See also:
-  ///
-  ///  * [backgroundColor], which serves this same purpose
-  ///    as this property, but has a name that's consistent with
-  ///    [AppBar.backgroundColor].
-  ///  * [AppBar.backwardsCompatibility], which forces [AppBar] to depend
-  ///    on this obsolete property.
-  @Deprecated(
-    'This property is no longer used, please use backgroundColor instead. '
-    'This feature was deprecated after v2.4.0-0.0.pre.',
-  )
-  Color? get color => backgroundColor;
-
   /// Overrides the default value of [AppBar.backgroundColor] in all
   /// descendant [AppBar] widgets.
   ///
@@ -177,9 +131,6 @@
   /// Overrides the default value of the obsolete [AppBar.toolbarTextStyle]
   /// property in all descendant [AppBar] widgets.
   ///
-  /// If this property is specified, then [backwardsCompatibility]
-  /// should be false (the default).
-  ///
   /// See also:
   ///
   ///  * [titleTextStyle], which overrides the default of [AppBar.titleTextStyle]
@@ -189,9 +140,6 @@
   /// Overrides the default value of [AppBar.titleTextStyle]
   /// property in all descendant [AppBar] widgets.
   ///
-  /// If this property is specified, then [backwardsCompatibility]
-  /// should be false (the default).
-  ///
   /// See also:
   ///
   ///  * [toolbarTextStyle], which overrides the default of [AppBar.toolbarTextStyle]
@@ -202,23 +150,10 @@
   /// property in all descendant [AppBar] widgets.
   final SystemUiOverlayStyle? systemOverlayStyle;
 
-  /// Overrides the default value of [AppBar.backwardsCompatibility]
-  /// property in all descendant [AppBar] widgets.
-  @Deprecated(
-    'This property is obsolete and is false by default. '
-    'This feature was deprecated after v2.4.0-0.0.pre.',
-  )
-  final bool? backwardsCompatibility;
-
   /// Creates a copy of this object with the given fields replaced with the
   /// new values.
   AppBarTheme copyWith({
     IconThemeData? actionsIconTheme,
-    @Deprecated(
-      'This property is no longer used, please use systemOverlayStyle instead. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    Brightness? brightness,
     Color? color,
     Color? backgroundColor,
     Color? foregroundColor,
@@ -234,18 +169,12 @@
     TextStyle? toolbarTextStyle,
     TextStyle? titleTextStyle,
     SystemUiOverlayStyle? systemOverlayStyle,
-    @Deprecated(
-      'This property is obsolete and is false by default. '
-      'This feature was deprecated after v2.4.0-0.0.pre.',
-    )
-    bool? backwardsCompatibility,
   }) {
     assert(
       color == null || backgroundColor == null,
       'The color and backgroundColor parameters mean the same thing. Only specify one.',
     );
     return AppBarTheme(
-      brightness: brightness ?? this.brightness,
       backgroundColor: backgroundColor ?? color ?? this.backgroundColor,
       foregroundColor: foregroundColor ?? this.foregroundColor,
       elevation: elevation ?? this.elevation,
@@ -261,7 +190,6 @@
       toolbarTextStyle: toolbarTextStyle ?? this.toolbarTextStyle,
       titleTextStyle: titleTextStyle ?? this.titleTextStyle,
       systemOverlayStyle: systemOverlayStyle ?? this.systemOverlayStyle,
-      backwardsCompatibility: backwardsCompatibility ?? this.backwardsCompatibility,
     );
   }
 
@@ -277,7 +205,6 @@
   /// {@macro dart.ui.shadow.lerp}
   static AppBarTheme lerp(AppBarTheme? a, AppBarTheme? b, double t) {
     return AppBarTheme(
-      brightness: t < 0.5 ? a?.brightness : b?.brightness,
       backgroundColor: Color.lerp(a?.backgroundColor, b?.backgroundColor, t),
       foregroundColor: Color.lerp(a?.foregroundColor, b?.foregroundColor, t),
       elevation: lerpDouble(a?.elevation, b?.elevation, t),
@@ -293,13 +220,11 @@
       toolbarTextStyle: TextStyle.lerp(a?.toolbarTextStyle, b?.toolbarTextStyle, t),
       titleTextStyle: TextStyle.lerp(a?.titleTextStyle, b?.titleTextStyle, t),
       systemOverlayStyle: t < 0.5 ? a?.systemOverlayStyle : b?.systemOverlayStyle,
-      backwardsCompatibility: t < 0.5 ? a?.backwardsCompatibility : b?.backwardsCompatibility,
     );
   }
 
   @override
   int get hashCode => Object.hash(
-    brightness,
     backgroundColor,
     foregroundColor,
     elevation,
@@ -315,7 +240,6 @@
     toolbarTextStyle,
     titleTextStyle,
     systemOverlayStyle,
-    backwardsCompatibility,
   );
 
   @override
@@ -327,7 +251,6 @@
       return false;
     }
     return other is AppBarTheme
-        && other.brightness == brightness
         && other.backgroundColor == backgroundColor
         && other.foregroundColor == foregroundColor
         && other.elevation == elevation
@@ -342,14 +265,12 @@
         && other.toolbarHeight == toolbarHeight
         && other.toolbarTextStyle == toolbarTextStyle
         && other.titleTextStyle == titleTextStyle
-        && other.systemOverlayStyle == systemOverlayStyle
-        && other.backwardsCompatibility == backwardsCompatibility;
+        && other.systemOverlayStyle == systemOverlayStyle;
   }
 
   @override
   void debugFillProperties(DiagnosticPropertiesBuilder properties) {
     super.debugFillProperties(properties);
-    properties.add(DiagnosticsProperty<Brightness>('brightness', brightness, defaultValue: null));
     properties.add(ColorProperty('backgroundColor', backgroundColor, defaultValue: null));
     properties.add(ColorProperty('foregroundColor', foregroundColor, defaultValue: null));
     properties.add(DiagnosticsProperty<double>('elevation', elevation, defaultValue: null));
@@ -364,6 +285,5 @@
     properties.add(DiagnosticsProperty<double>('toolbarHeight', toolbarHeight, defaultValue: null));
     properties.add(DiagnosticsProperty<TextStyle>('toolbarTextStyle', toolbarTextStyle, defaultValue: null));
     properties.add(DiagnosticsProperty<TextStyle>('titleTextStyle', titleTextStyle, defaultValue: null));
-    properties.add(DiagnosticsProperty<bool>('backwardsCompatibility', backwardsCompatibility, defaultValue: null));
   }
 }
diff --git a/framework/lib/src/material/badge.dart b/framework/lib/src/material/badge.dart
index 2d8d65d..837a91f 100644
--- a/framework/lib/src/material/badge.dart
+++ b/framework/lib/src/material/badge.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'package:flute/rendering.dart';
 import 'package:flute/widgets.dart';
 
 import 'badge_theme.dart';
@@ -35,6 +36,7 @@
     this.textStyle,
     this.padding,
     this.alignment,
+    this.offset,
     this.label,
     this.isLabelVisible = true,
     this.child,
@@ -54,6 +56,7 @@
     this.textStyle,
     this.padding,
     this.alignment,
+    this.offset,
     required int count,
     this.isLabelVisible = true,
     this.child,
@@ -106,13 +109,29 @@
   /// left and right if the theme's value is null.
   final EdgeInsetsGeometry? padding;
 
-  /// The location of the [label] relative to the [child].
+  /// Combined with [offset] to determine the location of the [label]
+  /// relative to the [child].
+  ///
+  /// The alignment positions the label in the same way a child of an
+  /// [Align] widget is positioned, except that, the alignment is
+  /// resolved as if the label was a [largeSize] square and [offset]
+  /// is added to the result.
   ///
   /// This value is only used if [label] is non-null.
   ///
-  /// Defaults to the [BadgeTheme]'s alignment, or `start = 12`
-  /// and `top = -4` if the theme's value is null.
-  final AlignmentDirectional? alignment;
+  /// Defaults to the [BadgeTheme]'s alignment, or
+  /// [AlignmentDirectional.topEnd] if the theme's value is null.
+  final AlignmentGeometry? alignment;
+
+  /// Combined with [alignment] to determine the location of the [label]
+  /// relative to the [child].
+  ///
+  /// This value is only used if [label] is non-null.
+  ///
+  /// Defaults to the [BadgeTheme]'s offset, or
+  /// if the theme's value is null then `Offset(4, -4)` for
+  /// [TextDirection.ltr] or `Offset(-4, -4)` for [TextDirection.rtl].
+  final Offset? offset;
 
   /// The badge's content, typically a [Text] widget that contains 1 to 4
   /// characters.
@@ -168,24 +187,99 @@
       return badge;
     }
 
-    final AlignmentDirectional effectiveAlignment = alignment ?? badgeTheme.alignment ?? defaults.alignment!;
+    final AlignmentGeometry effectiveAlignment = alignment ?? badgeTheme.alignment ?? defaults.alignment!;
+    final TextDirection textDirection = Directionality.of(context);
+    final Offset defaultOffset = textDirection == TextDirection.ltr ? const Offset(4, -4) : const Offset(-4, -4);
+    final Offset effectiveOffset = offset ?? badgeTheme.offset ?? defaultOffset;
+
     return
       Stack(
         clipBehavior: Clip.none,
         children: <Widget>[
           child!,
-          Positioned.directional(
-            textDirection: Directionality.of(context),
-            start: label == null ? null : effectiveAlignment.start,
-            end: label == null ? 0 : null,
-            top: label == null ? 0 : effectiveAlignment.y,
-            child: badge,
+          Positioned.fill(
+            child: _Badge(
+              alignment: effectiveAlignment,
+              offset: label == null ? Offset.zero : effectiveOffset,
+              textDirection: textDirection,
+              child: badge,
+            ),
           ),
         ],
       );
   }
 }
 
+class _Badge extends SingleChildRenderObjectWidget {
+  const _Badge({
+    required this.alignment,
+    required this.offset,
+    required this.textDirection,
+    super.child, // the badge
+  });
+
+  final AlignmentGeometry alignment;
+  final Offset offset;
+  final TextDirection textDirection;
+
+  @override
+  _RenderBadge createRenderObject(BuildContext context) {
+    return _RenderBadge(
+      alignment: alignment,
+      offset: offset,
+      textDirection: Directionality.maybeOf(context),
+    );
+  }
+
+  @override
+  void updateRenderObject(BuildContext context, _RenderBadge renderObject) {
+    renderObject
+      ..alignment = alignment
+      ..offset = offset
+      ..textDirection = Directionality.maybeOf(context);
+  }
+
+  @override
+  void debugFillProperties(DiagnosticPropertiesBuilder properties) {
+    super.debugFillProperties(properties);
+    properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment));
+    properties.add(DiagnosticsProperty<Offset>('offset', offset));
+  }
+}
+
+class _RenderBadge extends RenderAligningShiftedBox {
+  _RenderBadge({
+    super.textDirection,
+    super.alignment,
+    required Offset offset,
+  }) : _offset = offset;
+
+  Offset get offset => _offset;
+  Offset _offset;
+  set offset(Offset value) {
+    if (_offset == value) {
+      return;
+    }
+    _offset = value;
+    markNeedsLayout();
+  }
+
+  @override
+  void performLayout() {
+    final BoxConstraints constraints = this.constraints;
+    assert(constraints.hasBoundedWidth);
+    assert(constraints.hasBoundedHeight);
+    size = constraints.biggest;
+
+    child!.layout(const BoxConstraints(), parentUsesSize: true);
+    final double badgeSize = child!.size.height;
+    final Alignment resolvedAlignment = alignment.resolve(textDirection);
+    final BoxParentData childParentData = child!.parentData! as BoxParentData;
+    childParentData.offset = offset + resolvedAlignment.alongOffset(Offset(size.width - badgeSize, size.height - badgeSize));
+  }
+}
+
+
 // BEGIN GENERATED TOKEN PROPERTIES - Badge
 
 // Do not edit by hand. The code between the "BEGIN GENERATED" and
@@ -200,7 +294,7 @@
     smallSize: 6.0,
     largeSize: 16.0,
     padding: const EdgeInsets.symmetric(horizontal: 4),
-    alignment: const AlignmentDirectional(12, -4),
+    alignment: AlignmentDirectional.topEnd,
   );
 
   final BuildContext context;
diff --git a/framework/lib/src/material/badge_theme.dart b/framework/lib/src/material/badge_theme.dart
index 1b0298a..1095100 100644
--- a/framework/lib/src/material/badge_theme.dart
+++ b/framework/lib/src/material/badge_theme.dart
@@ -41,6 +41,7 @@
     this.textStyle,
     this.padding,
     this.alignment,
+    this.offset,
   });
 
   /// Overrides the default value for [Badge.backgroundColor].
@@ -62,7 +63,10 @@
   final EdgeInsetsGeometry? padding;
 
   /// Overrides the default value for [Badge.alignment].
-  final AlignmentDirectional? alignment;
+  final AlignmentGeometry? alignment;
+
+  /// Overrides the default value for [Badge.offset].
+  final Offset? offset;
 
   /// Creates a copy of this object but with the given fields replaced with the
   /// new values.
@@ -73,7 +77,8 @@
     double? largeSize,
     TextStyle? textStyle,
     EdgeInsetsGeometry? padding,
-    AlignmentDirectional? alignment,
+    AlignmentGeometry? alignment,
+    Offset? offset,
   }) {
     return BadgeThemeData(
       backgroundColor: backgroundColor ?? this.backgroundColor,
@@ -83,6 +88,7 @@
       textStyle: textStyle ?? this.textStyle,
       padding: padding ?? this.padding,
       alignment: alignment ?? this.alignment,
+      offset: offset ?? this.offset,
     );
   }
 
@@ -95,7 +101,8 @@
       largeSize: lerpDouble(a?.largeSize, b?.largeSize, t),
       textStyle: TextStyle.lerp(a?.textStyle, b?.textStyle, t),
       padding: EdgeInsetsGeometry.lerp(a?.padding, b?.padding, t),
-      alignment: AlignmentDirectional.lerp(a?.alignment, b?.alignment, t),
+      alignment: AlignmentGeometry.lerp(a?.alignment, b?.alignment, t),
+      offset: Offset.lerp(a?.offset, b?.offset, t),
     );
   }
 
@@ -108,6 +115,7 @@
     textStyle,
     padding,
     alignment,
+    offset,
   );
 
   @override
@@ -125,7 +133,8 @@
       && other.largeSize == largeSize
       && other.textStyle == textStyle
       && other.padding == padding
-      && other.alignment == alignment;
+      && other.alignment == alignment
+      && other.offset == offset;
   }
 
   @override
@@ -137,7 +146,8 @@
     properties.add(DoubleProperty('largeSize', largeSize, defaultValue: null));
     properties.add(DiagnosticsProperty<TextStyle>('textStyle', textStyle, defaultValue: null));
     properties.add(DiagnosticsProperty<EdgeInsetsGeometry>('padding', padding, defaultValue: null));
-    properties.add(DiagnosticsProperty<AlignmentDirectional>('alignment', alignment, defaultValue: null));
+    properties.add(DiagnosticsProperty<AlignmentGeometry>('alignment', alignment, defaultValue: null));
+    properties.add(DiagnosticsProperty<Offset>('offset', offset, defaultValue: null));
   }
 }
 
diff --git a/framework/lib/src/material/checkbox.dart b/framework/lib/src/material/checkbox.dart
index d4e8346..39b8846 100644
--- a/framework/lib/src/material/checkbox.dart
+++ b/framework/lib/src/material/checkbox.dart
@@ -254,10 +254,12 @@
   /// [ThemeData.focusColor] is used.
   final Color? focusColor;
 
+  /// {@template flutter.material.checkbox.hoverColor}
   /// The color for the checkbox's [Material] when a pointer is hovering over it.
   ///
   /// If [overlayColor] returns a non-null color in the [MaterialState.hovered]
   /// state, it will be used instead.
+  /// {@endtemplate}
   ///
   /// If null, then the value of [CheckboxThemeData.overlayColor] is used in the
   /// hovered state. If that is also null, then the value of
@@ -332,10 +334,12 @@
   /// will be width 2.
   final BorderSide? side;
 
+  /// {@template flutter.material.checkbox.isError}
   /// True if this checkbox wants to show an error state.
   ///
   /// The checkbox will have different default container color and check color when
   /// this is true. This is only used when [ThemeData.useMaterial3] is set to true.
+  /// {@endtemplate}
   ///
   /// Must not be null. Defaults to false.
   final bool isError;
diff --git a/framework/lib/src/material/checkbox_list_tile.dart b/framework/lib/src/material/checkbox_list_tile.dart
index 97f25c7..a7f046a 100644
--- a/framework/lib/src/material/checkbox_list_tile.dart
+++ b/framework/lib/src/material/checkbox_list_tile.dart
@@ -163,8 +163,20 @@
     super.key,
     required this.value,
     required this.onChanged,
+    this.mouseCursor,
     this.activeColor,
+    this.fillColor,
     this.checkColor,
+    this.hoverColor,
+    this.overlayColor,
+    this.splashRadius,
+    this.materialTapTargetSize,
+    this.visualDensity,
+    this.focusNode,
+    this.autofocus = false,
+    this.shape,
+    this.side,
+    this.isError = false,
     this.enabled,
     this.tileColor,
     this.title,
@@ -174,15 +186,10 @@
     this.secondary,
     this.selected = false,
     this.controlAffinity = ListTileControlAffinity.platform,
-    this.autofocus = false,
     this.contentPadding,
     this.tristate = false,
-    this.shape,
     this.checkboxShape,
     this.selectedTileColor,
-    this.side,
-    this.visualDensity,
-    this.focusNode,
     this.onFocusChange,
     this.enableFeedback,
   }) : assert(tristate || value != null),
@@ -219,16 +226,98 @@
   /// {@end-tool}
   final ValueChanged<bool?>? onChanged;
 
+  /// The cursor for a mouse pointer when it enters or is hovering over the
+  /// widget.
+  ///
+  /// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
+  /// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
+  ///
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [CheckboxThemeData.mouseCursor] is used. If
+  /// that is also null, then [MaterialStateMouseCursor.clickable] is used.
+  final MouseCursor? mouseCursor;
+
   /// The color to use when this checkbox is checked.
   ///
   /// Defaults to [ColorScheme.secondary] of the current [Theme].
   final Color? activeColor;
 
+  /// The color that fills the checkbox.
+  ///
+  /// Resolves in the following states:
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [activeColor] is used in the selected
+  /// state. If that is also null, the value of [CheckboxThemeData.fillColor]
+  /// is used. If that is also null, then the default value is used.
+  final MaterialStateProperty<Color?>? fillColor;
+
   /// The color to use for the check icon when this checkbox is checked.
   ///
   /// Defaults to Color(0xFFFFFFFF).
   final Color? checkColor;
 
+  /// {@macro flutter.material.checkbox.hoverColor}
+  final Color? hoverColor;
+
+  /// The color for the checkbox's [Material].
+  ///
+  /// Resolves in the following states:
+  ///  * [MaterialState.pressed].
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///
+  /// If null, then the value of [activeColor] with alpha [kRadialReactionAlpha]
+  /// and [hoverColor] is used in the pressed and hovered state. If that is also null,
+  /// the value of [CheckboxThemeData.overlayColor] is used. If that is also null,
+  /// then the the default value is used in the pressed and hovered state.
+  final MaterialStateProperty<Color?>? overlayColor;
+
+  /// {@macro flutter.material.checkbox.splashRadius}
+  ///
+  /// If null, then the value of [CheckboxThemeData.splashRadius] is used. If
+  /// that is also null, then [kRadialReactionRadius] is used.
+  final double? splashRadius;
+
+  /// {@macro flutter.material.checkbox.materialTapTargetSize}
+  ///
+  /// Defaults to [MaterialTapTargetSize.shrinkWrap].
+  final MaterialTapTargetSize? materialTapTargetSize;
+
+  /// Defines how compact the list tile's layout will be.
+  ///
+  /// {@macro flutter.material.themedata.visualDensity}
+  final VisualDensity? visualDensity;
+
+
+  /// {@macro flutter.widgets.Focus.focusNode}
+  final FocusNode? focusNode;
+
+  /// {@macro flutter.widgets.Focus.autofocus}
+  final bool autofocus;
+
+  /// {@macro flutter.material.ListTile.shape}
+  final ShapeBorder? shape;
+
+  /// {@macro flutter.material.checkbox.side}
+  ///
+  /// The given value is passed directly to [Checkbox.side].
+  ///
+  /// If this property is null, then [CheckboxThemeData.side] of
+  /// [ThemeData.checkboxTheme] is used. If that is also null, then the side
+  /// will be width 2.
+  final BorderSide? side;
+
+  /// {@macro flutter.material.checkbox.isError}
+  ///
+  /// Defaults to false.
+  final bool isError;
+
   /// {@macro flutter.material.ListTile.tileColor}
   final Color? tileColor;
 
@@ -270,9 +359,6 @@
   /// Where to place the control relative to the text.
   final ListTileControlAffinity controlAffinity;
 
-  /// {@macro flutter.widgets.Focus.autofocus}
-  final bool autofocus;
-
   /// Defines insets surrounding the tile's contents.
   ///
   /// This value will surround the [Checkbox], [title], [subtitle], and [secondary]
@@ -293,9 +379,6 @@
   /// If tristate is false (the default), [value] must not be null.
   final bool tristate;
 
-  /// {@macro flutter.material.ListTile.shape}
-  final ShapeBorder? shape;
-
   /// {@macro flutter.material.checkbox.shape}
   ///
   /// If this property is null then [CheckboxThemeData.shape] of [ThemeData.checkboxTheme]
@@ -306,23 +389,6 @@
   /// If non-null, defines the background color when [CheckboxListTile.selected] is true.
   final Color? selectedTileColor;
 
-  /// {@macro flutter.material.checkbox.side}
-  ///
-  /// The given value is passed directly to [Checkbox.side].
-  ///
-  /// If this property is null, then [CheckboxThemeData.side] of
-  /// [ThemeData.checkboxTheme] is used. If that is also null, then the side
-  /// will be width 2.
-  final BorderSide? side;
-
-  /// Defines how compact the list tile's layout will be.
-  ///
-  /// {@macro flutter.material.themedata.visualDensity}
-  final VisualDensity? visualDensity;
-
-  /// {@macro flutter.widgets.Focus.focusNode}
-  final FocusNode? focusNode;
-
   /// {@macro flutter.material.inkwell.onFocusChange}
   final ValueChanged<bool>? onFocusChange;
 
@@ -359,14 +425,20 @@
   Widget build(BuildContext context) {
     final Widget control = Checkbox(
       value: value,
-      onChanged: enabled ?? true ? onChanged : null ,
+      onChanged: enabled ?? true ? onChanged : null,
+      mouseCursor: mouseCursor,
       activeColor: activeColor,
+      fillColor: fillColor,
       checkColor: checkColor,
-      materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+      hoverColor: hoverColor,
+      overlayColor: overlayColor,
+      splashRadius: splashRadius,
+      materialTapTargetSize: materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap,
       autofocus: autofocus,
       tristate: tristate,
       shape: checkboxShape,
       side: side,
+      isError: isError,
     );
     Widget? leading, trailing;
     switch (controlAffinity) {
diff --git a/framework/lib/src/material/expansion_tile.dart b/framework/lib/src/material/expansion_tile.dart
index 855b9ce..0ec82f8 100644
--- a/framework/lib/src/material/expansion_tile.dart
+++ b/framework/lib/src/material/expansion_tile.dart
@@ -34,8 +34,7 @@
 /// to the [leading] and [trailing] properties of [ExpansionTile].
 ///
 /// {@tool dartpad}
-/// This example demonstrates how the [ExpansionTile] icon's location and appearance
-/// can be customized.
+/// This example demonstrates different configurations of ExpansionTile.
 ///
 /// ** See code in examples/api/lib/material/expansion_tile/expansion_tile.0.dart **
 /// {@end-tool}
@@ -217,7 +216,7 @@
   /// Used to override to the [ListTileThemeData.iconColor].
   ///
   /// If this property is null then [ExpansionTileThemeData.iconColor] is used. If that
-  /// is also null then the value of [ColorScheme.primary] is used.
+  /// is also null then the value of [ListTileThemeData.iconColor] is used.
   ///
   /// See also:
   ///
@@ -228,15 +227,6 @@
   /// The icon color of tile's expansion arrow icon when the sublist is collapsed.
   ///
   /// Used to override to the [ListTileThemeData.iconColor].
-  ///
-  /// If this property is null then [ExpansionTileThemeData.collapsedIconColor] is used. If that
-  /// is also null and [ThemeData.useMaterial3] is true, [ColorScheme.onSurface] is used. Otherwise,
-  /// defaults to [ThemeData.unselectedWidgetColor] color.
-  ///
-  /// See also:
-  ///
-  /// * [ExpansionTileTheme.of], which returns the nearest [ExpansionTileTheme]'s
-  ///   [ExpansionTileThemeData].
   final Color? collapsedIconColor;
 
 
@@ -245,8 +235,7 @@
   /// Used to override to the [ListTileThemeData.textColor].
   ///
   /// If this property is null then [ExpansionTileThemeData.textColor] is used. If that
-  /// is also null then and [ThemeData.useMaterial3] is true, color of the [TextTheme.bodyLarge]
-  /// will be used for the [title] and [subtitle]. Otherwise, defaults to [ColorScheme.primary] color.
+  /// is also null then the value of [ListTileThemeData.textColor] is used.
   ///
   /// See also:
   ///
@@ -258,10 +247,8 @@
   ///
   /// Used to override to the [ListTileThemeData.textColor].
   ///
-  /// If this property is null then [ExpansionTileThemeData.collapsedTextColor] is used.
-  /// If that is also null and [ThemeData.useMaterial3] is true, color of the
-  /// [TextTheme.bodyLarge] will be used for the [title] and [subtitle]. Otherwise,
-  /// defaults to color of the [TextTheme.titleMedium].
+  /// If this property is null then [ExpansionTileThemeData.collapsedTextColor] is used. If that
+  /// is also null then the value of [ListTileThemeData.textColor] is used.
   ///
   /// See also:
   ///
@@ -454,9 +441,7 @@
   void didChangeDependencies() {
     final ThemeData theme = Theme.of(context);
     final ExpansionTileThemeData expansionTileTheme = ExpansionTileTheme.of(context);
-    final ExpansionTileThemeData defaults = theme.useMaterial3
-      ? _ExpansionTileDefaultsM3(context)
-      : _ExpansionTileDefaultsM2(context);
+    final ColorScheme colorScheme = theme.colorScheme;
     _borderTween
       ..begin = widget.collapsedShape
         ?? expansionTileTheme.collapsedShape
@@ -473,13 +458,13 @@
     _headerColorTween
       ..begin = widget.collapsedTextColor
         ?? expansionTileTheme.collapsedTextColor
-        ?? defaults.collapsedTextColor
-      ..end = widget.textColor ?? expansionTileTheme.textColor ?? defaults.textColor;
+        ?? theme.textTheme.titleMedium!.color
+      ..end = widget.textColor ?? expansionTileTheme.textColor ?? colorScheme.primary;
     _iconColorTween
       ..begin = widget.collapsedIconColor
         ?? expansionTileTheme.collapsedIconColor
-        ?? defaults.collapsedIconColor
-      ..end = widget.iconColor ?? expansionTileTheme.iconColor ?? defaults.iconColor;
+        ?? theme.unselectedWidgetColor
+      ..end = widget.iconColor ?? expansionTileTheme.iconColor ?? colorScheme.primary;
     _backgroundColorTween
       ..begin = widget.collapsedBackgroundColor ?? expansionTileTheme.collapsedBackgroundColor
       ..end = widget.backgroundColor ?? expansionTileTheme.backgroundColor;
@@ -513,54 +498,3 @@
     );
   }
 }
-
-class _ExpansionTileDefaultsM2 extends ExpansionTileThemeData {
-  _ExpansionTileDefaultsM2(this.context);
-
-  final BuildContext context;
-  late final ThemeData _theme = Theme.of(context);
-  late final ColorScheme _colorScheme = _theme.colorScheme;
-
-  @override
-  Color? get textColor => _colorScheme.primary;
-
-  @override
-  Color? get iconColor => _colorScheme.primary;
-
-  @override
-  Color? get collapsedTextColor => _theme.textTheme.titleMedium!.color;
-
-  @override
-  Color? get collapsedIconColor => _theme.unselectedWidgetColor;
-}
-
-// BEGIN GENERATED TOKEN PROPERTIES - ExpansionTile
-
-// Do not edit by hand. The code between the "BEGIN GENERATED" and
-// "END GENERATED" comments are generated from data in the Material
-// Design token database by the script:
-//   dev/tools/gen_defaults/bin/gen_defaults.dart.
-
-// Token database version: v0_152
-
-class _ExpansionTileDefaultsM3 extends ExpansionTileThemeData {
-  _ExpansionTileDefaultsM3(this.context);
-
-  final BuildContext context;
-  late final ThemeData _theme = Theme.of(context);
-  late final ColorScheme _colors = _theme.colorScheme;
-
-  @override
-  Color? get textColor => Theme.of(context).textTheme.bodyLarge!.color;
-
-  @override
-  Color? get iconColor => _colors.primary;
-
-  @override
-  Color? get collapsedTextColor => Theme.of(context).textTheme.bodyLarge!.color;
-
-  @override
-  Color? get collapsedIconColor => _colors.onSurface;
-}
-
-// END GENERATED TOKEN PROPERTIES - ExpansionTile
diff --git a/framework/lib/src/material/input_chip.dart b/framework/lib/src/material/input_chip.dart
index ac5c40d..0e64b35 100644
--- a/framework/lib/src/material/input_chip.dart
+++ b/framework/lib/src/material/input_chip.dart
@@ -194,7 +194,7 @@
   Widget build(BuildContext context) {
     assert(debugCheckHasMaterial(context));
     final ChipThemeData? defaults = Theme.of(context).useMaterial3
-      ? _InputChipDefaultsM3(context, isEnabled)
+      ? _InputChipDefaultsM3(context, isEnabled, selected)
       : null;
     final Widget? resolvedDeleteIcon = deleteIcon
       ?? (Theme.of(context).useMaterial3 ? const Icon(Icons.clear, size: 18) : null);
@@ -247,7 +247,7 @@
 // Token database version: v0_158
 
 class _InputChipDefaultsM3 extends ChipThemeData {
-  const _InputChipDefaultsM3(this.context, this.isEnabled)
+  const _InputChipDefaultsM3(this.context, this.isEnabled, this.isSelected)
     : super(
         elevation: 0.0,
         shape: const RoundedRectangleBorder(borderRadius: BorderRadius.all(Radius.circular(8.0))),
@@ -256,6 +256,7 @@
 
   final BuildContext context;
   final bool isEnabled;
+  final bool isSelected;
 
   @override
   TextStyle? get labelStyle => Theme.of(context).textTheme.labelLarge;
@@ -270,7 +271,9 @@
   Color? get surfaceTintColor => Colors.transparent;
 
   @override
-  Color? get selectedColor => Theme.of(context).colorScheme.secondaryContainer;
+  Color? get selectedColor => isEnabled
+    ? Theme.of(context).colorScheme.secondaryContainer
+    : Theme.of(context).colorScheme.onSurface.withOpacity(0.12);
 
   @override
   Color? get checkmarkColor => null;
@@ -282,9 +285,11 @@
   Color? get deleteIconColor => Theme.of(context).colorScheme.onSecondaryContainer;
 
   @override
-  BorderSide? get side => isEnabled
-    ? BorderSide(color: Theme.of(context).colorScheme.outline)
-    : BorderSide(color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12));
+  BorderSide? get side => !isSelected
+    ? isEnabled
+      ? BorderSide(color: Theme.of(context).colorScheme.outline)
+      : BorderSide(color: Theme.of(context).colorScheme.onSurface.withOpacity(0.12))
+    : const BorderSide(color: Colors.transparent);
 
   @override
   IconThemeData? get iconTheme => IconThemeData(
diff --git a/framework/lib/src/material/list_tile.dart b/framework/lib/src/material/list_tile.dart
index c8af8a0..7fa0ea3 100644
--- a/framework/lib/src/material/list_tile.dart
+++ b/framework/lib/src/material/list_tile.dart
@@ -63,6 +63,49 @@
   platform,
 }
 
+/// Defines how [ListTile.leading] and [ListTile.trailing] are
+/// vertically aligned relative to the [ListTile]'s titles
+/// ([ListTile.title] and [ListTile.subtitle]).
+///
+/// See also:
+///
+///  * [ListTile.titleAlignment], to configure the title alignment for an
+///    individual [ListTile].
+///  * [ListTileThemeData.titleAlignment], to configure the title alignment
+///    for all of the [ListTile]s under a [ListTileTheme].
+///  * [ThemeData.listTileTheme], to configure the [ListTileTheme]
+///    for an entire app.
+enum ListTileTitleAlignment {
+  /// The top of the [ListTile.leading] and [ListTile.trailing] widgets are
+  /// placed [ListTile.minVerticalPadding] below the top of the [ListTile.title]
+  /// if [ListTile.isThreeLine] is true, otherwise they're centered relative
+  /// to the [ListTile.title] and [ListTile.subtitle] widgets.
+  ///
+  /// This is the default when [ThemeData.useMaterial3] is true.
+  threeLine,
+
+  /// The tops of the [ListTile.leading] and [ListTile.trailing] widgets are
+  /// placed 16 units below the top of the [ListTile.title]
+  /// if the titles' overall height is greater than 72, otherwise they're
+  /// centered relative to the [ListTile.title] and [ListTile.subtitle] widgets.
+  ///
+  /// This is the default when [ThemeData.useMaterial3] is false.
+  titleHeight,
+
+  /// The tops of the [ListTile.leading] and [ListTile.trailing] widgets are
+  /// placed [ListTile.minVerticalPadding] below the top of the [ListTile.title].
+  top,
+
+  /// The [ListTile.leading] and [ListTile.trailing] widgets are
+  /// centered relative to the [ListTile]'s titles.
+  center,
+
+  /// The bottoms of the [ListTile.leading] and [ListTile.trailing] widgets are
+  /// placed [ListTile.minVerticalPadding] above the bottom of the [ListTile]'s
+  /// titles.
+  bottom,
+}
+
 /// A single fixed-height row that typically contains some text as well as
 /// a leading or trailing icon.
 ///
@@ -156,6 +199,14 @@
 /// ** See code in examples/api/lib/material/list_tile/list_tile.3.dart **
 /// {@end-tool}
 ///
+/// {@tool dartpad}
+/// This sample shows [ListTile.titleAlignment] can be used to configure the
+/// [leading] and [trailing] widgets alignment relative to the [title] and
+/// [subtitle] widgets.
+///
+/// ** See code in examples/api/lib/material/list_tile/list_tile.4.dart **
+/// {@end-tool}
+///
 /// {@tool snippet}
 /// To use a [ListTile] within a [Row], it needs to be wrapped in an
 /// [Expanded] widget. [ListTile] requires fixed width constraints,
@@ -317,6 +368,7 @@
     this.horizontalTitleGap,
     this.minVerticalPadding,
     this.minLeadingWidth,
+    this.titleAlignment,
   }) : assert(!isThreeLine || subtitle != null);
 
   /// A widget to display before the title.
@@ -422,7 +474,7 @@
   /// Defines the default color for [leading] and [trailing] icons.
   ///
   /// If this property is null and [selected] is false then [ListTileThemeData.iconColor]
-  /// is used. If that is also null and [ThemeData.useMaterial3] is true, [ColorScheme.onSurface]
+  /// is used. If that is also null and [ThemeData.useMaterial3] is true, [ColorScheme.onSurfaceVariant]
   /// is used, otherwise if [ThemeData.brightness] is [Brightness.light], [Colors.black54] is used,
   /// and if [ThemeData.brightness] is [Brightness.dark], the value is null.
   ///
@@ -616,6 +668,20 @@
   /// that is also null, then a default value of 40 is used.
   final double? minLeadingWidth;
 
+  /// Defines how [ListTile.leading] and [ListTile.trailing] are
+  /// vertically aligned relative to the [ListTile]'s titles
+  /// ([ListTile.title] and [ListTile.subtitle]).
+  ///
+  /// If this property is null then [ListTileThemeData.titleAlignment]
+  /// is used. If that is also null then [ListTileTitleAlignment.threeLine]
+  /// is used.
+  ///
+  /// See also:
+  ///
+  /// * [ListTileTheme.of], which returns the nearest [ListTileTheme]'s
+  ///   [ListTileThemeData].
+  final ListTileTitleAlignment? titleAlignment;
+
   /// Add a one pixel border in between each tile. If color isn't specified the
   /// [ThemeData.dividerColor] of the context's [Theme] is used.
   ///
@@ -761,6 +827,7 @@
     final EdgeInsets resolvedContentPadding = contentPadding?.resolve(textDirection)
       ?? tileTheme.contentPadding?.resolve(textDirection)
       ?? defaults.contentPadding!.resolve(textDirection);
+
     // Show basic cursor when ListTile isn't enabled or gesture callbacks are null.
     final Set<MaterialState> mouseStates = <MaterialState>{
       if (!enabled || (onTap == null && onLongPress == null)) MaterialState.disabled,
@@ -769,6 +836,10 @@
       ?? tileTheme.mouseCursor?.resolve(mouseStates)
       ?? MaterialStateMouseCursor.clickable.resolve(mouseStates);
 
+    final ListTileTitleAlignment effectiveTitleAlignment = titleAlignment
+      ?? tileTheme.titleAlignment
+      ?? (theme.useMaterial3 ? ListTileTitleAlignment.threeLine : ListTileTitleAlignment.titleHeight);
+
     return InkWell(
       customBorder: shape ?? tileTheme.shape,
       onTap: enabled ? onTap : null,
@@ -812,7 +883,7 @@
                   horizontalTitleGap: horizontalTitleGap ?? tileTheme.horizontalTitleGap ?? 16,
                   minVerticalPadding: minVerticalPadding ?? tileTheme.minVerticalPadding ?? defaults.minVerticalPadding!,
                   minLeadingWidth: minLeadingWidth ?? tileTheme.minLeadingWidth ?? defaults.minLeadingWidth!,
-                  material3: theme.useMaterial3,
+                  titleAlignment: effectiveTitleAlignment,
                 ),
               ),
             ),
@@ -856,6 +927,7 @@
     properties.add(DoubleProperty('horizontalTitleGap', horizontalTitleGap, defaultValue: null));
     properties.add(DoubleProperty('minVerticalPadding', minVerticalPadding, defaultValue: null));
     properties.add(DoubleProperty('minLeadingWidth', minLeadingWidth, defaultValue: null));
+    properties.add(DiagnosticsProperty<ListTileTitleAlignment>('titleAlignment', titleAlignment, defaultValue: null));
   }
 }
 
@@ -910,7 +982,7 @@
     required this.minVerticalPadding,
     required this.minLeadingWidth,
     this.subtitleBaselineType,
-    required this.material3,
+    required this.titleAlignment,
   });
 
   final Widget? leading;
@@ -926,7 +998,7 @@
   final double horizontalTitleGap;
   final double minVerticalPadding;
   final double minLeadingWidth;
-  final bool material3;
+  final ListTileTitleAlignment titleAlignment;
 
   @override
   Iterable<_ListTileSlot> get slots => _ListTileSlot.values;
@@ -957,7 +1029,7 @@
       horizontalTitleGap: horizontalTitleGap,
       minVerticalPadding: minVerticalPadding,
       minLeadingWidth: minLeadingWidth,
-      material3: material3,
+      titleAlignment: titleAlignment,
     );
   }
 
@@ -973,7 +1045,7 @@
       ..horizontalTitleGap = horizontalTitleGap
       ..minLeadingWidth = minLeadingWidth
       ..minVerticalPadding = minVerticalPadding
-      ..material3 = material3;
+      ..titleAlignment = titleAlignment;
   }
 }
 
@@ -988,7 +1060,7 @@
     required double horizontalTitleGap,
     required double minVerticalPadding,
     required double minLeadingWidth,
-    required bool material3,
+    required ListTileTitleAlignment titleAlignment,
   }) : _isDense = isDense,
        _visualDensity = visualDensity,
        _isThreeLine = isThreeLine,
@@ -998,7 +1070,7 @@
        _horizontalTitleGap = horizontalTitleGap,
        _minVerticalPadding = minVerticalPadding,
        _minLeadingWidth = minLeadingWidth,
-       _material3 = material3;
+       _titleAlignment = titleAlignment;
 
   RenderBox? get leading => childForSlot(_ListTileSlot.leading);
   RenderBox? get title => childForSlot(_ListTileSlot.title);
@@ -1114,13 +1186,13 @@
     markNeedsLayout();
   }
 
-  bool get material3 => _material3;
-  bool _material3;
-  set material3(bool value) {
-    if (_material3 == value) {
+  ListTileTitleAlignment get titleAlignment => _titleAlignment;
+  ListTileTitleAlignment _titleAlignment;
+  set titleAlignment(ListTileTitleAlignment value) {
+    if (_titleAlignment == value) {
       return;
     }
-    _material3 = value;
+    _titleAlignment = value;
     markNeedsLayout();
   }
 
@@ -1314,30 +1386,51 @@
 
     final double leadingY;
     final double trailingY;
-    if (material3) {
-      if (isThreeLine) {
+
+    switch (titleAlignment) {
+      case ListTileTitleAlignment.threeLine: {
+        if (isThreeLine) {
+          leadingY = _minVerticalPadding;
+          trailingY = _minVerticalPadding;
+        } else {
+          leadingY = (tileHeight - leadingSize.height) / 2.0;
+          trailingY = (tileHeight - trailingSize.height) / 2.0;
+        }
+        break;
+      }
+      case ListTileTitleAlignment.titleHeight: {
+        // This attempts to implement the redlines for the vertical position of the
+        // leading and trailing icons on the spec page:
+        //   https://m2.material.io/components/lists#specs
+        // The interpretation for these redlines is as follows:
+        //  - For large tiles (> 72dp), both leading and trailing controls should be
+        //    a fixed distance from top. As per guidelines this is set to 16dp.
+        //  - For smaller tiles, trailing should always be centered. Leading can be
+        //    centered or closer to the top. It should never be further than 16dp
+        //    to the top.
+        if (tileHeight > 72.0) {
+          leadingY = 16.0;
+          trailingY = 16.0;
+        } else {
+          leadingY = math.min((tileHeight - leadingSize.height) / 2.0, 16.0);
+          trailingY = (tileHeight - trailingSize.height) / 2.0;
+        }
+        break;
+      }
+      case ListTileTitleAlignment.top: {
         leadingY = _minVerticalPadding;
         trailingY = _minVerticalPadding;
-      } else {
+        break;
+      }
+      case ListTileTitleAlignment.center: {
         leadingY = (tileHeight - leadingSize.height) / 2.0;
         trailingY = (tileHeight - trailingSize.height) / 2.0;
+        break;
       }
-    } else {
-      // This attempts to implement the redlines for the vertical position of the
-      // leading and trailing icons on the spec page:
-      //   https://material.io/design/components/lists.html#specs
-      // The interpretation for these redlines is as follows:
-      //  - For large tiles (> 72dp), both leading and trailing controls should be
-      //    a fixed distance from top. As per guidelines this is set to 16dp.
-      //  - For smaller tiles, trailing should always be centered. Leading can be
-      //    centered or closer to the top. It should never be further than 16dp
-      //    to the top.
-      if (tileHeight > 72.0) {
-        leadingY = 16.0;
-        trailingY = 16.0;
-      } else {
-        leadingY = math.min((tileHeight - leadingSize.height) / 2.0, 16.0);
-        trailingY = (tileHeight - trailingSize.height) / 2.0;
+      case ListTileTitleAlignment.bottom: {
+        leadingY = tileHeight - leadingSize.height - _minVerticalPadding;
+        trailingY = tileHeight - trailingSize.height - _minVerticalPadding;
+        break;
       }
     }
 
@@ -1500,7 +1593,7 @@
   Color? get selectedColor => _colors.primary;
 
   @override
-  Color? get iconColor => _colors.onSurface;
+  Color? get iconColor => _colors.onSurfaceVariant;
 }
 
 // END GENERATED TOKEN PROPERTIES - LisTile
diff --git a/framework/lib/src/material/list_tile_theme.dart b/framework/lib/src/material/list_tile_theme.dart
index 9f3aee6..9be598a 100644
--- a/framework/lib/src/material/list_tile_theme.dart
+++ b/framework/lib/src/material/list_tile_theme.dart
@@ -63,6 +63,7 @@
     this.enableFeedback,
     this.mouseCursor,
     this.visualDensity,
+    this.titleAlignment,
   });
 
   /// Overrides the default value of [ListTile.dense].
@@ -119,6 +120,9 @@
   /// If specified, overrides the default value of [ListTile.visualDensity].
   final VisualDensity? visualDensity;
 
+  /// If specified, overrides the default value of [ListTile.titleAlignment].
+  final ListTileTitleAlignment? titleAlignment;
+
   /// Creates a copy of this object with the given fields replaced with the
   /// new values.
   ListTileThemeData copyWith({
@@ -141,6 +145,7 @@
     MaterialStateProperty<MouseCursor?>? mouseCursor,
     bool? isThreeLine,
     VisualDensity? visualDensity,
+    ListTileTitleAlignment? titleAlignment,
   }) {
     return ListTileThemeData(
       dense: dense ?? this.dense,
@@ -161,6 +166,7 @@
       enableFeedback: enableFeedback ?? this.enableFeedback,
       mouseCursor: mouseCursor ?? this.mouseCursor,
       visualDensity: visualDensity ?? this.visualDensity,
+      titleAlignment: titleAlignment ?? this.titleAlignment,
     );
   }
 
@@ -188,6 +194,7 @@
       enableFeedback: t < 0.5 ? a?.enableFeedback : b?.enableFeedback,
       mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
       visualDensity: t < 0.5 ? a?.visualDensity : b?.visualDensity,
+      titleAlignment: t < 0.5 ? a?.titleAlignment : b?.titleAlignment,
     );
   }
 
@@ -211,6 +218,7 @@
     enableFeedback,
     mouseCursor,
     visualDensity,
+    titleAlignment,
   );
 
   @override
@@ -239,7 +247,8 @@
       && other.minLeadingWidth == minLeadingWidth
       && other.enableFeedback == enableFeedback
       && other.mouseCursor == mouseCursor
-      && other.visualDensity == visualDensity;
+      && other.visualDensity == visualDensity
+      && other.titleAlignment == titleAlignment;
   }
 
   @override
@@ -263,6 +272,7 @@
     properties.add(DiagnosticsProperty<bool>('enableFeedback', enableFeedback, defaultValue: null));
     properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: null));
     properties.add(DiagnosticsProperty<VisualDensity>('visualDensity', visualDensity, defaultValue: null));
+    properties.add(DiagnosticsProperty<ListTileTitleAlignment>('titleAlignment', titleAlignment, defaultValue: null));
   }
 }
 
@@ -477,6 +487,7 @@
     double? horizontalTitleGap,
     double? minVerticalPadding,
     double? minLeadingWidth,
+    ListTileTitleAlignment? titleAlignment,
     required Widget child,
   }) {
     return Builder(
@@ -498,6 +509,7 @@
             horizontalTitleGap: horizontalTitleGap ?? parent.horizontalTitleGap,
             minVerticalPadding: minVerticalPadding ?? parent.minVerticalPadding,
             minLeadingWidth: minLeadingWidth ?? parent.minLeadingWidth,
+            titleAlignment: titleAlignment ?? parent.titleAlignment,
           ),
           child: child,
         );
diff --git a/framework/lib/src/material/material_state.dart b/framework/lib/src/material/material_state.dart
index 16357a0..de9ab14 100644
--- a/framework/lib/src/material/material_state.dart
+++ b/framework/lib/src/material/material_state.dart
@@ -632,7 +632,6 @@
 ///
 /// {@macro flutter.material.MaterialStateProperty.implementations}
 abstract class MaterialStateProperty<T> {
-
   /// Returns a value of type `T` that depends on [states].
   ///
   /// Widgets like [TextButton] and [ElevatedButton] apply this method to their
diff --git a/framework/lib/src/material/navigation_rail_theme.dart b/framework/lib/src/material/navigation_rail_theme.dart
index 72780de..2253054 100644
--- a/framework/lib/src/material/navigation_rail_theme.dart
+++ b/framework/lib/src/material/navigation_rail_theme.dart
@@ -151,8 +151,10 @@
       elevation: lerpDouble(a?.elevation, b?.elevation, t),
       unselectedLabelTextStyle: TextStyle.lerp(a?.unselectedLabelTextStyle, b?.unselectedLabelTextStyle, t),
       selectedLabelTextStyle: TextStyle.lerp(a?.selectedLabelTextStyle, b?.selectedLabelTextStyle, t),
-      unselectedIconTheme: IconThemeData.lerp(a?.unselectedIconTheme, b?.unselectedIconTheme, t),
-      selectedIconTheme: IconThemeData.lerp(a?.selectedIconTheme, b?.selectedIconTheme, t),
+      unselectedIconTheme: a?.unselectedIconTheme == null && b?.unselectedIconTheme == null
+        ? null : IconThemeData.lerp(a?.unselectedIconTheme, b?.unselectedIconTheme, t),
+      selectedIconTheme: a?.selectedIconTheme == null && b?.selectedIconTheme == null
+        ? null : IconThemeData.lerp(a?.selectedIconTheme, b?.selectedIconTheme, t),
       groupAlignment: lerpDouble(a?.groupAlignment, b?.groupAlignment, t),
       labelType: t < 0.5 ? a?.labelType : b?.labelType,
       useIndicator: t < 0.5 ? a?.useIndicator : b?.useIndicator,
diff --git a/framework/lib/src/material/radio.dart b/framework/lib/src/material/radio.dart
index 8fc68d5..014bb72 100644
--- a/framework/lib/src/material/radio.dart
+++ b/framework/lib/src/material/radio.dart
@@ -264,10 +264,12 @@
   /// [ThemeData.focusColor] is used.
   final Color? focusColor;
 
+  /// {@template flutter.material.radio.hoverColor}
   /// The color for the radio's [Material] when a pointer is hovering over it.
   ///
   /// If [overlayColor] returns a non-null color in the [MaterialState.hovered]
   /// state, it will be used instead.
+  /// {@endtemplate}
   ///
   /// If null, then the value of [RadioThemeData.overlayColor] is used in the
   /// hovered state. If that is also null, then the value of
@@ -275,7 +277,7 @@
   final Color? hoverColor;
 
   /// {@template flutter.material.radio.overlayColor}
-  /// The color for the checkbox's [Material].
+  /// The color for the radio's [Material].
   ///
   /// Resolves in the following states:
   ///  * [MaterialState.pressed].
diff --git a/framework/lib/src/material/radio_list_tile.dart b/framework/lib/src/material/radio_list_tile.dart
index 754220c..bc5534d 100644
--- a/framework/lib/src/material/radio_list_tile.dart
+++ b/framework/lib/src/material/radio_list_tile.dart
@@ -162,8 +162,14 @@
     required this.value,
     required this.groupValue,
     required this.onChanged,
+    this.mouseCursor,
     this.toggleable = false,
     this.activeColor,
+    this.fillColor,
+    this.hoverColor,
+    this.overlayColor,
+    this.splashRadius,
+    this.materialTapTargetSize,
     this.title,
     this.subtitle,
     this.isThreeLine = false,
@@ -220,6 +226,20 @@
   /// ```
   final ValueChanged<T?>? onChanged;
 
+  /// The cursor for a mouse pointer when it enters or is hovering over the
+  /// widget.
+  ///
+  /// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
+  /// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
+  ///
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [RadioThemeData.mouseCursor] is used.
+  /// If that is also null, then [MaterialStateMouseCursor.clickable] is used.
+  final MouseCursor? mouseCursor;
+
   /// Set to true if this radio list tile is allowed to be returned to an
   /// indeterminate state by selecting it again when selected.
   ///
@@ -250,6 +270,45 @@
   /// Defaults to [ColorScheme.secondary] of the current [Theme].
   final Color? activeColor;
 
+  /// The color that fills the radio button.
+  ///
+  /// Resolves in the following states:
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [activeColor] is used in the selected state. If
+  /// that is also null, then the value of [RadioThemeData.fillColor] is used.
+  /// If that is also null, then the default value is used.
+  final MaterialStateProperty<Color?>? fillColor;
+
+  /// {@macro flutter.material.radio.materialTapTargetSize}
+  ///
+  /// Defaults to [MaterialTapTargetSize.shrinkWrap].
+  final MaterialTapTargetSize? materialTapTargetSize;
+
+  /// {@macro flutter.material.radio.hoverColor}
+  final Color? hoverColor;
+
+  /// The color for the radio's [Material].
+  ///
+  /// Resolves in the following states:
+  ///  * [MaterialState.pressed].
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///
+  /// If null, then the value of [activeColor] with alpha [kRadialReactionAlpha]
+  /// and [hoverColor] is used in the pressed and hovered state. If that is also
+  /// null, the value of [SwitchThemeData.overlayColor] is used. If that is
+  /// also null, then the default value is used in the pressed and hovered state.
+  final MaterialStateProperty<Color?>? overlayColor;
+
+  /// {@macro flutter.material.radio.splashRadius}
+  ///
+  /// If null, then the value of [RadioThemeData.splashRadius] is used. If that
+  /// is also null, then [kRadialReactionRadius] is used.
+  final double? splashRadius;
+
   /// The primary content of the list tile.
   ///
   /// Typically a [Text] widget.
@@ -341,8 +400,13 @@
       onChanged: onChanged,
       toggleable: toggleable,
       activeColor: activeColor,
-      materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+      materialTapTargetSize: materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap,
       autofocus: autofocus,
+      fillColor: fillColor,
+      mouseCursor: mouseCursor,
+      hoverColor: hoverColor,
+      overlayColor: overlayColor,
+      splashRadius: splashRadius,
     );
     Widget? leading, trailing;
     switch (controlAffinity) {
diff --git a/framework/lib/src/material/search.dart b/framework/lib/src/material/search.dart
index e5f656b..f26d895 100644
--- a/framework/lib/src/material/search.dart
+++ b/framework/lib/src/material/search.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'package:flute/services.dart';
 import 'package:flute/widgets.dart';
 
 import 'app_bar.dart';
@@ -231,7 +232,9 @@
     final ColorScheme colorScheme = theme.colorScheme;
     return theme.copyWith(
       appBarTheme: AppBarTheme(
-        brightness: colorScheme.brightness,
+        systemOverlayStyle: colorScheme.brightness == Brightness.dark
+          ? SystemUiOverlayStyle.light
+          : SystemUiOverlayStyle.dark,
         backgroundColor: colorScheme.brightness == Brightness.dark ? Colors.grey[900] : Colors.white,
         iconTheme: theme.primaryIconTheme.copyWith(color: Colors.grey),
         titleTextStyle: theme.textTheme.titleLarge,
diff --git a/framework/lib/src/material/slider.dart b/framework/lib/src/material/slider.dart
index d64d736..c903541 100644
--- a/framework/lib/src/material/slider.dart
+++ b/framework/lib/src/material/slider.dart
@@ -1215,7 +1215,7 @@
       return;
     }
     _sliderTheme = value;
-    markNeedsPaint();
+    _updateLabelPainter();
   }
 
   double get textScaleFactor => _textScaleFactor;
diff --git a/framework/lib/src/material/snack_bar.dart b/framework/lib/src/material/snack_bar.dart
index 5d45c47..67cf2bd 100644
--- a/framework/lib/src/material/snack_bar.dart
+++ b/framework/lib/src/material/snack_bar.dart
@@ -140,15 +140,20 @@
     final SnackBarThemeData snackBarTheme = Theme.of(context).snackBarTheme;
 
     MaterialStateColor resolveForegroundColor() {
-      if (widget.textColor is MaterialStateColor) {
-        return widget.textColor! as MaterialStateColor;
+      if (widget.textColor != null) {
+        if (widget.textColor is MaterialStateColor) {
+          return widget.textColor! as MaterialStateColor;
+        }
+      } else if (snackBarTheme.actionTextColor != null) {
+        if (snackBarTheme.actionTextColor is MaterialStateColor) {
+          return snackBarTheme.actionTextColor! as MaterialStateColor;
+        }
+      } else if (defaults.actionTextColor != null) {
+        if (defaults.actionTextColor is MaterialStateColor) {
+          return defaults.actionTextColor! as MaterialStateColor;
+        }
       }
-      if (snackBarTheme.actionTextColor is MaterialStateColor) {
-        return snackBarTheme.actionTextColor! as MaterialStateColor;
-      }
-      if (defaults.actionTextColor is MaterialStateColor) {
-        return defaults.actionTextColor! as MaterialStateColor;
-      }
+
       return MaterialStateColor.resolveWith((Set<MaterialState> states) {
         if (states.contains(MaterialState.disabled)) {
           return widget.disabledTextColor ??
@@ -234,6 +239,7 @@
     this.shape,
     this.behavior,
     this.action,
+    this.actionOverflowThreshold,
     this.showCloseIcon,
     this.closeIconColor,
     this.duration = _snackBarDisplayDuration,
@@ -242,10 +248,11 @@
     this.dismissDirection = DismissDirection.down,
     this.clipBehavior = Clip.hardEdge,
   }) : assert(elevation == null || elevation >= 0.0),
-       assert(
-         width == null || margin == null,
+       assert(width == null || margin == null,
          'Width and margin can not be used together',
-       );
+       ),
+       assert(actionOverflowThreshold == null || (actionOverflowThreshold >= 0 && actionOverflowThreshold <= 1),
+        'Action overflow threshold must be between 0 and 1 inclusive');
 
   /// The primary content of the snack bar.
   ///
@@ -353,6 +360,18 @@
   /// The action should not be "dismiss" or "cancel".
   final SnackBarAction? action;
 
+  /// (optional) The percentage threshold for action widget's width before it overflows
+  /// to a new line.
+  ///
+  /// Must be between 0 and 1. If the width of the snackbar's [content] is greater
+  /// than this percentage of the width of the snackbar less the width of its [action],
+  /// then the [action] will appear below the [content].
+  ///
+  /// At a value of 0, the action will not overflow to a new line.
+  ///
+  /// Defaults to 0.25.
+  final double? actionOverflowThreshold;
+
   /// (optional) Whether to include a "close" icon widget.
   ///
   /// Tapping the icon will close the snack bar.
@@ -426,6 +445,7 @@
       shape: shape,
       behavior: behavior,
       action: action,
+      actionOverflowThreshold: actionOverflowThreshold,
       showCloseIcon: showCloseIcon,
       closeIconColor: closeIconColor,
       duration: duration,
@@ -596,10 +616,11 @@
     final EdgeInsets margin = widget.margin?.resolve(TextDirection.ltr) ?? snackBarTheme.insetPadding ?? defaults.insetPadding!;
 
     final double snackBarWidth = widget.width ?? MediaQuery.sizeOf(context).width - (margin.left + margin.right);
-    // Action and Icon will overflow to a new line if their width is greater
-    // than one quarter of the total Snack Bar width.
-    final bool actionLineOverflow =
-        actionAndIconWidth / snackBarWidth > 0.25;
+    final double actionOverflowThreshold = widget.actionOverflowThreshold
+      ?? snackBarTheme.actionOverflowThreshold
+      ?? defaults.actionOverflowThreshold!;
+
+    final bool willOverflowAction = actionAndIconWidth / snackBarWidth > actionOverflowThreshold;
 
     final List<Widget> maybeActionAndIcon = <Widget>[
       if (widget.action != null)
@@ -640,18 +661,17 @@
                     ),
                   ),
                 ),
-                if(!actionLineOverflow) ...maybeActionAndIcon,
-                if(actionLineOverflow) SizedBox(width: snackBarWidth*0.4),
+                if (!willOverflowAction) ...maybeActionAndIcon,
+                if (willOverflowAction) SizedBox(width: snackBarWidth * 0.4),
               ],
             ),
-            if(actionLineOverflow) Padding(
-              padding: const EdgeInsets.only(bottom: _singleLineVerticalPadding),
-              child: Row(mainAxisAlignment: MainAxisAlignment.end,
-              children: maybeActionAndIcon),
-            ),
-          ],
-
-      ),
+            if (willOverflowAction)
+              Padding(
+                padding: const EdgeInsets.only(bottom: _singleLineVerticalPadding),
+                child: Row(mainAxisAlignment: MainAxisAlignment.end, children: maybeActionAndIcon),
+              ),
+            ],
+        ),
     );
 
     if (!isFloatingSnackBar) {
@@ -815,6 +835,9 @@
 
   @override
   Color get closeIconColor => _colors.onSurface;
+
+  @override
+  double get actionOverflowThreshold => 0.25;
 }
 
 // BEGIN GENERATED TOKEN PROPERTIES - Snackbar
@@ -879,6 +902,12 @@
 
   @override
   bool get showCloseIcon => false;
+
+  @override
+  Color? get closeIconColor => _colors.onInverseSurface;
+
+  @override
+  double get actionOverflowThreshold => 0.25;
 }
 
 // END GENERATED TOKEN PROPERTIES - Snackbar
diff --git a/framework/lib/src/material/snack_bar_theme.dart b/framework/lib/src/material/snack_bar_theme.dart
index a4b4c88..820e35a 100644
--- a/framework/lib/src/material/snack_bar_theme.dart
+++ b/framework/lib/src/material/snack_bar_theme.dart
@@ -64,11 +64,13 @@
     this.insetPadding,
     this.showCloseIcon,
     this.closeIconColor,
+    this.actionOverflowThreshold,
   })  : assert(elevation == null || elevation >= 0.0),
-        assert(
-            width == null ||
-                (identical(behavior, SnackBarBehavior.floating)),
-            'Width can only be set if behaviour is SnackBarBehavior.floating');
+        assert(width == null || identical(behavior, SnackBarBehavior.floating),
+          'Width can only be set if behaviour is SnackBarBehavior.floating'),
+        assert(actionOverflowThreshold == null || (actionOverflowThreshold >= 0 && actionOverflowThreshold <= 1),
+          'Action overflow threshold must be between 0 and 1 inclusive');
+
   /// Overrides the default value for [SnackBar.backgroundColor].
   ///
   /// If null, [SnackBar] defaults to dark grey: `Color(0xFF323232)`.
@@ -133,6 +135,11 @@
   /// This value is only used if [showCloseIcon] is true.
   final Color? closeIconColor;
 
+  /// Overrides the default value for [SnackBar.actionOverflowThreshold].
+  ///
+  /// Must be a value between 0 and 1, if present.
+  final double? actionOverflowThreshold;
+
   /// Creates a copy of this object with the given fields replaced with the
   /// new values.
   SnackBarThemeData copyWith({
@@ -147,6 +154,7 @@
     EdgeInsets? insetPadding,
     bool? showCloseIcon,
     Color? closeIconColor,
+    double? actionOverflowThreshold,
   }) {
     return SnackBarThemeData(
       backgroundColor: backgroundColor ?? this.backgroundColor,
@@ -160,6 +168,7 @@
       insetPadding: insetPadding ?? this.insetPadding,
       showCloseIcon: showCloseIcon ?? this.showCloseIcon,
       closeIconColor: closeIconColor ?? this.closeIconColor,
+      actionOverflowThreshold: actionOverflowThreshold ?? this.actionOverflowThreshold,
     );
   }
 
@@ -180,6 +189,7 @@
       width: lerpDouble(a?.width, b?.width, t),
       insetPadding: EdgeInsets.lerp(a?.insetPadding, b?.insetPadding, t),
       closeIconColor: Color.lerp(a?.closeIconColor, b?.closeIconColor, t),
+      actionOverflowThreshold: lerpDouble(a?.actionOverflowThreshold, b?.actionOverflowThreshold, t),
     );
   }
 
@@ -196,6 +206,7 @@
         insetPadding,
         showCloseIcon,
         closeIconColor,
+        actionOverflowThreshold,
       );
 
   @override
@@ -217,7 +228,8 @@
         && other.width == width
         && other.insetPadding == insetPadding
         && other.showCloseIcon == showCloseIcon
-        && other.closeIconColor == closeIconColor;
+        && other.closeIconColor == closeIconColor
+        && other.actionOverflowThreshold == actionOverflowThreshold;
   }
 
   @override
@@ -234,5 +246,6 @@
     properties.add(DiagnosticsProperty<EdgeInsets>('insetPadding', insetPadding, defaultValue: null));
     properties.add(DiagnosticsProperty<bool>('showCloseIcon', showCloseIcon, defaultValue: null));
     properties.add(ColorProperty('closeIconColor', closeIconColor, defaultValue: null));
+    properties.add(DoubleProperty('actionOverflowThreshold', actionOverflowThreshold, defaultValue: null));
   }
 }
diff --git a/framework/lib/src/material/switch.dart b/framework/lib/src/material/switch.dart
index 0170814..1e05612 100644
--- a/framework/lib/src/material/switch.dart
+++ b/framework/lib/src/material/switch.dart
@@ -105,6 +105,7 @@
     this.onInactiveThumbImageError,
     this.thumbColor,
     this.trackColor,
+    this.trackOutlineColor,
     this.thumbIcon,
     this.materialTapTargetSize,
     this.dragStartBehavior = DragStartBehavior.start,
@@ -151,6 +152,7 @@
     this.materialTapTargetSize,
     this.thumbColor,
     this.trackColor,
+    this.trackOutlineColor,
     this.thumbIcon,
     this.dragStartBehavior = DragStartBehavior.start,
     this.mouseCursor,
@@ -195,7 +197,9 @@
   /// ```
   final ValueChanged<bool>? onChanged;
 
+  /// {@template flutter.material.switch.activeColor}
   /// The color to use when this switch is on.
+  /// {@endtemplate}
   ///
   /// Defaults to [ColorScheme.secondary].
   ///
@@ -203,7 +207,9 @@
   /// state, it will be used instead of this color.
   final Color? activeColor;
 
+  /// {@template flutter.material.switch.activeTrackColor}
   /// The color to use on the track when this switch is on.
+  /// {@endtemplate}
   ///
   /// Defaults to [ColorScheme.secondary] with the opacity set at 50%.
   ///
@@ -213,7 +219,9 @@
   /// state, it will be used instead of this color.
   final Color? activeTrackColor;
 
+  /// {@template flutter.material.switch.inactiveThumbColor}
   /// The color to use on the thumb when this switch is off.
+  /// {@endtemplate}
   ///
   /// Defaults to the colors described in the Material design specification.
   ///
@@ -223,7 +231,9 @@
   /// used instead of this color.
   final Color? inactiveThumbColor;
 
+  /// {@template flutter.material.switch.inactiveTrackColor}
   /// The color to use on the track when this switch is off.
+  /// {@endtemplate}
   ///
   /// Defaults to the colors described in the Material design specification.
   ///
@@ -233,22 +243,30 @@
   /// used instead of this color.
   final Color? inactiveTrackColor;
 
+  /// {@template flutter.material.switch.activeThumbImage}
   /// An image to use on the thumb of this switch when the switch is on.
+  /// {@endtemplate}
   ///
   /// Ignored if this switch is created with [Switch.adaptive].
   final ImageProvider? activeThumbImage;
 
+  /// {@template flutter.material.switch.onActiveThumbImageError}
   /// An optional error callback for errors emitted when loading
   /// [activeThumbImage].
+  /// {@endtemplate}
   final ImageErrorListener? onActiveThumbImageError;
 
+  /// {@template flutter.material.switch.inactiveThumbImage}
   /// An image to use on the thumb of this switch when the switch is off.
+  /// {@endtemplate}
   ///
   /// Ignored if this switch is created with [Switch.adaptive].
   final ImageProvider? inactiveThumbImage;
 
+  /// {@template flutter.material.switch.onInactiveThumbImageError}
   /// An optional error callback for errors emitted when loading
   /// [inactiveThumbImage].
+  /// {@endtemplate}
   final ImageErrorListener? onInactiveThumbImageError;
 
   /// {@template flutter.material.switch.thumbColor}
@@ -333,6 +351,40 @@
   /// | Disabled | `Colors.black12`                | `Colors.white10`                |
   final MaterialStateProperty<Color?>? trackColor;
 
+  /// {@template flutter.material.switch.trackOutlineColor}
+  /// The outline color of this [Switch]'s track.
+  ///
+  /// Resolved in the following states:
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.focused].
+  ///  * [MaterialState.disabled].
+  ///
+  /// {@tool snippet}
+  /// This example resolves the [trackOutlineColor] based on the current
+  /// [MaterialState] of the [Switch], providing a different [Color] when it is
+  /// [MaterialState.disabled].
+  ///
+  /// ```dart
+  /// Switch(
+  ///   value: true,
+  ///   onChanged: (_) => true,
+  ///   trackOutlineColor: MaterialStateProperty.resolveWith<Color?>((Set<MaterialState> states) {
+  ///     if (states.contains(MaterialState.disabled)) {
+  ///       return Colors.orange.withOpacity(.48);
+  ///     }
+  ///     return null; // Use the default color.
+  ///   }),
+  /// )
+  /// ```
+  /// {@end-tool}
+  /// {@endtemplate}
+  ///
+  /// In Material 3, the outline color defaults to transparent in the selected
+  /// state and [ColorScheme.outline] in the unselected state. In Material 2,
+  /// the [Switch] track has no outline by default.
+  final MaterialStateProperty<Color?>? trackOutlineColor;
+
   /// {@template flutter.material.switch.thumbIcon}
   /// The icon to use on the thumb of this switch
   ///
@@ -519,6 +571,7 @@
       onInactiveThumbImageError: onInactiveThumbImageError,
       thumbColor: thumbColor,
       trackColor: trackColor,
+      trackOutlineColor: trackOutlineColor,
       thumbIcon: thumbIcon,
       materialTapTargetSize: materialTapTargetSize,
       dragStartBehavior: dragStartBehavior,
@@ -578,6 +631,7 @@
     this.onInactiveThumbImageError,
     this.thumbColor,
     this.trackColor,
+    this.trackOutlineColor,
     this.thumbIcon,
     this.materialTapTargetSize,
     this.dragStartBehavior = DragStartBehavior.start,
@@ -604,6 +658,7 @@
   final ImageErrorListener? onInactiveThumbImageError;
   final MaterialStateProperty<Color?>? thumbColor;
   final MaterialStateProperty<Color?>? trackColor;
+  final MaterialStateProperty<Color?>? trackOutlineColor;
   final MaterialStateProperty<Icon?>? thumbIcon;
   final MaterialTapTargetSize? materialTapTargetSize;
   final DragStartBehavior dragStartBehavior;
@@ -765,11 +820,17 @@
       ?? switchTheme.trackColor?.resolve(activeStates)
       ?? _widgetThumbColor.resolve(activeStates)?.withAlpha(0x80)
       ?? defaults.trackColor!.resolve(activeStates)!;
+    final Color effectiveActiveTrackOutlineColor = widget.trackOutlineColor?.resolve(activeStates)
+      ?? switchTheme.trackOutlineColor?.resolve(activeStates)
+      ?? Colors.transparent;
+
     final Color effectiveInactiveTrackColor = widget.trackColor?.resolve(inactiveStates)
       ?? _widgetTrackColor.resolve(inactiveStates)
       ?? switchTheme.trackColor?.resolve(inactiveStates)
       ?? defaults.trackColor!.resolve(inactiveStates)!;
-    final Color? effectiveInactiveTrackOutlineColor = switchConfig.trackOutlineColor?.resolve(inactiveStates);
+    final Color? effectiveInactiveTrackOutlineColor = widget.trackOutlineColor?.resolve(inactiveStates)
+      ?? switchTheme.trackOutlineColor?.resolve(inactiveStates)
+      ?? defaults.trackOutlineColor?.resolve(inactiveStates);
 
     final Icon? effectiveActiveIcon = widget.thumbIcon?.resolve(activeStates)
       ?? switchTheme.thumbIcon?.resolve(activeStates);
@@ -858,6 +919,7 @@
             ..inactiveThumbImage = widget.inactiveThumbImage
             ..onInactiveThumbImageError = widget.onInactiveThumbImageError
             ..activeTrackColor = effectiveActiveTrackColor
+            ..activeTrackOutlineColor = effectiveActiveTrackOutlineColor
             ..inactiveTrackColor = effectiveInactiveTrackColor
             ..inactiveTrackOutlineColor = effectiveInactiveTrackOutlineColor
             ..configuration = createLocalImageConfiguration(context)
@@ -1089,6 +1151,16 @@
     notifyListeners();
   }
 
+  Color? get activeTrackOutlineColor => _activeTrackOutlineColor;
+  Color? _activeTrackOutlineColor;
+  set activeTrackOutlineColor(Color? value) {
+    if (value == _activeTrackOutlineColor) {
+      return;
+    }
+    _activeTrackOutlineColor = value;
+    notifyListeners();
+  }
+
   Color? get inactiveTrackOutlineColor => _inactiveTrackOutlineColor;
   Color? _inactiveTrackOutlineColor;
   set inactiveTrackOutlineColor(Color? value) {
@@ -1297,7 +1369,7 @@
     final double colorValue = CurvedAnimation(parent: positionController, curve: Curves.easeOut, reverseCurve: Curves.easeIn).value;
     final Color trackColor = Color.lerp(inactiveTrackColor, activeTrackColor, colorValue)!;
     final Color? trackOutlineColor = inactiveTrackOutlineColor == null ? null
-        : Color.lerp(inactiveTrackOutlineColor, Colors.transparent, colorValue);
+        : Color.lerp(inactiveTrackOutlineColor, activeTrackOutlineColor, colorValue);
     Color lerpedThumbColor;
     if (!reaction.isDismissed) {
       lerpedThumbColor = Color.lerp(inactivePressedColor, activePressedColor, colorValue)!;
@@ -1493,7 +1565,6 @@
   double get pressedThumbRadius;
   double get thumbRadiusWithIcon;
   List<BoxShadow>? get thumbShadow;
-  MaterialStateProperty<Color?>? get trackOutlineColor;
   MaterialStateProperty<Color> get iconColor;
   double? get thumbOffset;
   Size get transitionalThumbSize;
@@ -1535,9 +1606,6 @@
   double get trackHeight => 14.0;
 
   @override
-  MaterialStateProperty<Color?>? get trackOutlineColor => null;
-
-  @override
   double get trackWidth => 33.0;
 
   @override
@@ -1591,6 +1659,9 @@
   }
 
   @override
+  MaterialStateProperty<Color?>? get trackOutlineColor => null;
+
+  @override
   MaterialTapTargetSize get materialTapTargetSize => _theme.materialTapTargetSize;
 
   @override
@@ -1701,6 +1772,19 @@
   }
 
   @override
+  MaterialStateProperty<Color?> get trackOutlineColor {
+    return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
+      if (states.contains(MaterialState.selected)) {
+        return Colors.transparent;
+      }
+      if (states.contains(MaterialState.disabled)) {
+        return _colors.onSurface.withOpacity(0.12);
+      }
+      return _colors.outline;
+    });
+  }
+
+  @override
   MaterialStateProperty<Color?> get overlayColor {
     return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
       if (states.contains(MaterialState.selected)) {
@@ -1803,19 +1887,6 @@
   double get trackHeight => 32.0;
 
   @override
-  MaterialStateProperty<Color?> get trackOutlineColor {
-    return MaterialStateProperty.resolveWith((Set<MaterialState> states) {
-      if (states.contains(MaterialState.selected)) {
-        return null;
-      }
-      if (states.contains(MaterialState.disabled)) {
-        return _colors.onSurface.withOpacity(0.12);
-      }
-      return _colors.outline;
-    });
-  }
-
-  @override
   double get trackWidth => 52.0;
 
   // The thumb size at the middle of the track. Hand coded default based on the animation specs.
diff --git a/framework/lib/src/material/switch_list_tile.dart b/framework/lib/src/material/switch_list_tile.dart
index e017c2d..f060e9b 100644
--- a/framework/lib/src/material/switch_list_tile.dart
+++ b/framework/lib/src/material/switch_list_tile.dart
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+import 'package:flute/gestures.dart';
 import 'package:flute/widgets.dart';
 
 import 'list_tile.dart';
@@ -163,13 +164,27 @@
     super.key,
     required this.value,
     required this.onChanged,
-    this.tileColor,
     this.activeColor,
     this.activeTrackColor,
     this.inactiveThumbColor,
     this.inactiveTrackColor,
     this.activeThumbImage,
+    this.onActiveThumbImageError,
     this.inactiveThumbImage,
+    this.onInactiveThumbImageError,
+    this.thumbColor,
+    this.trackColor,
+    this.trackOutlineColor,
+    this.thumbIcon,
+    this.materialTapTargetSize,
+    this.dragStartBehavior = DragStartBehavior.start,
+    this.mouseCursor,
+    this.overlayColor,
+    this.splashRadius,
+    this.focusNode,
+    this.onFocusChange,
+    this.autofocus = false,
+    this.tileColor,
     this.title,
     this.subtitle,
     this.isThreeLine = false,
@@ -177,16 +192,16 @@
     this.contentPadding,
     this.secondary,
     this.selected = false,
-    this.autofocus = false,
     this.controlAffinity = ListTileControlAffinity.platform,
     this.shape,
     this.selectedTileColor,
     this.visualDensity,
-    this.focusNode,
-    this.onFocusChange,
     this.enableFeedback,
     this.hoverColor,
   }) : _switchListTileType = _SwitchListTileType.material,
+       applyCupertinoTheme = false,
+       assert(activeThumbImage != null || onActiveThumbImageError == null),
+       assert(inactiveThumbImage != null || onInactiveThumbImageError == null),
        assert(!isThreeLine || subtitle != null);
 
   /// Creates a Material [ListTile] with an adaptive [Switch], following
@@ -205,13 +220,28 @@
     super.key,
     required this.value,
     required this.onChanged,
-    this.tileColor,
     this.activeColor,
     this.activeTrackColor,
     this.inactiveThumbColor,
     this.inactiveTrackColor,
     this.activeThumbImage,
+    this.onActiveThumbImageError,
     this.inactiveThumbImage,
+    this.onInactiveThumbImageError,
+    this.thumbColor,
+    this.trackColor,
+    this.trackOutlineColor,
+    this.thumbIcon,
+    this.materialTapTargetSize,
+    this.dragStartBehavior = DragStartBehavior.start,
+    this.mouseCursor,
+    this.overlayColor,
+    this.splashRadius,
+    this.focusNode,
+    this.onFocusChange,
+    this.autofocus = false,
+    this.applyCupertinoTheme,
+    this.tileColor,
     this.title,
     this.subtitle,
     this.isThreeLine = false,
@@ -219,17 +249,16 @@
     this.contentPadding,
     this.secondary,
     this.selected = false,
-    this.autofocus = false,
     this.controlAffinity = ListTileControlAffinity.platform,
     this.shape,
     this.selectedTileColor,
     this.visualDensity,
-    this.focusNode,
-    this.onFocusChange,
     this.enableFeedback,
     this.hoverColor,
   }) : _switchListTileType = _SwitchListTileType.adaptive,
-       assert(!isThreeLine || subtitle != null);
+       assert(!isThreeLine || subtitle != null),
+       assert(activeThumbImage != null || onActiveThumbImageError == null),
+       assert(inactiveThumbImage != null || onInactiveThumbImageError == null);
 
   /// Whether this switch is checked.
   ///
@@ -263,43 +292,146 @@
   /// {@end-tool}
   final ValueChanged<bool>? onChanged;
 
-  /// The color to use when this switch is on.
+  /// {@macro flutter.material.switch.activeColor}
   ///
   /// Defaults to [ColorScheme.secondary] of the current [Theme].
   final Color? activeColor;
 
-  /// The color to use on the track when this switch is on.
+  /// {@macro flutter.material.switch.activeTrackColor}
   ///
   /// Defaults to [ThemeData.toggleableActiveColor] with the opacity set at 50%.
   ///
   /// Ignored if created with [SwitchListTile.adaptive].
   final Color? activeTrackColor;
 
-  /// The color to use on the thumb when this switch is off.
+  /// {@macro flutter.material.switch.inactiveThumbColor}
   ///
   /// Defaults to the colors described in the Material design specification.
   ///
   /// Ignored if created with [SwitchListTile.adaptive].
   final Color? inactiveThumbColor;
 
-  /// The color to use on the track when this switch is off.
+  /// {@macro flutter.material.switch.inactiveTrackColor}
   ///
   /// Defaults to the colors described in the Material design specification.
   ///
   /// Ignored if created with [SwitchListTile.adaptive].
   final Color? inactiveTrackColor;
 
-  /// {@macro flutter.material.ListTile.tileColor}
-  final Color? tileColor;
-
-  /// An image to use on the thumb of this switch when the switch is on.
+  /// {@macro flutter.material.switch.activeThumbImage}
   final ImageProvider? activeThumbImage;
 
-  /// An image to use on the thumb of this switch when the switch is off.
+  /// {@macro flutter.material.switch.onActiveThumbImageError}
+  final ImageErrorListener? onActiveThumbImageError;
+
+  /// {@macro flutter.material.switch.inactiveThumbImage}
   ///
   /// Ignored if created with [SwitchListTile.adaptive].
   final ImageProvider? inactiveThumbImage;
 
+  /// {@macro flutter.material.switch.onInactiveThumbImageError}
+  final ImageErrorListener? onInactiveThumbImageError;
+
+  /// The color of this switch's thumb.
+  ///
+  /// Resolved in the following states:
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [activeColor] is used in the selected state
+  /// and [inactiveThumbColor] in the default state. If that is also null, then
+  /// the value of [SwitchThemeData.thumbColor] is used. If that is also null,
+  /// The default value is used.
+  final MaterialStateProperty<Color?>? thumbColor;
+
+  /// The color of this switch's track.
+  ///
+  /// Resolved in the following states:
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [activeTrackColor] is used in the selected
+  /// state and [inactiveTrackColor] in the default state. If that is also null,
+  /// then the value of [SwitchThemeData.trackColor] is used. If that is also
+  /// null, then the default value is used.
+  final MaterialStateProperty<Color?>? trackColor;
+
+  /// {@macro flutter.material.switch.trackOutlineColor}
+  ///
+  /// The [ListTile] will be focused when this [SwitchListTile] requests focus,
+  /// so the focused outline color of the switch will be ignored.
+  ///
+  /// In Material 3, the outline color defaults to transparent in the selected
+  /// state and [ColorScheme.outline] in the unselected state. In Material 2,
+  /// the [Switch] track has no outline.
+  final MaterialStateProperty<Color?>? trackOutlineColor;
+
+  /// The icon to use on the thumb of this switch
+  ///
+  /// Resolved in the following states:
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [SwitchThemeData.thumbIcon] is used. If this is
+  /// also null, then the [Switch] does not have any icons on the thumb.
+  final MaterialStateProperty<Icon?>? thumbIcon;
+
+  /// {@macro flutter.material.switch.materialTapTargetSize}
+  ///
+  /// defaults to [MaterialTapTargetSize.shrinkWrap].
+  final MaterialTapTargetSize? materialTapTargetSize;
+
+  /// {@macro flutter.cupertino.CupertinoSwitch.dragStartBehavior}
+  final DragStartBehavior dragStartBehavior;
+
+  /// The cursor for a mouse pointer when it enters or is hovering over the
+  /// widget.
+  ///
+  /// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
+  /// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
+  ///
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///  * [MaterialState.disabled].
+  ///
+  /// If null, then the value of [SwitchThemeData.mouseCursor] is used. If that
+  /// is also null, then [MaterialStateMouseCursor.clickable] is used.
+  final MouseCursor? mouseCursor;
+
+  /// The color for the switch's [Material].
+  ///
+  /// Resolves in the following states:
+  ///  * [MaterialState.pressed].
+  ///  * [MaterialState.selected].
+  ///  * [MaterialState.hovered].
+  ///
+  /// If null, then the value of [activeColor] with alpha [kRadialReactionAlpha]
+  /// and [hoverColor] is used in the pressed and hovered state. If that is also
+  /// null, the value of [SwitchThemeData.overlayColor] is used. If that is
+  /// also null, then the default value is used in the pressed and hovered state.
+  final MaterialStateProperty<Color?>? overlayColor;
+
+  /// {@macro flutter.material.switch.splashRadius}
+  ///
+  /// If null, then the value of [SwitchThemeData.splashRadius] is used. If that
+  /// is also null, then [kRadialReactionRadius] is used.
+  final double? splashRadius;
+
+  /// {@macro flutter.widgets.Focus.focusNode}
+  final FocusNode? focusNode;
+
+  /// {@macro flutter.material.inkwell.onFocusChange}
+  final ValueChanged<bool>? onFocusChange;
+
+  /// {@macro flutter.widgets.Focus.autofocus}
+  final bool autofocus;
+
+  /// {@macro flutter.material.ListTile.tileColor}
+  final Color? tileColor;
+
   /// The primary content of the list tile.
   ///
   /// Typically a [Text] widget.
@@ -344,9 +476,6 @@
   /// Normally, this property is left to its default value, false.
   final bool selected;
 
-  /// {@macro flutter.widgets.Focus.autofocus}
-  final bool autofocus;
-
   /// If adaptive, creates the switch with [Switch.adaptive].
   final _SwitchListTileType _switchListTileType;
 
@@ -366,12 +495,6 @@
   /// {@macro flutter.material.themedata.visualDensity}
   final VisualDensity? visualDensity;
 
-  /// {@macro flutter.widgets.Focus.focusNode}
-  final FocusNode? focusNode;
-
-  /// {@macro flutter.material.inkwell.onFocusChange}
-  final ValueChanged<bool>? onFocusChange;
-
   /// {@macro flutter.material.ListTile.enableFeedback}
   ///
   /// See also:
@@ -382,6 +505,9 @@
   /// The color for the tile's [Material] when a pointer is hovering over it.
   final Color? hoverColor;
 
+  /// {@macro flutter.cupertino.CupertinoSwitch.applyTheme}
+  final bool? applyCupertinoTheme;
+
   @override
   Widget build(BuildContext context) {
     final Widget control;
@@ -393,12 +519,23 @@
           activeColor: activeColor,
           activeThumbImage: activeThumbImage,
           inactiveThumbImage: inactiveThumbImage,
-          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+          materialTapTargetSize: materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap,
           activeTrackColor: activeTrackColor,
           inactiveTrackColor: inactiveTrackColor,
           inactiveThumbColor: inactiveThumbColor,
           autofocus: autofocus,
           onFocusChange: onFocusChange,
+          onActiveThumbImageError: onActiveThumbImageError,
+          onInactiveThumbImageError: onInactiveThumbImageError,
+          thumbColor: thumbColor,
+          trackColor: trackColor,
+          trackOutlineColor: trackOutlineColor,
+          thumbIcon: thumbIcon,
+          applyCupertinoTheme: applyCupertinoTheme,
+          dragStartBehavior: dragStartBehavior,
+          mouseCursor: mouseCursor,
+          splashRadius: splashRadius,
+          overlayColor: overlayColor,
         );
         break;
 
@@ -409,12 +546,22 @@
           activeColor: activeColor,
           activeThumbImage: activeThumbImage,
           inactiveThumbImage: inactiveThumbImage,
-          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
+          materialTapTargetSize: materialTapTargetSize ?? MaterialTapTargetSize.shrinkWrap,
           activeTrackColor: activeTrackColor,
           inactiveTrackColor: inactiveTrackColor,
           inactiveThumbColor: inactiveThumbColor,
           autofocus: autofocus,
           onFocusChange: onFocusChange,
+          onActiveThumbImageError: onActiveThumbImageError,
+          onInactiveThumbImageError: onInactiveThumbImageError,
+          thumbColor: thumbColor,
+          trackColor: trackColor,
+          trackOutlineColor: trackOutlineColor,
+          thumbIcon: thumbIcon,
+          dragStartBehavior: dragStartBehavior,
+          mouseCursor: mouseCursor,
+          splashRadius: splashRadius,
+          overlayColor: overlayColor,
         );
     }
 
diff --git a/framework/lib/src/material/switch_theme.dart b/framework/lib/src/material/switch_theme.dart
index 3c6139b..4d204fe 100644
--- a/framework/lib/src/material/switch_theme.dart
+++ b/framework/lib/src/material/switch_theme.dart
@@ -39,6 +39,7 @@
   const SwitchThemeData({
     this.thumbColor,
     this.trackColor,
+    this.trackOutlineColor,
     this.materialTapTargetSize,
     this.mouseCursor,
     this.overlayColor,
@@ -56,6 +57,11 @@
   /// If specified, overrides the default value of [Switch.trackColor].
   final MaterialStateProperty<Color?>? trackColor;
 
+  /// {@macro flutter.material.switch.trackOutlineColor}
+  ///
+  /// If specified, overrides the default value of [Switch.trackOutlineColor].
+  final MaterialStateProperty<Color?>? trackOutlineColor;
+
   /// {@macro flutter.material.switch.materialTapTargetSize}
   ///
   /// If specified, overrides the default value of
@@ -87,6 +93,7 @@
   SwitchThemeData copyWith({
     MaterialStateProperty<Color?>? thumbColor,
     MaterialStateProperty<Color?>? trackColor,
+    MaterialStateProperty<Color?>? trackOutlineColor,
     MaterialTapTargetSize? materialTapTargetSize,
     MaterialStateProperty<MouseCursor?>? mouseCursor,
     MaterialStateProperty<Color?>? overlayColor,
@@ -96,6 +103,7 @@
     return SwitchThemeData(
       thumbColor: thumbColor ?? this.thumbColor,
       trackColor: trackColor ?? this.trackColor,
+      trackOutlineColor: trackOutlineColor ?? this.trackOutlineColor,
       materialTapTargetSize: materialTapTargetSize ?? this.materialTapTargetSize,
       mouseCursor: mouseCursor ?? this.mouseCursor,
       overlayColor: overlayColor ?? this.overlayColor,
@@ -111,6 +119,7 @@
     return SwitchThemeData(
       thumbColor: MaterialStateProperty.lerp<Color?>(a?.thumbColor, b?.thumbColor, t, Color.lerp),
       trackColor: MaterialStateProperty.lerp<Color?>(a?.trackColor, b?.trackColor, t, Color.lerp),
+      trackOutlineColor: MaterialStateProperty.lerp<Color?>(a?.trackOutlineColor, b?.trackOutlineColor, t, Color.lerp),
       materialTapTargetSize: t < 0.5 ? a?.materialTapTargetSize : b?.materialTapTargetSize,
       mouseCursor: t < 0.5 ? a?.mouseCursor : b?.mouseCursor,
       overlayColor: MaterialStateProperty.lerp<Color?>(a?.overlayColor, b?.overlayColor, t, Color.lerp),
@@ -123,6 +132,7 @@
   int get hashCode => Object.hash(
     thumbColor,
     trackColor,
+    trackOutlineColor,
     materialTapTargetSize,
     mouseCursor,
     overlayColor,
@@ -141,6 +151,7 @@
     return other is SwitchThemeData
       && other.thumbColor == thumbColor
       && other.trackColor == trackColor
+      && other.trackOutlineColor == trackOutlineColor
       && other.materialTapTargetSize == materialTapTargetSize
       && other.mouseCursor == mouseCursor
       && other.overlayColor == overlayColor
@@ -153,6 +164,7 @@
     super.debugFillProperties(properties);
     properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('thumbColor', thumbColor, defaultValue: null));
     properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('trackColor', trackColor, defaultValue: null));
+    properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('trackOutlineColor', trackOutlineColor, defaultValue: null));
     properties.add(DiagnosticsProperty<MaterialTapTargetSize>('materialTapTargetSize', materialTapTargetSize, defaultValue: null));
     properties.add(DiagnosticsProperty<MaterialStateProperty<MouseCursor?>>('mouseCursor', mouseCursor, defaultValue: null));
     properties.add(DiagnosticsProperty<MaterialStateProperty<Color?>>('overlayColor', overlayColor, defaultValue: null));
diff --git a/framework/lib/src/material/tab_bar_theme.dart b/framework/lib/src/material/tab_bar_theme.dart
index 5e9f249..3c011d1 100644
--- a/framework/lib/src/material/tab_bar_theme.dart
+++ b/framework/lib/src/material/tab_bar_theme.dart
@@ -55,6 +55,12 @@
   final Color? dividerColor;
 
   /// Overrides the default value for [TabBar.labelColor].
+  ///
+  /// If [labelColor] is a [MaterialStateColor], then the effective color will
+  /// depend on the [MaterialState.selected] state, i.e. if the [Tab] is
+  /// selected or not. In case of unselected state, this [MaterialStateColor]'s
+  /// resolved color will be used even if [TabBar.unselectedLabelColor] or
+  /// [unselectedLabelColor] is non-null.
   final Color? labelColor;
 
   /// Overrides the default value for [TabBar.labelPadding].
diff --git a/framework/lib/src/material/tabs.dart b/framework/lib/src/material/tabs.dart
index 732009f..ebac40f 100644
--- a/framework/lib/src/material/tabs.dart
+++ b/framework/lib/src/material/tabs.dart
@@ -166,7 +166,7 @@
 class _TabStyle extends AnimatedWidget {
   const _TabStyle({
     required Animation<double> animation,
-    required this.selected,
+    required this.isSelected,
     required this.labelColor,
     required this.unselectedLabelColor,
     required this.labelStyle,
@@ -176,11 +176,47 @@
 
   final TextStyle? labelStyle;
   final TextStyle? unselectedLabelStyle;
-  final bool selected;
+  final bool isSelected;
   final Color? labelColor;
   final Color? unselectedLabelColor;
   final Widget child;
 
+  MaterialStateColor _resolveWithLabelColor(BuildContext context) {
+    final ThemeData themeData = Theme.of(context);
+    final TabBarTheme tabBarTheme = TabBarTheme.of(context);
+    final TabBarTheme defaults = themeData.useMaterial3 ? _TabsDefaultsM3(context) : _TabsDefaultsM2(context);
+    final Animation<double> animation = listenable as Animation<double>;
+
+    // labelStyle.color (and tabBarTheme.labelStyle.color) is not considered
+    // as it'll be a breaking change without a possible migration plan. for
+    // details: https://github.com/flutter/flutter/pull/109541#issuecomment-1294241417
+    Color selectedColor = labelColor
+        ?? tabBarTheme.labelColor
+        ?? defaults.labelColor!;
+
+    final Color unselectedColor;
+
+    if (selectedColor is MaterialStateColor) {
+      unselectedColor = selectedColor.resolve(const <MaterialState>{});
+      selectedColor = selectedColor.resolve(const <MaterialState>{MaterialState.selected});
+    } else {
+      // unselectedLabelColor and tabBarTheme.unselectedLabelColor are ignored
+      // when labelColor is a MaterialStateColor.
+      unselectedColor = unselectedLabelColor
+          ?? tabBarTheme.unselectedLabelColor
+          ?? (themeData.useMaterial3
+               ? defaults.unselectedLabelColor!
+               : selectedColor.withAlpha(0xB2)); // 70% alpha
+    }
+
+    return MaterialStateColor.resolveWith((Set<MaterialState> states) {
+      if (states.contains(MaterialState.selected)) {
+        return Color.lerp(selectedColor, unselectedColor, animation.value)!;
+      }
+      return Color.lerp(unselectedColor, selectedColor, animation.value)!;
+    });
+  }
+
   @override
   Widget build(BuildContext context) {
     final ThemeData themeData = Theme.of(context);
@@ -188,6 +224,10 @@
     final TabBarTheme defaults = themeData.useMaterial3 ? _TabsDefaultsM3(context) : _TabsDefaultsM2(context);
     final Animation<double> animation = listenable as Animation<double>;
 
+    final Set<MaterialState> states = isSelected
+      ? const <MaterialState>{MaterialState.selected}
+      : const <MaterialState>{};
+
     // To enable TextStyle.lerp(style1, style2, value), both styles must have
     // the same value of inherit. Force that to be inherit=true here.
     final TextStyle defaultStyle = (labelStyle
@@ -199,21 +239,10 @@
       ?? labelStyle
       ?? defaults.unselectedLabelStyle!
     ).copyWith(inherit: true);
-    final TextStyle textStyle = selected
+    final TextStyle textStyle = isSelected
       ? TextStyle.lerp(defaultStyle, defaultUnselectedStyle, animation.value)!
       : TextStyle.lerp(defaultUnselectedStyle, defaultStyle, animation.value)!;
-
-    final Color selectedColor = labelColor
-       ?? tabBarTheme.labelColor
-       ?? defaults.labelColor!;
-    final Color unselectedColor = unselectedLabelColor
-      ?? tabBarTheme.unselectedLabelColor
-      ?? (themeData.useMaterial3
-           ? defaults.unselectedLabelColor!
-           : selectedColor.withAlpha(0xB2)); // 70% alpha
-    final Color color = selected
-      ? Color.lerp(selectedColor, unselectedColor, animation.value)!
-      : Color.lerp(unselectedColor, selectedColor, animation.value)!;
+    final Color color = _resolveWithLabelColor(context).resolve(states);
 
     return DefaultTextStyle(
       style: textStyle.copyWith(color: color),
@@ -738,7 +767,8 @@
   ///
   /// If [automaticIndicatorColorAdjustment] is true,
   /// then the [indicatorColor] will be automatically adjusted to [Colors.white]
-  /// when the [indicatorColor] is same as [Material.color] of the [Material] parent widget.
+  /// when the [indicatorColor] is same as [Material.color] of the [Material]
+  /// parent widget.
   final bool automaticIndicatorColorAdjustment;
 
   /// Defines how the selected tab indicator's size is computed.
@@ -762,23 +792,50 @@
 
   /// The color of selected tab labels.
   ///
-  /// If [ThemeData.useMaterial3] is false, unselected tab labels are rendered with
-  /// the same color with 70% opacity unless [unselectedLabelColor] is non-null.
-  ///
-  /// If this property is null and [ThemeData.useMaterial3] is true, [ColorScheme.primary]
-  /// will be used, otherwise the color of the [ThemeData.primaryTextTheme]'s
+  /// If null, then [TabBarTheme.labelColor] is used. If that is also null and
+  /// [ThemeData.useMaterial3] is true, [ColorScheme.primary] will be used,
+  /// otherwise the color of the [ThemeData.primaryTextTheme]'s
   /// [TextTheme.bodyLarge] text color is used.
+  ///
+  /// If [labelColor] (or, if null, [TabBarTheme.labelColor]) is a
+  /// [MaterialStateColor], then the effective tab color will depend on the
+  /// [MaterialState.selected] state, i.e. if the [Tab] is selected or not,
+  /// ignoring [unselectedLabelColor] even if it's non-null.
+  ///
+  /// Note: [labelStyle]'s color and [TabBarTheme.labelStyle]'s color do not
+  /// affect the effective [labelColor].
+  ///
+  /// See also:
+  ///
+  ///   * [unselectedLabelColor], for color of unselected tab labels.
   final Color? labelColor;
 
   /// The color of unselected tab labels.
   ///
-  /// If this property is null and [ThemeData.useMaterial3] is true, [ColorScheme.onSurfaceVariant]
-  /// will be used, otherwise unselected tab labels are rendered with the
-  /// [labelColor] with 70% opacity.
+  /// If [labelColor] (or, if null, [TabBarTheme.labelColor]) is a
+  /// [MaterialStateColor], then the unselected tabs are rendered with
+  /// that [MaterialStateColor]'s resolved color for unselected state, even if
+  /// [unselectedLabelColor] is non-null.
+  ///
+  /// If null, then [TabBarTheme.unselectedLabelColor] is used. If that is also
+  /// null and [ThemeData.useMaterial3] is true, [ColorScheme.onSurfaceVariant]
+  /// will be used, otherwise unselected tab labels are rendered with
+  /// [labelColor] at 70% opacity.
+  ///
+  /// Note: [unselectedLabelStyle]'s color and
+  /// [TabBarTheme.unselectedLabelStyle]'s color are ignored in
+  /// [unselectedLabelColor]'s precedence calculation.
+  ///
+  /// See also:
+  ///
+  ///  * [labelColor], for color of selected tab labels.
   final Color? unselectedLabelColor;
 
   /// The text style of the selected tab labels.
   ///
+  /// This does not influence color of the tab labels even if [TextStyle.color]
+  /// is non-null. Refer [labelColor] to color selected tab labels instead.
+  ///
   /// If [unselectedLabelStyle] is null, then this text style will be used for
   /// both selected and unselected label styles.
   ///
@@ -787,6 +844,18 @@
   /// [TextTheme.bodyLarge] definition is used.
   final TextStyle? labelStyle;
 
+  /// The text style of the unselected tab labels.
+  ///
+  /// This does not influence color of the tab labels even if [TextStyle.color]
+  /// is non-null. Refer [unselectedLabelColor] to color unselected tab labels
+  /// instead.
+  ///
+  /// If this property is null and [ThemeData.useMaterial3] is true,
+  /// [TextTheme.titleSmall] will be used, otherwise then the [labelStyle] value
+  /// is used. If [labelStyle] is null, the text style of the
+  /// [ThemeData.primaryTextTheme]'s [TextTheme.bodyLarge] definition is used.
+  final TextStyle? unselectedLabelStyle;
+
   /// The padding added to each of the tab labels.
   ///
   /// If there are few tabs with both icon and text and few
@@ -796,14 +865,6 @@
   /// If this property is null, then kTabLabelPadding is used.
   final EdgeInsetsGeometry? labelPadding;
 
-  /// The text style of the unselected tab labels.
-  ///
-  /// If this property is null and [ThemeData.useMaterial3] is true, [TextTheme.titleSmall]
-  /// will be used, otherwise then the [labelStyle] value is used. If [labelStyle]
-  /// is null, the text style of the [ThemeData.primaryTextTheme]'s
-  /// [TextTheme.bodyLarge] definition is used.
-  final TextStyle? unselectedLabelStyle;
-
   /// Defines the ink response focus, hover, and splash colors.
   ///
   /// If non-null, it is resolved against one of [MaterialState.focused],
@@ -1081,7 +1142,7 @@
       _updateTabController();
       _initIndicatorPainter();
       // Adjust scroll position.
-      if (_scrollController != null) {
+      if (_scrollController != null && _scrollController!.hasClients) {
         final ScrollPosition position = _scrollController!.position;
         if (position is _TabBarScrollPosition) {
           position.markNeedsPixelsCorrection();
@@ -1209,10 +1270,10 @@
     widget.onTap?.call(index);
   }
 
-  Widget _buildStyledTab(Widget child, bool selected, Animation<double> animation) {
+  Widget _buildStyledTab(Widget child, bool isSelected, Animation<double> animation) {
     return _TabStyle(
       animation: animation,
-      selected: selected,
+      isSelected: isSelected,
       labelColor: widget.labelColor,
       unselectedLabelColor: widget.unselectedLabelColor,
       labelStyle: widget.labelStyle,
@@ -1368,7 +1429,7 @@
       painter: _indicatorPainter,
       child: _TabStyle(
         animation: kAlwaysDismissedAnimation,
-        selected: false,
+        isSelected: false,
         labelColor: widget.labelColor,
         unselectedLabelColor: widget.unselectedLabelColor,
         labelStyle: widget.labelStyle,
diff --git a/framework/lib/src/material/theme_data.dart b/framework/lib/src/material/theme_data.dart
index cdaf4c0..1f85ff4 100644
--- a/framework/lib/src/material/theme_data.dart
+++ b/framework/lib/src/material/theme_data.dart
@@ -389,13 +389,6 @@
     )
     Color? accentColor,
     @Deprecated(
-      'No longer used by the framework, please remove any reference to it. '
-      'For more information, consult the migration guide at '
-      'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. '
-      'This feature was deprecated after v2.3.0-0.1.pre.',
-    )
-    Brightness? accentColorBrightness,
-    @Deprecated(
       'This "fix" is now enabled by default. '
       'This feature was deprecated after v2.5.0-1.0.pre.',
     )
@@ -486,7 +479,6 @@
       primaryColorBrightness = ThemeData.estimateBrightnessForColor(primarySurfaceColor);
       canvasColor ??= colorScheme.background;
       accentColor ??= colorScheme.secondary;
-      accentColorBrightness ??= ThemeData.estimateBrightnessForColor(colorScheme.secondary);
       scaffoldBackgroundColor ??= colorScheme.background;
       bottomAppBarColor ??= colorScheme.surface;
       cardColor ??= colorScheme.surface;
@@ -506,7 +498,6 @@
     final bool primaryIsDark = estimatedPrimaryColorBrightness == Brightness.dark;
     toggleableActiveColor ??= isDark ? Colors.tealAccent[200]! : (accentColor ?? primarySwatch[600]!);
     accentColor ??= isDark ? Colors.tealAccent[200]! : primarySwatch[500]!;
-    accentColorBrightness ??= estimateBrightnessForColor(accentColor);
     focusColor ??= isDark ? Colors.white.withOpacity(0.12) : Colors.black.withOpacity(0.12);
     hoverColor ??= isDark ? Colors.white.withOpacity(0.04) : Colors.black.withOpacity(0.04);
     shadowColor ??= Colors.black;
@@ -712,7 +703,6 @@
       tooltipTheme: tooltipTheme,
       // DEPRECATED (newest deprecations at the bottom)
       accentColor: accentColor,
-      accentColorBrightness: accentColorBrightness,
       fixTextFieldOutlineLabel: fixTextFieldOutlineLabel,
       primaryColorBrightness: primaryColorBrightness,
       androidOverscrollIndicator: androidOverscrollIndicator,
@@ -831,13 +821,6 @@
     )
     Color? accentColor,
     @Deprecated(
-      'No longer used by the framework, please remove any reference to it. '
-      'For more information, consult the migration guide at '
-      'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. '
-      'This feature was deprecated after v2.3.0-0.1.pre.',
-    )
-    Brightness? accentColorBrightness,
-    @Deprecated(
       'This "fix" is now enabled by default. '
       'This feature was deprecated after v2.5.0-1.0.pre.',
     )
@@ -883,7 +866,6 @@
   }) : // DEPRECATED (newest deprecations at the bottom)
        // should not be `required`, use getter pattern to avoid breakages.
        _accentColor = accentColor,
-       _accentColorBrightness = accentColorBrightness,
        _fixTextFieldOutlineLabel = fixTextFieldOutlineLabel,
        _primaryColorBrightness = primaryColorBrightness,
        _toggleableActiveColor = toggleableActiveColor,
@@ -894,7 +876,6 @@
        assert(toggleableActiveColor != null),
         // DEPRECATED (newest deprecations at the bottom)
        assert(accentColor != null),
-       assert(accentColorBrightness != null),
        assert(fixTextFieldOutlineLabel != null),
        assert(primaryColorBrightness != null),
        assert(errorColor != null),
@@ -946,7 +927,6 @@
       primaryColorBrightness: ThemeData.estimateBrightnessForColor(primarySurfaceColor),
       canvasColor: colorScheme.background,
       accentColor: colorScheme.secondary,
-      accentColorBrightness: ThemeData.estimateBrightnessForColor(colorScheme.secondary),
       scaffoldBackgroundColor: colorScheme.background,
       bottomAppBarColor: colorScheme.surface,
       cardColor: colorScheme.surface,
@@ -1572,23 +1552,6 @@
   Color get accentColor => _accentColor!;
   final Color? _accentColor;
 
-  /// Obsolete property that was originally used to determine the color
-  /// of text and icons placed on top of the accent color (e.g. the
-  /// icons on a floating action button).
-  ///
-  /// The material library no longer uses this property. The
-  /// [floatingActionButtonTheme] can be used to configure
-  /// the appearance of [FloatingActionButton]s. The brightness
-  /// of any color can be found with [ThemeData.estimateBrightnessForColor].
-  @Deprecated(
-    'No longer used by the framework, please remove any reference to it. '
-    'For more information, consult the migration guide at '
-    'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. '
-    'This feature was deprecated after v2.3.0-0.1.pre.',
-  )
-  Brightness get accentColorBrightness => _accentColorBrightness!;
-  final Brightness? _accentColorBrightness;
-
   /// An obsolete flag to allow apps to opt-out of a
   /// [small fix](https://github.com/flutter/flutter/issues/54028) for the Y
   /// coordinate of the floating label in a [TextField] [OutlineInputBorder].
@@ -1781,13 +1744,6 @@
     )
     Color? accentColor,
     @Deprecated(
-      'No longer used by the framework, please remove any reference to it. '
-      'For more information, consult the migration guide at '
-      'https://flutter.dev/docs/release/breaking-changes/theme-data-accent-properties#migration-guide. '
-      'This feature was deprecated after v2.3.0-0.1.pre.',
-    )
-    Brightness? accentColorBrightness,
-    @Deprecated(
       'This "fix" is now enabled by default. '
       'This feature was deprecated after v2.5.0-1.0.pre.',
     )
@@ -1921,7 +1877,6 @@
       tooltipTheme: tooltipTheme ?? this.tooltipTheme,
       // DEPRECATED (newest deprecations at the bottom)
       accentColor: accentColor ?? _accentColor,
-      accentColorBrightness: accentColorBrightness ?? _accentColorBrightness,
       fixTextFieldOutlineLabel: fixTextFieldOutlineLabel ?? _fixTextFieldOutlineLabel,
       primaryColorBrightness: primaryColorBrightness ?? _primaryColorBrightness,
       androidOverscrollIndicator: androidOverscrollIndicator ?? this.androidOverscrollIndicator,
@@ -2113,7 +2068,6 @@
       tooltipTheme: TooltipThemeData.lerp(a.tooltipTheme, b.tooltipTheme, t)!,
       // DEPRECATED (newest deprecations at the bottom)
       accentColor: Color.lerp(a.accentColor, b.accentColor, t),
-      accentColorBrightness: t < 0.5 ? a.accentColorBrightness : b.accentColorBrightness,
       fixTextFieldOutlineLabel: t < 0.5 ? a.fixTextFieldOutlineLabel : b.fixTextFieldOutlineLabel,
       primaryColorBrightness: t < 0.5 ? a.primaryColorBrightness : b.primaryColorBrightness,
       androidOverscrollIndicator:t < 0.5 ? a.androidOverscrollIndicator : b.androidOverscrollIndicator,
@@ -2220,7 +2174,6 @@
         other.tooltipTheme == tooltipTheme &&
         // DEPRECATED (newest deprecations at the bottom)
         other.accentColor == accentColor &&
-        other.accentColorBrightness == accentColorBrightness &&
         other.fixTextFieldOutlineLabel == fixTextFieldOutlineLabel &&
         other.primaryColorBrightness == primaryColorBrightness &&
         other.androidOverscrollIndicator == androidOverscrollIndicator &&
@@ -2324,7 +2277,6 @@
       tooltipTheme,
       // DEPRECATED (newest deprecations at the bottom)
       accentColor,
-      accentColorBrightness,
       fixTextFieldOutlineLabel,
       primaryColorBrightness,
       androidOverscrollIndicator,
@@ -2430,7 +2382,6 @@
     properties.add(DiagnosticsProperty<TooltipThemeData>('tooltipTheme', tooltipTheme, level: DiagnosticLevel.debug));
     // DEPRECATED (newest deprecations at the bottom)
     properties.add(ColorProperty('accentColor', accentColor, defaultValue: defaultData.accentColor, level: DiagnosticLevel.debug));
-    properties.add(EnumProperty<Brightness>('accentColorBrightness', accentColorBrightness, defaultValue: defaultData.accentColorBrightness, level: DiagnosticLevel.debug));
     properties.add(DiagnosticsProperty<bool>('fixTextFieldOutlineLabel', fixTextFieldOutlineLabel, level: DiagnosticLevel.debug));
     properties.add(EnumProperty<Brightness>('primaryColorBrightness', primaryColorBrightness, defaultValue: defaultData.primaryColorBrightness, level: DiagnosticLevel.debug));
     properties.add(EnumProperty<AndroidOverscrollIndicator>('androidOverscrollIndicator', androidOverscrollIndicator, defaultValue: null, level: DiagnosticLevel.debug));
diff --git a/framework/lib/src/painting/shader_warm_up.dart b/framework/lib/src/painting/shader_warm_up.dart
index 8da3379..d7d7df5 100644
--- a/framework/lib/src/painting/shader_warm_up.dart
+++ b/framework/lib/src/painting/shader_warm_up.dart
@@ -69,10 +69,10 @@
   ///
   /// To decide which draw operations to be added to your custom warm up
   /// process, consider capturing an skp using `flutter screenshot
-  /// --observatory-uri=<uri> --type=skia` and analyzing it with
+  /// --vm-service-uri=<uri> --type=skia` and analyzing it with
   /// <https://debugger.skia.org/>. Alternatively, one may run the app with
   /// `flutter run --trace-skia` and then examine the raster thread in the
-  /// observatory timeline to see which Skia draw operations are commonly used,
+  /// Flutter DevTools timeline to see which Skia draw operations are commonly used,
   /// and which shader compilations are causing jank.
   @protected
   Future<void> warmUpOnCanvas(ui.Canvas canvas);
diff --git a/framework/lib/src/rendering/proxy_box.dart b/framework/lib/src/rendering/proxy_box.dart
index 8f54447..f38f77f 100644
--- a/framework/lib/src/rendering/proxy_box.dart
+++ b/framework/lib/src/rendering/proxy_box.dart
@@ -53,8 +53,10 @@
 ///
 /// Use this mixin in situations where the proxying behavior
 /// of [RenderProxyBox] is desired but inheriting from [RenderProxyBox] is
-/// impractical (e.g. because you want to mix in other classes as well).
-// TODO(ianh): Remove this class once https://github.com/dart-lang/sdk/issues/31543 is fixed
+/// impractical (e.g. because you want to inherit from a different class).
+///
+/// If a class already inherits from [RenderProxyBox] and also uses this mixin,
+/// you can safely delete the use of the mixin.
 @optionalTypeArgs
 mixin RenderProxyBoxMixin<T extends RenderBox> on RenderBox, RenderObjectWithChildMixin<T> {
   @override
@@ -1095,7 +1097,7 @@
 ///
 /// This is a variant of [RenderOpacity] that uses an [Animation<double>] rather
 /// than a [double] to control the opacity.
-class RenderAnimatedOpacity extends RenderProxyBox with RenderProxyBoxMixin, RenderAnimatedOpacityMixin<RenderBox> {
+class RenderAnimatedOpacity extends RenderProxyBox with RenderAnimatedOpacityMixin<RenderBox> {
   /// Creates a partially transparent render object.
   ///
   /// The [opacity] argument must not be null.
diff --git a/framework/lib/src/services/platform_views.dart b/framework/lib/src/services/platform_views.dart
index 6229559..7825904 100644
--- a/framework/lib/src/services/platform_views.dart
+++ b/framework/lib/src/services/platform_views.dart
@@ -863,7 +863,7 @@
   Future<void> setLayoutDirection(TextDirection layoutDirection) async {
     assert(
       _state != _AndroidViewState.disposed,
-      'trying to set a layout direction for a disposed UIView. View id: $viewId',
+      'trying to set a layout direction for a disposed Android view. View id: $viewId',
     );
 
     if (layoutDirection == _layoutDirection) {
@@ -938,12 +938,13 @@
   /// disposed.
   @override
   Future<void> dispose() async {
-    if (_state == _AndroidViewState.creating || _state == _AndroidViewState.created) {
+    final _AndroidViewState state = _state;
+    _state = _AndroidViewState.disposed;
+    _platformViewCreatedCallbacks.clear();
+    PlatformViewsService._instance._focusCallbacks.remove(viewId);
+    if (state == _AndroidViewState.creating || state == _AndroidViewState.created) {
       await _sendDisposeMessage();
     }
-    _platformViewCreatedCallbacks.clear();
-    _state = _AndroidViewState.disposed;
-    PlatformViewsService._instance._focusCallbacks.remove(viewId);
   }
 }
 
diff --git a/framework/lib/src/services/system_chrome.dart b/framework/lib/src/services/system_chrome.dart
index e37f78b..6b0ed70 100644
--- a/framework/lib/src/services/system_chrome.dart
+++ b/framework/lib/src/services/system_chrome.dart
@@ -72,7 +72,7 @@
 
 /// Specifies a system overlay at a particular location.
 ///
-/// Used by [SystemChrome.setEnabledSystemUIOverlays].
+/// Used by [SystemChrome.setEnabledSystemUIMode].
 enum SystemUiOverlay {
   /// The status bar provided by the embedder on the top of the application
   /// surface, if any.
@@ -400,36 +400,6 @@
     );
   }
 
-  /// Specifies the set of system overlays to have visible when the application
-  /// is running.
-  ///
-  /// The `overlays` argument is a list of [SystemUiOverlay] enum values
-  /// denoting the overlays to show.
-  ///
-  /// If a particular overlay is unsupported on the platform, enabling or
-  /// disabling that overlay will be ignored.
-  ///
-  /// The settings here can be overridden by the platform when System UI becomes
-  /// necessary for functionality.
-  ///
-  /// For example, on Android, when the keyboard becomes visible, it will enable the
-  /// navigation bar and status bar system UI overlays. When the keyboard is closed,
-  /// Android will not restore the previous UI visibility settings, and the UI
-  /// visibility cannot be changed until 1 second after the keyboard is closed to
-  /// prevent malware locking users from navigation buttons.
-  ///
-  /// To regain "fullscreen" after text entry, the UI overlays should be set again
-  /// after a delay of 1 second. This can be achieved through [restoreSystemUIOverlays]
-  /// or calling this again. Otherwise, the original UI overlay settings will be
-  /// automatically restored only when the application loses and regains focus.
-  @Deprecated(
-    'Migrate to setEnabledSystemUIMode. '
-    'This feature was deprecated after v2.3.0-17.0.pre.'
-  )
-  static Future<void> setEnabledSystemUIOverlays(List<SystemUiOverlay> overlays) async {
-    await setEnabledSystemUIMode(SystemUiMode.manual, overlays: overlays);
-  }
-
   /// Specifies the [SystemUiMode] to have visible when the application
   /// is running.
   ///
@@ -508,7 +478,7 @@
   }
 
   /// Restores the system overlays to the last settings provided via
-  /// [setEnabledSystemUIOverlays]. May be used when the platform force enables/disables
+  /// [setEnabledSystemUIMode]. May be used when the platform force enables/disables
   /// UI elements.
   ///
   /// For example, when the Android keyboard disables hidden status and navigation bars,
@@ -534,10 +504,10 @@
   /// system UI styles. For instance, to change the system UI style on a new
   /// page, consider calling when pushing/popping a new [PageRoute].
   ///
-  /// However, the [AppBar] widget automatically sets the system overlay style
-  /// based on its [AppBar.brightness], so configure that instead of calling
-  /// this method directly. Likewise, do the same for [CupertinoNavigationBar]
-  /// via [CupertinoNavigationBar.backgroundColor].
+  /// The [AppBar] widget automatically sets the system overlay style based on
+  /// its [AppBar.systemOverlayStyle], so configure that instead of calling this
+  /// method directly. Likewise, do the same for [CupertinoNavigationBar] via
+  /// [CupertinoNavigationBar.backgroundColor].
   ///
   /// If a particular style is not supported on the platform, selecting it will
   /// have no effect.
diff --git a/framework/lib/src/services/text_boundary.dart b/framework/lib/src/services/text_boundary.dart
index efbea24..4e2414e 100644
--- a/framework/lib/src/services/text_boundary.dart
+++ b/framework/lib/src/services/text_boundary.dart
@@ -150,17 +150,16 @@
       return 0;
     }
 
-    final List<int> codeUnits = _text.codeUnits;
     int index = position;
 
-    if (index > 1 && codeUnits[index] == 0xA && codeUnits[index - 1] == 0xD) {
+    if (index > 1 && _text.codeUnitAt(index) == 0x0A && _text.codeUnitAt(index - 1) == 0x0D) {
       index -= 2;
-    } else if (TextLayoutMetrics.isLineTerminator(codeUnits[index])) {
+    } else if (TextLayoutMetrics.isLineTerminator(_text.codeUnitAt(index))) {
       index -= 1;
     }
 
     while (index > 0) {
-      if (TextLayoutMetrics.isLineTerminator(codeUnits[index])) {
+      if (TextLayoutMetrics.isLineTerminator(_text.codeUnitAt(index))) {
         return index + 1;
       }
       index -= 1;
@@ -183,19 +182,18 @@
       return 0;
     }
 
-    final List<int> codeUnits = _text.codeUnits;
     int index = position;
 
-    while (!TextLayoutMetrics.isLineTerminator(codeUnits[index])) {
+    while (!TextLayoutMetrics.isLineTerminator(_text.codeUnitAt(index))) {
       index += 1;
-      if (index == codeUnits.length) {
+      if (index == _text.length) {
         return index;
       }
     }
 
-    return index < codeUnits.length - 1
-                && codeUnits[index] == 0xD
-                && codeUnits[index + 1] == 0xA
+    return index < _text.length - 1
+                && _text.codeUnitAt(index) == 0x0D
+                && _text.codeUnitAt(index + 1) == 0x0A
                 ? index + 2
                 : index + 1;
   }
diff --git a/framework/lib/src/services/text_layout_metrics.dart b/framework/lib/src/services/text_layout_metrics.dart
index 6ae774a..ab23137 100644
--- a/framework/lib/src/services/text_layout_metrics.dart
+++ b/framework/lib/src/services/text_layout_metrics.dart
@@ -60,10 +60,10 @@
   /// (https://www.unicode.org/standard/reports/tr13/tr13-5.html).
   static bool isLineTerminator(int codeUnit) {
     switch (codeUnit) {
-      case 0xA: // line feed
-      case 0xB: // vertical feed
-      case 0xC: // form feed
-      case 0xD: // carriage return
+      case 0x0A: // line feed
+      case 0x0B: // vertical feed
+      case 0x0C: // form feed
+      case 0x0D: // carriage return
       case 0x85: // new line
       case 0x2028: // line separator
       case 0x2029: // paragraph separator
diff --git a/framework/lib/src/widgets/app.dart b/framework/lib/src/widgets/app.dart
index 1791729..a5f6449 100644
--- a/framework/lib/src/widgets/app.dart
+++ b/framework/lib/src/widgets/app.dart
@@ -1174,7 +1174,7 @@
 
   /// If true, forces the performance overlay to be visible in all instances.
   ///
-  /// Used by the `showPerformanceOverlay` observatory extension.
+  /// Used by the `showPerformanceOverlay` VM service extension.
   static bool showPerformanceOverlayOverride = false;
 
   /// If true, forces the widget inspector to be visible.
@@ -1184,12 +1184,12 @@
   /// The inspector allows you to select a location on your device or emulator
   /// and view what widgets and render objects associated with it. An outline of
   /// the selected widget and some summary information is shown on device and
-  /// more detailed information is shown in the IDE or Observatory.
+  /// more detailed information is shown in the IDE or DevTools.
   static bool debugShowWidgetInspectorOverride = false;
 
   /// If false, prevents the debug banner from being visible.
   ///
-  /// Used by the `debugAllowBanner` observatory extension.
+  /// Used by the `debugAllowBanner` VM service extension.
   ///
   /// This is how `flutter run` turns off the banner when you take a screen shot
   /// with "s".
@@ -1623,6 +1623,7 @@
         debugLabel: 'Navigator Scope',
         autofocus: true,
         child: Navigator(
+          clipBehavior: Clip.none,
           restorationScopeId: 'nav',
           key: _navigator,
           initialRoute: _initialRouteName,
diff --git a/framework/lib/src/widgets/debug.dart b/framework/lib/src/widgets/debug.dart
index 6ac04f9..d401f2d 100644
--- a/framework/lib/src/widgets/debug.dart
+++ b/framework/lib/src/widgets/debug.dart
@@ -33,8 +33,8 @@
 /// Combined with [debugPrintScheduleBuildForStacks], this lets you watch a
 /// widget's dirty/clean lifecycle.
 ///
-/// To get similar information but showing it on the timeline available from the
-/// Observatory rather than getting it in the console (where it can be
+/// To get similar information but showing it on the timeline available from
+/// Flutter DevTools rather than getting it in the console (where it can be
 /// overwhelming), consider [debugProfileBuildsEnabled].
 ///
 /// See also:
diff --git a/framework/lib/src/widgets/default_text_editing_shortcuts.dart b/framework/lib/src/widgets/default_text_editing_shortcuts.dart
index ae75678..edee66f 100644
--- a/framework/lib/src/widgets/default_text_editing_shortcuts.dart
+++ b/framework/lib/src/widgets/default_text_editing_shortcuts.dart
@@ -207,6 +207,9 @@
     const SingleActivator(LogicalKeyboardKey.arrowLeft, shift: true, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: false, collapseSelection: false),
     const SingleActivator(LogicalKeyboardKey.arrowRight, shift: true, control: true): const ExtendSelectionToNextWordBoundaryIntent(forward: true, collapseSelection: false),
 
+    const SingleActivator(LogicalKeyboardKey.arrowUp, shift: true, control: true): const ExtendSelectionToNextParagraphBoundaryIntent(forward: false, collapseSelection: false),
+    const SingleActivator(LogicalKeyboardKey.arrowDown, shift: true, control: true): const ExtendSelectionToNextParagraphBoundaryIntent(forward: true, collapseSelection: false),
+
     // Page Up / Down: Move selection by page.
     const SingleActivator(LogicalKeyboardKey.pageUp): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: false, collapseSelection: true),
     const SingleActivator(LogicalKeyboardKey.pageDown): const ExtendSelectionVerticallyToAdjacentPageIntent(forward: true, collapseSelection: true),
diff --git a/framework/lib/src/widgets/editable_text.dart b/framework/lib/src/widgets/editable_text.dart
index 95353e9..02093ae 100644
--- a/framework/lib/src/widgets/editable_text.dart
+++ b/framework/lib/src/widgets/editable_text.dart
@@ -3463,11 +3463,9 @@
         );
       } else {
         _scrollController.jumpTo(targetOffset.offset);
-        if (_value.selection.isCollapsed) {
-          renderEditable.showOnScreen(
-            rect: caretPadding.inflateRect(rectToReveal),
-          );
-        }
+        renderEditable.showOnScreen(
+          rect: caretPadding.inflateRect(rectToReveal),
+        );
       }
     });
   }
@@ -4424,6 +4422,7 @@
     ExtendSelectionByCharacterIntent: _makeOverridable(_UpdateTextSelectionAction<ExtendSelectionByCharacterIntent>(this, _characterBoundary, _moveBeyondTextBoundary, ignoreNonCollapsedSelection: false)),
     ExtendSelectionByPageIntent: _makeOverridable(CallbackAction<ExtendSelectionByPageIntent>(onInvoke: _extendSelectionByPage)),
     ExtendSelectionToNextWordBoundaryIntent: _makeOverridable(_UpdateTextSelectionAction<ExtendSelectionToNextWordBoundaryIntent>(this, _nextWordBoundary, _moveBeyondTextBoundary, ignoreNonCollapsedSelection: true)),
+    ExtendSelectionToNextParagraphBoundaryIntent : _makeOverridable(_UpdateTextSelectionAction<ExtendSelectionToNextParagraphBoundaryIntent>(this, _paragraphBoundary, _moveBeyondTextBoundary, ignoreNonCollapsedSelection: true)),
     ExtendSelectionToLineBreakIntent: _makeOverridable(_UpdateTextSelectionAction<ExtendSelectionToLineBreakIntent>(this, _linebreak, _moveToTextBoundary, ignoreNonCollapsedSelection: true)),
     ExtendSelectionVerticallyToAdjacentLineIntent: _makeOverridable(_verticalSelectionUpdateAction),
     ExtendSelectionVerticallyToAdjacentPageIntent: _makeOverridable(_verticalSelectionUpdateAction),
diff --git a/framework/lib/src/widgets/gesture_detector.dart b/framework/lib/src/widgets/gesture_detector.dart
index 42adfac..21c413b 100644
--- a/framework/lib/src/widgets/gesture_detector.dart
+++ b/framework/lib/src/widgets/gesture_detector.dart
@@ -1050,7 +1050,8 @@
             ..onTertiaryTapDown = onTertiaryTapDown
             ..onTertiaryTapUp = onTertiaryTapUp
             ..onTertiaryTapCancel = onTertiaryTapCancel
-            ..gestureSettings = gestureSettings;
+            ..gestureSettings = gestureSettings
+            ..supportedDevices = supportedDevices;
         },
       );
     }
@@ -1065,7 +1066,8 @@
             ..onDoubleTapDown = onDoubleTapDown
             ..onDoubleTap = onDoubleTap
             ..onDoubleTapCancel = onDoubleTapCancel
-            ..gestureSettings = gestureSettings;
+            ..gestureSettings = gestureSettings
+            ..supportedDevices = supportedDevices;
         },
       );
     }
@@ -1116,7 +1118,8 @@
             ..onTertiaryLongPressMoveUpdate = onTertiaryLongPressMoveUpdate
             ..onTertiaryLongPressUp = onTertiaryLongPressUp
             ..onTertiaryLongPressEnd = onTertiaryLongPressEnd
-            ..gestureSettings = gestureSettings;
+            ..gestureSettings = gestureSettings
+            ..supportedDevices = supportedDevices;
         },
       );
     }
@@ -1136,7 +1139,8 @@
             ..onEnd = onVerticalDragEnd
             ..onCancel = onVerticalDragCancel
             ..dragStartBehavior = dragStartBehavior
-            ..gestureSettings = gestureSettings;
+            ..gestureSettings = gestureSettings
+            ..supportedDevices = supportedDevices;
         },
       );
     }
@@ -1156,7 +1160,8 @@
             ..onEnd = onHorizontalDragEnd
             ..onCancel = onHorizontalDragCancel
             ..dragStartBehavior = dragStartBehavior
-            ..gestureSettings = gestureSettings;
+            ..gestureSettings = gestureSettings
+            ..supportedDevices = supportedDevices;
         },
       );
     }
@@ -1176,7 +1181,8 @@
             ..onEnd = onPanEnd
             ..onCancel = onPanCancel
             ..dragStartBehavior = dragStartBehavior
-            ..gestureSettings = gestureSettings;
+            ..gestureSettings = gestureSettings
+            ..supportedDevices = supportedDevices;
         },
       );
     }
@@ -1192,7 +1198,8 @@
             ..dragStartBehavior = dragStartBehavior
             ..gestureSettings = gestureSettings
             ..trackpadScrollCausesScale = trackpadScrollCausesScale
-            ..trackpadScrollToScaleFactor = trackpadScrollToScaleFactor;
+            ..trackpadScrollToScaleFactor = trackpadScrollToScaleFactor
+            ..supportedDevices = supportedDevices;
         },
       );
     }
@@ -1209,7 +1216,8 @@
             ..onPeak = onForcePressPeak
             ..onUpdate = onForcePressUpdate
             ..onEnd = onForcePressEnd
-            ..gestureSettings = gestureSettings;
+            ..gestureSettings = gestureSettings
+            ..supportedDevices = supportedDevices;
         },
       );
     }
diff --git a/framework/lib/src/widgets/overlay.dart b/framework/lib/src/widgets/overlay.dart
index d3cd0de..f1629c9 100644
--- a/framework/lib/src/widgets/overlay.dart
+++ b/framework/lib/src/widgets/overlay.dart
@@ -702,8 +702,6 @@
     addAll(children);
   }
 
-  bool _hasVisualOverflow = false;
-
   @override
   void setupParentData(RenderBox child) {
     if (child.parentData is! StackParentData) {
@@ -827,8 +825,6 @@
 
   @override
   void performLayout() {
-    _hasVisualOverflow = false;
-
     if (_onstageChildCount == 0) {
       return;
     }
@@ -847,7 +843,7 @@
         child.layout(nonPositionedConstraints, parentUsesSize: true);
         childParentData.offset = _resolvedAlignment!.alongOffset(size - child.size as Offset);
       } else {
-        _hasVisualOverflow = RenderStack.layoutPositionedChild(child, childParentData, size, _resolvedAlignment!) || _hasVisualOverflow;
+        RenderStack.layoutPositionedChild(child, childParentData, size, _resolvedAlignment!);
       }
 
       assert(child.parentData == childParentData);
@@ -889,7 +885,7 @@
 
   @override
   void paint(PaintingContext context, Offset offset) {
-    if (_hasVisualOverflow && clipBehavior != Clip.none) {
+    if (clipBehavior != Clip.none) {
       _clipRectLayer.layer = context.pushClipRect(
         needsCompositing,
         offset,
@@ -930,7 +926,7 @@
       case Clip.hardEdge:
       case Clip.antiAlias:
       case Clip.antiAliasWithSaveLayer:
-        return _hasVisualOverflow ? Offset.zero & size : null;
+        return Offset.zero & size;
     }
   }
 
diff --git a/framework/lib/src/widgets/overscroll_indicator.dart b/framework/lib/src/widgets/overscroll_indicator.dart
index eae45a3..272d089 100644
--- a/framework/lib/src/widgets/overscroll_indicator.dart
+++ b/framework/lib/src/widgets/overscroll_indicator.dart
@@ -601,6 +601,15 @@
   }
 }
 
+enum _StretchDirection {
+  /// The [trailing] direction indicates that the content will be stretched toward
+  /// the trailing edge.
+  trailing,
+  /// The [leading] direction indicates that the content will be stretched toward
+  /// the leading edge.
+  leading,
+}
+
 /// A Material Design visual indication that a scroll view has overscrolled.
 ///
 /// A [StretchingOverscrollIndicator] listens for [ScrollNotification]s in order
@@ -689,6 +698,9 @@
   late final _StretchController _stretchController = _StretchController(vsync: this);
   ScrollNotification? _lastNotification;
   OverscrollNotification? _lastOverscrollNotification;
+
+  double _totalOverscroll = 0.0;
+
   bool _accepted = true;
 
   bool _handleScrollNotification(ScrollNotification notification) {
@@ -706,9 +718,11 @@
 
       assert(notification.metrics.axis == widget.axis);
       if (_accepted) {
+        _totalOverscroll += notification.overscroll;
+
         if (notification.velocity != 0.0) {
           assert(notification.dragDetails == null);
-          _stretchController.absorbImpact(notification.velocity.abs());
+          _stretchController.absorbImpact(notification.velocity.abs(), _totalOverscroll);
         } else {
           assert(notification.overscroll != 0.0);
           if (notification.dragDetails != null) {
@@ -716,38 +730,40 @@
             // which is the furthest distance a single pointer could pull on the
             // screen. This is because more than one pointer will multiply the
             // amount of overscroll - https://github.com/flutter/flutter/issues/11884
+
             final double viewportDimension = notification.metrics.viewportDimension;
-            final double distanceForPull =
-              (notification.overscroll.abs() / viewportDimension) + _stretchController.pullDistance;
+            final double distanceForPull = _totalOverscroll.abs() / viewportDimension;
             final double clampedOverscroll = clampDouble(distanceForPull, 0, 1.0);
-            _stretchController.pull(clampedOverscroll);
+            _stretchController.pull(clampedOverscroll, _totalOverscroll);
           }
         }
       }
     } else if (notification is ScrollEndNotification || notification is ScrollUpdateNotification) {
+      // Since the overscrolling ended, we reset the total overscroll amount.
+      _totalOverscroll = 0;
       _stretchController.scrollEnd();
     }
     _lastNotification = notification;
     return false;
   }
 
-  AlignmentGeometry _getAlignmentForAxisDirection(double overscroll) {
+  AlignmentGeometry _getAlignmentForAxisDirection(_StretchDirection stretchDirection) {
     // Accounts for reversed scrollables by checking the AxisDirection
     switch (widget.axisDirection) {
       case AxisDirection.up:
-        return overscroll > 0
+        return stretchDirection == _StretchDirection.trailing
             ? AlignmentDirectional.topCenter
             : AlignmentDirectional.bottomCenter;
       case AxisDirection.right:
-        return overscroll > 0
+        return stretchDirection == _StretchDirection.trailing
             ? Alignment.centerRight
             : Alignment.centerLeft;
       case AxisDirection.down:
-        return overscroll > 0
+        return stretchDirection == _StretchDirection.trailing
             ? AlignmentDirectional.bottomCenter
             : AlignmentDirectional.topCenter;
       case AxisDirection.left:
-        return overscroll > 0
+        return stretchDirection == _StretchDirection.trailing
             ? Alignment.centerLeft
             : Alignment.centerRight;
     }
@@ -784,7 +800,7 @@
           }
 
           final AlignmentGeometry alignment = _getAlignmentForAxisDirection(
-            _lastOverscrollNotification?.overscroll ?? 0.0
+            _stretchController.stretchDirection,
           );
 
           final double viewportDimension = _lastOverscrollNotification?.metrics.viewportDimension ?? mainAxisSize;
@@ -836,6 +852,9 @@
   double get pullDistance => _pullDistance;
   double _pullDistance = 0.0;
 
+  _StretchDirection get stretchDirection => _stretchDirection;
+  _StretchDirection _stretchDirection = _StretchDirection.trailing;
+
   // Constants from Android.
   static const double _exponentialScalar = math.e / 0.33;
   static const double _stretchIntensity = 0.016;
@@ -847,7 +866,7 @@
   /// Handle a fling to the edge of the viewport at a particular velocity.
   ///
   /// The velocity must be positive.
-  void absorbImpact(double velocity) {
+  void absorbImpact(double velocity, double totalOverscroll) {
     assert(velocity >= 0.0);
     velocity = clampDouble(velocity, 1, 10000);
     _stretchSizeTween.begin = _stretchSize.value;
@@ -855,6 +874,7 @@
     _stretchController.duration = Duration(milliseconds: (velocity * 0.02).round());
     _stretchController.forward(from: 0.0);
     _state = _StretchState.absorb;
+    _stretchDirection = totalOverscroll > 0 ? _StretchDirection.trailing : _StretchDirection.leading;
   }
 
   /// Handle a user-driven overscroll.
@@ -862,8 +882,19 @@
   /// The `normalizedOverscroll` argument should be the absolute value of the
   /// scroll distance in logical pixels, divided by the extent of the viewport
   /// in the main axis.
-  void pull(double normalizedOverscroll) {
+  void pull(double normalizedOverscroll, double totalOverscroll) {
     assert(normalizedOverscroll >= 0.0);
+
+    final _StretchDirection newStretchDirection = totalOverscroll > 0 ? _StretchDirection.trailing : _StretchDirection.leading;
+    if (_stretchDirection != newStretchDirection && _state == _StretchState.recede) {
+      // When the stretch direction changes while we are in the recede state, we need to ignore the change.
+      // If we don't, the stretch will instantly jump to the new direction with the recede animation still playing, which causes
+      // a unwanted visual abnormality (https://github.com/flutter/flutter/pull/116548#issuecomment-1414872567).
+      // By ignoring the directional change until the recede state is finished, we can avoid this.
+      return;
+    }
+
+    _stretchDirection = newStretchDirection;
     _pullDistance = normalizedOverscroll;
     _stretchSizeTween.begin = _stretchSize.value;
     final double linearIntensity =_stretchIntensity * _pullDistance;
diff --git a/framework/lib/src/widgets/platform_view.dart b/framework/lib/src/widgets/platform_view.dart
index a18f7cc..2513191 100644
--- a/framework/lib/src/widgets/platform_view.dart
+++ b/framework/lib/src/widgets/platform_view.dart
@@ -485,7 +485,7 @@
     _layoutDirection = newLayoutDirection;
 
     if (widget.viewType != oldWidget.viewType) {
-      _controller.dispose();
+      _controller.disposePostFrame();
       _createNewAndroidView();
       return;
     }
@@ -890,7 +890,7 @@
     super.didUpdateWidget(oldWidget);
 
     if (widget.viewType != oldWidget.viewType) {
-      _controller?.dispose();
+      _controller?.disposePostFrame();
       // The _surface has to be recreated as its controller is disposed.
       // Setting _surface to null will trigger its creation in build().
       _surface = null;
@@ -911,9 +911,11 @@
   }
 
   void _onPlatformViewCreated(int id) {
-    setState(() {
-      _platformViewCreated = true;
-    });
+    if (mounted) {
+      setState(() {
+        _platformViewCreated = true;
+      });
+    }
   }
 
   void _handleFrameworkFocusChanged(bool isFocused) {
@@ -1209,3 +1211,13 @@
     renderObject.onLayout = onLayout;
   }
 }
+
+extension on PlatformViewController {
+  /// Disposes the controller in a post-frame callback, to allow other widgets to
+  /// remove their listeners before the controller is disposed.
+  void disposePostFrame() {
+    SchedulerBinding.instance.addPostFrameCallback((_) {
+      dispose();
+    });
+  }
+}
diff --git a/framework/lib/src/widgets/scrollable.dart b/framework/lib/src/widgets/scrollable.dart
index 9a3ae7c..57ff081 100644
--- a/framework/lib/src/widgets/scrollable.dart
+++ b/framework/lib/src/widgets/scrollable.dart
@@ -630,7 +630,8 @@
                   ..maxFlingVelocity = _physics?.maxFlingVelocity
                   ..velocityTrackerBuilder = _configuration.velocityTrackerBuilder(context)
                   ..dragStartBehavior = widget.dragStartBehavior
-                  ..gestureSettings = _mediaQueryGestureSettings;
+                  ..gestureSettings = _mediaQueryGestureSettings
+                  ..supportedDevices = _configuration.dragDevices;
               },
             ),
           };
@@ -651,7 +652,8 @@
                   ..maxFlingVelocity = _physics?.maxFlingVelocity
                   ..velocityTrackerBuilder = _configuration.velocityTrackerBuilder(context)
                   ..dragStartBehavior = widget.dragStartBehavior
-                  ..gestureSettings = _mediaQueryGestureSettings;
+                  ..gestureSettings = _mediaQueryGestureSettings
+                  ..supportedDevices = _configuration.dragDevices;
               },
             ),
           };
diff --git a/framework/lib/src/widgets/text_editing_intents.dart b/framework/lib/src/widgets/text_editing_intents.dart
index 80b2588..2d7143a 100644
--- a/framework/lib/src/widgets/text_editing_intents.dart
+++ b/framework/lib/src/widgets/text_editing_intents.dart
@@ -223,10 +223,23 @@
 
 /// Extends, or moves the current selection from the current
 /// [TextSelection.extent] position to the previous or the next paragraph
+/// boundary.
+class ExtendSelectionToNextParagraphBoundaryIntent extends DirectionalCaretMovementIntent {
+  /// Creates an [ExtendSelectionToNextParagraphBoundaryIntent].
+  const ExtendSelectionToNextParagraphBoundaryIntent({
+    required bool forward,
+    required bool collapseSelection,
+  }) : super(forward, collapseSelection);
+}
+
+/// Extends, or moves the current selection from the current
+/// [TextSelection.extent] position to the previous or the next paragraph
 /// boundary depending on the [forward] parameter.
 ///
-/// This [Intent] collapses the selection when the order of [TextSelection.base]
-/// and [TextSelection.extent] would reverse.
+/// This [Intent] typically has the same effect as an
+/// [ExtendSelectionToNextParagraphBoundaryIntent], except it collapses the selection
+/// when the order of [TextSelection.base] and [TextSelection.extent] would
+/// reverse.
 ///
 /// This is typically only used on MacOS.
 class ExtendSelectionToNextParagraphBoundaryOrCaretLocationIntent extends DirectionalCaretMovementIntent {
diff --git a/framework/lib/src/widgets/widget_inspector.dart b/framework/lib/src/widgets/widget_inspector.dart
index ee4922e..f8d557f 100644
--- a/framework/lib/src/widgets/widget_inspector.dart
+++ b/framework/lib/src/widgets/widget_inspector.dart
@@ -23,6 +23,7 @@
 import 'package:flute/foundation.dart';
 import 'package:flute/rendering.dart';
 import 'package:flute/scheduler.dart';
+import 'package:meta/meta_meta.dart';
 
 import 'app.dart';
 import 'basic.dart';
@@ -702,7 +703,7 @@
 /// operation making it easier to avoid memory leaks.
 ///
 /// All methods in this class are appropriate to invoke from debugging tools
-/// using the Observatory service protocol to evaluate Dart expressions of the
+/// using the VM service protocol to evaluate Dart expressions of the
 /// form `WidgetInspectorService.instance.methodName(arg1, arg2, ...)`. If you
 /// make changes to any instance method of this class you need to verify that
 /// the [Flutter IntelliJ Plugin](https://github.com/flutter/flutter-intellij/blob/master/README.md)
@@ -711,7 +712,7 @@
 /// All methods returning String values return JSON.
 mixin WidgetInspectorService {
   /// Ring of cached JSON values to prevent JSON from being garbage
-  /// collected before it can be requested over the Observatory protocol.
+  /// collected before it can be requested over the VM service protocol.
   final List<String?> _serializeRing = List<String?>.filled(20, null);
   int _serializeRingIndex = 0;
 
@@ -738,7 +739,7 @@
   /// when the inspection target changes on device.
   InspectorSelectionChangedCallback? selectionChangedCallback;
 
-  /// The Observatory protocol does not keep alive object references so this
+  /// The VM service protocol does not keep alive object references so this
   /// class needs to manually manage groups of objects that should be kept
   /// alive.
   final Map<String, Set<_InspectorReferenceData>> _groups = <String, Set<_InspectorReferenceData>>{};
@@ -1689,7 +1690,7 @@
 
   /// Wrapper around `json.encode` that uses a ring of cached values to prevent
   /// the Dart garbage collector from collecting objects between when
-  /// the value is returned over the Observatory protocol and when the
+  /// the value is returned over the VM service protocol and when the
   /// separate observatory protocol command has to be used to retrieve its full
   /// contents.
   //
@@ -2455,7 +2456,10 @@
       return;
     }
     final _HasCreationLocation creationLocationSource = widget;
-    final _Location location = creationLocationSource._location;
+    final _Location? location = creationLocationSource._location;
+    if (location == null) {
+      return;
+    }
     final int id = _toLocationId(location);
 
     _LocationCount entry;
@@ -3279,7 +3283,7 @@
 /// {@macro flutter.widgets.WidgetInspectorService.getChildrenSummaryTree}
 // ignore: unused_element
 abstract class _HasCreationLocation {
-  _Location get _location;
+  _Location? get _location;
 }
 
 /// A tuple with file, line, and column number, for displaying human-readable
@@ -3681,3 +3685,68 @@
     );
   }
 }
+
+@Target(<TargetKind>{TargetKind.method})
+class _WidgetFactory {
+  const _WidgetFactory();
+}
+
+/// Annotation which marks a function as a widget factory for the purpose of
+/// widget creation tracking.
+///
+/// When widget creation tracking is enabled, the framework tracks the source
+/// code location of the constructor call for each widget instance. This
+/// information is used by the DevTools to provide an improved developer
+/// experience. For example, it allows the Flutter inspector to present the
+/// widget tree in a manner similar to how the UI was defined in your source
+/// code.
+///
+/// [Widget] constructors are automatically instrumented to track the source
+/// code location of constructor calls. However, there are cases where
+/// a function acts as a sort of a constructor for a widget and a call to such
+/// a function should be considered as the creation location for the returned
+/// widget instance.
+///
+/// Annotating a function with this annotation marks the function as a widget
+/// factory. The framework will then instrument that function in the same way
+/// as it does for [Widget] constructors.
+///
+/// Note that the function **must not** have optional positional parameters for
+/// tracking to work correctly.
+///
+/// Currently this annotation is only supported on extension methods.
+///
+/// {@tool snippet}
+///
+/// This example shows how to use the [widgetFactory] annotation to mark an
+/// extension method as a widget factory:
+///
+/// ```dart
+/// extension PaddingModifier on Widget {
+///   @widgetFactory
+///   Widget padding(EdgeInsetsGeometry padding) {
+///     return Padding(padding: padding, child: this);
+///   }
+/// }
+/// ```
+///
+/// When using the above extension method, the framework will track the
+/// creation location of the [Padding] widget instance as the source code
+/// location where the `padding` extension method was called:
+///
+/// ```dart
+/// // continuing from previous example...
+/// const Text('Hello World!')
+///     .padding(const EdgeInsets.all(8));
+/// ```
+///
+/// {@end-tool}
+///
+/// See also:
+///
+/// * the documentation for [Track widget creation](https://docs.flutter.dev/development/tools/devtools/inspector#track-widget-creation).
+// The below ignore is needed because the static type of the annotation is used
+// by the CFE kernel transformer that implements the instrumentation to
+// recognize the annotation.
+// ignore: library_private_types_in_public_api
+const _WidgetFactory widgetFactory = _WidgetFactory();