Fix Selected DropdownMenuItem isn't highlighted on mobile (#167874)

Fix https://github.com/flutter/flutter/issues/70294

### Description

The bug is about the previously selected DropdownMenuItem isn't
highlighted on mobile while it works on Web and desktop. The reason is
that `FocusManager.instance.highlightMode` has fallen to
`FocusHighlightMode.touch` on mobile by default (or touch device without
mouse in general):


https://github.com/flutter/flutter/blob/6f220d3ec0948a4def1622de805fabda9855338d/packages/flutter/lib/src/material/dropdown.dart#L172-L175


https://github.com/flutter/flutter/blob/7d56be4c8de814022357633179a816b51ffca4b8/packages/flutter/lib/src/widgets/focus_manager.dart#L2335-L2353


https://github.com/flutter/flutter/blob/7d56be4c8de814022357633179a816b51ffca4b8/packages/flutter/lib/src/widgets/focus_manager.dart#L1741-L1748

We actually can work around this by setting
`FocusManager.instance.highlightStrategy` to
`FocusHighlightStrategy.alwaysTraditional`, see
https://github.com/flutter/flutter/pull/70442#issuecomment-727036571.
Nevertheless, this approach will may affect the entire scope of the app,
potentially resulting in unforeseen behavior for other widgets. 

In this PR, I propose a straightforward solution that utilizes an
ancestor widget (Ink) to manage the color state corresponding to
`InkWell.overlayColor`.

### Demo the fix


https://github.com/user-attachments/assets/b6476732-716c-4f39-ab82-7ab5accb7182


## Pre-launch Checklist

- [x] I read the [Contributor Guide] and followed the process outlined
there for submitting PRs.
- [x] I read the [Tree Hygiene] wiki page, which explains my
responsibilities.
- [x] I read and followed the [Flutter Style Guide], including [Features
we expect every widget to implement].
- [x] I signed the [CLA].
- [x] I listed at least one issue that this PR fixes in the description
above.
- [x] I updated/added relevant documentation (doc comments with `///`).
- [x] I added new tests to check the change I am making, or this PR is
[test-exempt].
- [x] I followed the [breaking change policy] and added [Data Driven
Fixes] where supported.
- [x] All existing and new tests are passing.

If you need help, consider asking for advice on the #hackers-new channel
on [Discord].

<!-- Links -->
[Contributor Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#overview
[Tree Hygiene]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md
[test-exempt]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#tests
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md
[Features we expect every widget to implement]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Style-guide-for-Flutter-repo.md#features-we-expect-every-widget-to-implement
[CLA]: https://cla.developers.google.com/
[flutter/tests]: https://github.com/flutter/tests
[breaking change policy]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Tree-hygiene.md#handling-breaking-changes
[Discord]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Chat.md
[Data Driven Fixes]:
https://github.com/flutter/flutter/blob/main/docs/contributing/Data-driven-Fixes.md

Signed-off-by: huycozy <huy@nevercode.io>
diff --git a/packages/flutter/lib/src/material/dropdown.dart b/packages/flutter/lib/src/material/dropdown.dart
index 28c93be..611802a 100644
--- a/packages/flutter/lib/src/material/dropdown.dart
+++ b/packages/flutter/lib/src/material/dropdown.dart
@@ -23,6 +23,7 @@
 import 'constants.dart';
 import 'debug.dart';
 import 'icons.dart';
+import 'ink_decoration.dart';
 import 'ink_well.dart';
 import 'input_decorator.dart';
 import 'material.dart';
@@ -217,14 +218,22 @@
       child = Padding(padding: padding, child: child);
     }
     child = SizedBox(height: widget.route.itemHeight, child: child);
+
+    final bool isSelected = widget.itemIndex == widget.route.selectedIndex;
+    final FocusHighlightMode highlightMode = FocusManager.instance.highlightMode;
     // An [InkWell] is added to the item only if it is enabled
     if (dropdownMenuItem.enabled) {
       child = InkWell(
-        autofocus: widget.itemIndex == widget.route.selectedIndex,
+        autofocus: isSelected,
         enableFeedback: widget.enableFeedback,
         onTap: _handleOnTap,
         onFocusChange: _handleFocusChange,
-        child: child,
+        // When highlightMode is traditional, the InkWell draws the selected item background color.
+        // When highlightMode is touch, insert an Ink to force the selected item background color.
+        child:
+            highlightMode == FocusHighlightMode.touch
+                ? Ink(color: isSelected ? Theme.of(context).focusColor : null, child: child)
+                : child,
       );
     }
     child = FadeTransition(opacity: _opacityAnimation, child: child);
diff --git a/packages/flutter/test/material/dropdown_test.dart b/packages/flutter/test/material/dropdown_test.dart
index bf45458..88bc269 100644
--- a/packages/flutter/test/material/dropdown_test.dart
+++ b/packages/flutter/test/material/dropdown_test.dart
@@ -4449,4 +4449,67 @@
     // The dropdown should still be open, i.e., there should be one widget with 'second' text.
     expect(find.text('second'), findsOneWidget);
   });
+
+  // This is a regression test for https://github.com/flutter/flutter/issues/70294.
+  testWidgets(
+    'The previous selected item should be highlighted when reopening dropdown on mobile',
+    (WidgetTester tester) async {
+      final Color selectedColor = Colors.black.withValues(alpha: 0.12);
+      String currentValue = 'one';
+      await tester.pumpWidget(
+        MaterialApp(
+          theme: ThemeData(focusColor: selectedColor),
+          home: Scaffold(
+            body: Center(
+              child: StatefulBuilder(
+                builder: (BuildContext context, StateSetter setState) {
+                  return DropdownButton<String>(
+                    value: currentValue,
+                    items:
+                        menuItems
+                            .map(
+                              (String item) =>
+                                  DropdownMenuItem<String>(value: item, child: Text(item)),
+                            )
+                            .toList(),
+                    onChanged: (String? newValue) {
+                      setState(() {
+                        currentValue = newValue!;
+                      });
+                    },
+                  );
+                },
+              ),
+            ),
+          ),
+        ),
+      );
+
+      // Make sure the current value of dropdown is the first one of items list menuItems.
+      expect(find.text('one'), findsOne);
+
+      // Tap to open the dropdown.
+      await tester.tap(find.text('one'));
+      await tester.pumpAndSettle();
+
+      // Select the second item from the dropdown list.
+      await tester.tap(find.text('two'));
+      await tester.pumpAndSettle();
+
+      // Make sure the current item of dropdown is the second item of items list menuItems.
+      expect(find.text('two'), findsOneWidget);
+
+      // Tap to reopen the dropdown.
+      await tester.tap(find.text('two'));
+      await tester.pumpAndSettle();
+
+      // Make sure the current selected item is highlighted with selectedColor.
+      final Ink selectedItemInk = tester.widget<Ink>(
+        find.ancestor(of: find.text('two'), matching: find.byType(Ink)).first,
+      );
+      final BoxDecoration decoration = selectedItemInk.decoration! as BoxDecoration;
+      expect(decoration.color, selectedColor);
+    },
+    variant: TargetPlatformVariant.mobile(),
+  );
 }