Skip to content

DisplayServer.get_display_safe_area is too small on some android phones in some orientations #105462

Closed
@Gromph

Description

@Gromph

Tested versions

  • Reproducible in Godot 4.3.stable and 4.4.1.stable

System information

Android 15 - Pixel 9 - Compatibility

Issue description

The width of safe area returned by DisplayServer.get_display_safe_area() is too narrow on Pixel 9 in some orientations:

In the screenshots below you can see the grey area outside the safe area is twice as big as it should be when the top camera is on the right or bottom

Too narrow:
Landscape - camera on the right:
Image

Too short:
Portrait - camera on the bottom:
Image

Correct:
Landscape - camera on left:
Image

Portrait - camera on top:
Image

The problem did not reproduce on:
Pixel 6a - Android 16
Galaxy A10e - Android 11

I believe the problem is in GodotIO.java getDisplaySafeArea
getWindowVisibleDisplayFrame already has the insets removed in some cases, so it should use getWindowVisibleDisplayFrame or getRootWindowInsets but not both at the same time.

Here is my version of getDisplaySafeArea that works on these 3 phones correctly. I'm not sure if using decorView.getX, getY, getWidth, getHeight is the best way to get the size or not though.

	public int[] getDisplaySafeArea() {
		Rect rect = new Rect();
		activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);

		int[] result = { rect.left, rect.top, rect.right, rect.bottom };
		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
			View decorView = activity.getWindow().getDecorView();
			result[0] = (int) decorView.getX();
			result[1] = (int) decorView.getY();
			result[2] = decorView.getWidth();
			result[3] = decorView.getHeight();
			WindowInsets insets = activity.getWindow().getDecorView().getRootWindowInsets();
			DisplayCutout cutout = insets.getDisplayCutout();
			if (cutout != null) {
				int insetLeft = cutout.getSafeInsetLeft();
				int insetTop = cutout.getSafeInsetTop();
				result[0] = insetLeft;
				result[1] = insetTop;
				result[2] -= insetLeft + cutout.getSafeInsetRight();
				result[3] -= insetTop + cutout.getSafeInsetBottom();
			}
		}
		return result;
	}

Steps to reproduce

See attached project, but basically:

  1. Create new project
  2. Set orientation in project settings to sensor
  3. Call DisplayServer.get_display_safe_area() while holding phone in different orientations

Minimal reproduction project (MRP)

safe-area-bug.zip

Metadata

Metadata

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions