[FloatingActionButtonLocation] Avoid docked FAB to be clipped by the software keyboard (#77769)

diff --git a/packages/flutter/lib/src/material/floating_action_button_location.dart b/packages/flutter/lib/src/material/floating_action_button_location.dart
index dc6350c..d8cb9df 100644
--- a/packages/flutter/lib/src/material/floating_action_button_location.dart
+++ b/packages/flutter/lib/src/material/floating_action_button_location.dart
@@ -584,7 +584,23 @@
     final double bottomSheetHeight = scaffoldGeometry.bottomSheetSize.height;
     final double fabHeight = scaffoldGeometry.floatingActionButtonSize.height;
     final double snackBarHeight = scaffoldGeometry.snackBarSize.height;
-    final double safeMargin = bottomViewPadding > contentMargin ? bottomViewPadding : 0.0;
+    final double bottomMinInset = scaffoldGeometry.minInsets.bottom;
+
+    double safeMargin;
+
+    if (contentMargin > bottomMinInset + fabHeight / 2.0) {
+      // If contentMargin is higher than bottomMinInset enough to display the
+      // FAB without clipping, don't provide a margin
+      safeMargin = 0.0;
+    } else if (bottomMinInset == 0.0) {
+      // If bottomMinInset is zero(the software keyboard is not on the screen)
+      // provide bottomViewPadding as margin
+      safeMargin = bottomViewPadding;
+    } else {
+      // Provide a margin that would shift the FAB enough so that it stays away
+      // from the keyboard
+      safeMargin = fabHeight / 2.0 + kFloatingActionButtonMargin;
+    }
 
     double fabY = contentBottom - fabHeight / 2.0 - safeMargin;
     // The FAB should sit with a margin between it and the snack bar.
diff --git a/packages/flutter/test/material/floating_action_button_location_test.dart b/packages/flutter/test/material/floating_action_button_location_test.dart
index 09e3791..23b7cd3 100644
--- a/packages/flutter/test/material/floating_action_button_location_test.dart
+++ b/packages/flutter/test/material/floating_action_button_location_test.dart
@@ -1037,7 +1037,9 @@
       );
     });
 
-    // Test docked locations, for each (6), keyboard presented or not:
+    // Test docked locations, for each (6), keyboard presented or not.
+    // If keyboard is presented and resizeToAvoidBottomInset: true, test whether
+    // the FAB is away from the keyboard(and thus not clipped):
     //  - Default
     //  - Default with resizeToAvoidBottomInset: false
     //  - docked with BottomNavigationBar
@@ -1057,6 +1059,7 @@
       const double keyboardHeight = 200.0;
       const double viewPadding = 50.0;
       const double bottomNavHeight = 106.0;
+      const double scaffoldHeight = 600.0;
       final Key floatingActionButton = UniqueKey();
       final double fabHeight = mini ? 48.0 : 56.0;
       // Default
@@ -1084,9 +1087,14 @@
         tester.getRect(find.byKey(floatingActionButton)),
         rectMoreOrLessEquals(defaultRect.translate(
           0.0,
-          viewPadding - keyboardHeight + fabHeight / 2.0,
+          viewPadding - keyboardHeight - kFloatingActionButtonMargin,
         )),
       );
+      // The FAB should be away from the keyboard
+      expect(
+        tester.getRect(find.byKey(floatingActionButton)).bottom,
+        lessThan(scaffoldHeight - keyboardHeight),
+      );
 
       // With resizeToAvoidBottomInset: false
       // With keyboard presented, should maintain default position
@@ -1136,9 +1144,14 @@
         tester.getRect(find.byKey(floatingActionButton)),
         rectMoreOrLessEquals(bottomNavigationBarRect.translate(
           0.0,
-          -keyboardHeight + bottomNavHeight,
+          bottomNavHeight + fabHeight / 2.0 - keyboardHeight - kFloatingActionButtonMargin - fabHeight,
         )),
       );
+      // The FAB should be away from the keyboard
+      expect(
+        tester.getRect(find.byKey(floatingActionButton)).bottom,
+        lessThan(scaffoldHeight - keyboardHeight),
+      );
 
       // BottomNavigationBar with resizeToAvoidBottomInset: false
       // With keyboard presented, should maintain default position
@@ -1195,6 +1208,11 @@
           -keyboardHeight + bottomNavHeight,
         )),
       );
+      // The FAB should be away from the keyboard
+      expect(
+        tester.getRect(find.byKey(floatingActionButton)).bottom,
+        lessThan(scaffoldHeight - keyboardHeight),
+      );
 
       // BottomNavigationBar + BottomSheet with resizeToAvoidBottomInset: false
       // With keyboard presented, should maintain default position
@@ -1264,6 +1282,11 @@
         tester.getRect(find.byKey(floatingActionButton)),
         rectMoreOrLessEquals(snackBarRect.translate(0.0, -keyboardHeight)),
       );
+      // The FAB should be away from the keyboard
+      expect(
+        tester.getRect(find.byKey(floatingActionButton)).bottom,
+        lessThan(scaffoldHeight - keyboardHeight),
+      );
     }
 
     testWidgets('startDocked', (WidgetTester tester) async {