@@ -1373,15 +1373,15 @@ public static boolean isImmersive() {
13731373 }
13741374 return isImmersive (getActivity ().getWindow ());
13751375 }
1376- public static boolean isImmersive (Window window ) {
1377- if (Build .VERSION .SDK_INT >= 35 ) {
1378- // Android 15+ is always immersive (overlay mode by default)
1379- return true ;
1380- }
1381- // On Android 34 and below, we can't detect decorFitsSystemWindows
1382- // reliably at runtime. So the app must make the decision explicitly.
1383- return false ;
1384- }
1376+ public static boolean isImmersive (Window window ) {
1377+ if (Build .VERSION .SDK_INT >= 35 ) {
1378+ // Android 15+ is always immersive (overlay mode by default)
1379+ return true ;
1380+ }
1381+ // On Android 34 and below, we can't detect decorFitsSystemWindows
1382+ // reliably at runtime. So the app must make the decision explicitly.
1383+ return false ;
1384+ }
13851385 public static Rect getSystemBarInsets (final View rootView ) {
13861386 final Rect result = new Rect (0 , 0 , 0 , 0 );
13871387 try {
@@ -1400,14 +1400,34 @@ public static Rect getSystemBarInsets(final View rootView) {
14001400 .invoke (insets , new Object []{systemBarsMask });
14011401 if (insetsObject == null ) return result ;
14021402 Class insetsClass = insetsObject .getClass ();
1403- int left = ((Integer ) insetsClass .getField ("left" ).get (insetsObject )).intValue ();
1404- int top = ((Integer ) insetsClass .getField ("top" ).get (insetsObject )).intValue ();
1405- int right = ((Integer ) insetsClass .getField ("right" ).get (insetsObject )).intValue ();
1406- int bottom = ((Integer ) insetsClass .getField ("bottom" ).get (insetsObject )).intValue ();
1407- result .set (left , top , right , bottom );
1408- } catch (Throwable t ) {
1409- t .printStackTrace (); // Optional: log this or suppress if expected
1410- }
1403+ int left = ((Integer ) insetsClass .getField ("left" ).get (insetsObject )).intValue ();
1404+ int top = ((Integer ) insetsClass .getField ("top" ).get (insetsObject )).intValue ();
1405+ int right = ((Integer ) insetsClass .getField ("right" ).get (insetsObject )).intValue ();
1406+ int bottom = ((Integer ) insetsClass .getField ("bottom" ).get (insetsObject )).intValue ();
1407+ // Include mandatory gesture insets (e.g. gesture navigation handle area).
1408+ // Some devices expose a larger interaction-protected bottom region here
1409+ // than in plain system bar insets.
1410+ try {
1411+ int mandatoryGesturesMask = ((Integer ) typeClass
1412+ .getMethod ("mandatorySystemGestures" )
1413+ .invoke (null )).intValue ();
1414+ Object mandatoryInsetsObject = insets .getClass ()
1415+ .getMethod ("getInsets" , new Class []{int .class })
1416+ .invoke (insets , new Object []{mandatoryGesturesMask });
1417+ if (mandatoryInsetsObject != null ) {
1418+ Class mandatoryInsetsClass = mandatoryInsetsObject .getClass ();
1419+ left = Math .max (left , ((Integer ) mandatoryInsetsClass .getField ("left" ).get (mandatoryInsetsObject )).intValue ());
1420+ top = Math .max (top , ((Integer ) mandatoryInsetsClass .getField ("top" ).get (mandatoryInsetsObject )).intValue ());
1421+ right = Math .max (right , ((Integer ) mandatoryInsetsClass .getField ("right" ).get (mandatoryInsetsObject )).intValue ());
1422+ bottom = Math .max (bottom , ((Integer ) mandatoryInsetsClass .getField ("bottom" ).get (mandatoryInsetsObject )).intValue ());
1423+ }
1424+ } catch (Throwable t ) {
1425+ // Ignore if mandatory gesture insets are unavailable.
1426+ }
1427+ result .set (left , top , right , bottom );
1428+ } catch (Throwable t ) {
1429+ t .printStackTrace (); // Optional: log this or suppress if expected
1430+ }
14111431 return result ;
14121432 }
14131433
0 commit comments