Skip to content

Commit ad4164e

Browse files
authored
Respect mandatory system gesture insets when computing system bar insets (Android) (#4757)
1 parent 53e91ec commit ad4164e

2 files changed

Lines changed: 37 additions & 17 deletions

File tree

Ports/Android/src/com/codename1/impl/android/AndroidImplementation.java

Lines changed: 37 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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

-9 Bytes
Loading

0 commit comments

Comments
 (0)