Add flag to use root navigator for showModalBottomSheet (#35878)

* Add flag to use root navigator for showModalBottomSheet

* Add documentation

* Add tests

* Address feedback and fix analyzer issues

* Address feedback

* Update comments
diff --git a/packages/flutter/lib/src/material/bottom_sheet.dart b/packages/flutter/lib/src/material/bottom_sheet.dart
index 8f9ca2a..7ede1d9 100644
--- a/packages/flutter/lib/src/material/bottom_sheet.dart
+++ b/packages/flutter/lib/src/material/bottom_sheet.dart
@@ -400,6 +400,11 @@
 /// a [GridView] and have the bottom sheet be draggable, you should set this
 /// parameter to true.
 ///
+/// The `useRootNavigator` parameter ensures that the root navigator is used to
+/// display the [BottomSheet] when set to `true`. This is useful in the case
+/// that a modal [BottomSheet] needs to be displayed above all other content
+/// but the caller is inside another [Navigator].
+///
 /// Returns a `Future` that resolves to the value (if any) that was passed to
 /// [Navigator.pop] when the modal bottom sheet was closed.
 ///
@@ -417,14 +422,16 @@
   double elevation,
   ShapeBorder shape,
   bool isScrollControlled = false,
+  bool useRootNavigator = false,
 }) {
   assert(context != null);
   assert(builder != null);
   assert(isScrollControlled != null);
+  assert(useRootNavigator != null);
   assert(debugCheckHasMediaQuery(context));
   assert(debugCheckHasMaterialLocalizations(context));
 
-  return Navigator.push(context, _ModalBottomSheetRoute<T>(
+  return Navigator.of(context, rootNavigator: useRootNavigator).push(_ModalBottomSheetRoute<T>(
     builder: builder,
     theme: Theme.of(context, shadowThemeOnly: true),
     isScrollControlled: isScrollControlled,
diff --git a/packages/flutter/test/material/bottom_sheet_test.dart b/packages/flutter/test/material/bottom_sheet_test.dart
index 15cca8e..f0cf7e6 100644
--- a/packages/flutter/test/material/bottom_sheet_test.dart
+++ b/packages/flutter/test/material/bottom_sheet_test.dart
@@ -361,4 +361,91 @@
     ), ignoreTransform: true, ignoreRect: true, ignoreId: true));
     semantics.dispose();
   });
+
+  testWidgets('showModalBottomSheet does not use root Navigator by default', (WidgetTester tester) async {
+    await tester.pumpWidget(MaterialApp(
+      home: Scaffold(
+        body: Navigator(onGenerateRoute: (RouteSettings settings) => MaterialPageRoute<void>(builder: (_) {
+          return const _TestPage();
+        })),
+        bottomNavigationBar: BottomNavigationBar(
+          items: const <BottomNavigationBarItem>[
+            BottomNavigationBarItem(
+              icon: Icon(Icons.ac_unit),
+              title: Text('Item 1'),
+            ),
+            BottomNavigationBarItem(
+              icon: Icon(Icons.style),
+              title: Text('Item 2'),
+            )
+          ],
+        ),
+      ),
+    ));
+
+    await tester.tap(find.text('Show bottom sheet'));
+    await tester.pumpAndSettle();
+
+    // Bottom sheet is displayed in correct position within the inner navigator
+    // and above the BottomNavigationBar.
+    expect(tester.getBottomLeft(find.byType(BottomSheet)).dy, 544.0);
+  });
+
+  testWidgets('showModalBottomSheet uses root Navigator when specified', (WidgetTester tester) async {
+    await tester.pumpWidget(MaterialApp(
+      home: Scaffold(
+        body: Navigator(onGenerateRoute: (RouteSettings settings) => MaterialPageRoute<void>(builder: (_) {
+          return const _TestPage(useRootNavigator: true);
+        })),
+        bottomNavigationBar: BottomNavigationBar(
+          items: const <BottomNavigationBarItem>[
+            BottomNavigationBarItem(
+              icon: Icon(Icons.ac_unit),
+              title: Text('Item 1'),
+            ),
+            BottomNavigationBarItem(
+              icon: Icon(Icons.style),
+              title: Text('Item 2'),
+            )
+          ],
+        ),
+      ),
+    ));
+
+    await tester.tap(find.text('Show bottom sheet'));
+    await tester.pumpAndSettle();
+
+    // Bottom sheet is displayed in correct position above all content including
+    // the BottomNavigationBar.
+    expect(tester.getBottomLeft(find.byType(BottomSheet)).dy, 600.0);
+  });
+}
+
+class _TestPage extends StatelessWidget {
+  const _TestPage({Key key, this.useRootNavigator}) : super(key: key);
+
+  final bool useRootNavigator;
+
+  @override
+  Widget build(BuildContext context) {
+    return Center(
+      child: FlatButton(
+        child: const Text('Show bottom sheet'),
+        onPressed: () {
+          if (useRootNavigator != null) {
+            showModalBottomSheet<void>(
+              useRootNavigator: useRootNavigator,
+              context: context,
+              builder: (_) => const Text('Modal bottom sheet'),
+            );
+          } else {
+            showModalBottomSheet<void>(
+              context: context,
+              builder: (_) => const Text('Modal bottom sheet'),
+            );
+          }
+        }
+      ),
+    );
+  }
 }