dvAndroidGeometry function

Map<String, Object?>? dvAndroidGeometry({
  1. required int widthPixels,
  2. required int heightPixels,
  3. required double density,
})

The default display, or null when Android has not said yet.

This reverses a decision recorded here, so the reasoning is worth keeping. The position was that screen.geometry "would come from WindowManager, whose modern API returns metrics through classes that vary by API level", and that "Flutter already reports the same numbers, so a binding would add a second answer that can disagree with the first". Both halves were right about the route they assumed. Neither survives the route actually taken:

  • Nothing here touches WindowManager. The numbers come from Resources.getDisplayMetrics() off the application Context, which has carried the same three fields since API 1. There is no WindowMetrics branch and nothing to vary.
  • The two answers are not the same number and were never meant to be. Flutter reports the view — the window this application draws into, a fraction of the screen in split screen and a slice of it in a freeform window. This reports the default display, which is exactly what the same binding name reports on every other target: XDisplayWidth of the default X screen on Linux, the main display on macOS, window.screen on the web. Android answering the window instead is what would make the name mean two things.

What is given up by using the application Context is multi-display accuracy: its resources track the default display, so an application shown on an external monitor or a foldable's other panel is described by the panel it is not on. That is a real limit, it is the same limit Linux and macOS have for the same reason, and the alternative — an Activity's resources — reports window bounds from API 30 and display bounds before it, which is the API-level variance the original objection was about.

The keys match the web binding's — width, height, devicePixelRatio — because application code reading screen.geometry must not have to know which platform answered. Linux adds an X screen number instead of a ratio; Android has a density and no screen number.

Null rather than zeroes. DisplayMetrics read before the display is up gives 0x0, and a caller handed {width: 0, height: 0} cannot tell that from a screen — every layout computed from it is quietly wrong and nothing upstream throws.

A density of zero drops the ratio and keeps the pixels: the pixels are still true, and a zero ratio is a division waiting to happen a long way from here.

Implementation

Map<String, Object?>? dvAndroidGeometry({
  required int widthPixels,
  required int heightPixels,
  required double density,
}) {
  if (widthPixels <= 0 || heightPixels <= 0) return null;
  return <String, Object?>{
    'width': widthPixels,
    'height': heightPixels,
    if (density > 0) 'devicePixelRatio': density,
  };
}