Skip to content

Read screen size from WindowMetrics on API 30+ - #993

Open
Madroid2 wants to merge 2 commits into
prebid:masterfrom
Madroid2:fix/screen-metrics-deprecated-api-956
Open

Read screen size from WindowMetrics on API 30+#993
Madroid2 wants to merge 2 commits into
prebid:masterfrom
Madroid2:fix/screen-metrics-deprecated-api-956

Conversation

@Madroid2

@Madroid2 Madroid2 commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Change log and rationale:

  • WindowManager.getDefaultDisplay() and Display.getRealSize() are deprecated from API 30. The old utility also served two consumers with different size semantics: OpenRTB device dimensions and WebView/interstitial layout.

  • On API 30+, Utils.getScreenWidth()/getScreenHeight() now use getMaximumWindowMetrics().getBounds(). This preserves the full physical-screen dimensions required by OpenRTB device.w/device.h, including when the Activity is in split-screen or freeform mode.

  • New Utils.getWindowWidth()/getWindowHeight() helpers use getCurrentWindowMetrics().getBounds(). AdWebView and PrebidWebViewBase use these current-window dimensions for resize and scale calculations, which reflects the space where the creative actually renders.

  • The pre-30 implementation is preserved in a single legacyDisplaySize() helper. Deprecated calls and their suppression remain scoped to that compatibility path.

  • Robolectric coverage for API 30 models split-screen by returning different current and maximum window bounds. Tests verify that OpenRTB-facing screen dimensions use maximum metrics, rendering uses current metrics, deprecated display APIs are not consulted, and a null WindowManager returns zero.

Partially addresses #956 (display metrics). The location permission and network connection items in that issue are handled separately.

Utils.getScreenWidth() and getScreenHeight() sized the display through
WindowManager.getDefaultDisplay() and Display.getRealSize(). Both were
deprecated in API 30 in favour of WindowManager.getCurrentWindowMetrics(),
and getDefaultDisplay() is additionally the wrong call on devices that can
present an activity on a secondary or folded display, since it always
describes the default one rather than the display the ad is actually on.

From API 30 the size now comes from getCurrentWindowMetrics().getBounds().
Both APIs report the full display area including system decorations, so the
width and height sent in the bid request are unchanged.

The pre-30 branch is preserved for the still-supported minSdk and pulled into
a single legacyDisplaySize() helper, so the deprecated calls exist once rather
than four times and @SuppressWarnings("deprecation") is scoped to just that
method instead of leaking over the rest of Utils. The null-WindowManager guard
becomes an early return.

Adds coverage in UtilsTest for the API 30 path -- width and height come from
the window metrics bounds and getDefaultDisplay() is never consulted -- plus
the null-WindowManager case, which was previously untested. The new tests run
under @config(sdk = 30) so android.view.WindowMetrics is on the runtime
classpath; the existing SDK 16 and 17 tests are unchanged and still cover the
legacy branch.

Partially addresses prebid#956 (display metrics). The location permission and
network connection items in that issue are handled separately.

@YuriyVelichkoPI YuriyVelichkoPI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the cleanup — deduping the deprecated calls into legacyDisplaySize() and scoping @SuppressWarnings("deprecation") to just that method is a nice improvement, and the new Robolectric coverage for API 30 looks correct.

However, I think this introduces a spec-compliance regression for one of the two consumers of Utils.getScreenWidth()/getScreenHeight():

Where this is used:

  • DeviceInfoImplDeviceInfoParameterBuilder (DeviceInfoParameterBuilder.java:54-55) sets device.w/device.h in the OpenRTB bid request.
  • AdWebView.java:85-87 / PrebidWebViewBase.java:253-254 use it for interstitial resize/scale calculations.

Both can receive a WindowManager obtained from an Activity context (see ManagersResolver.java:60-66: "Try with application context or activity context").

The problem: WindowManager.getCurrentWindowMetrics().getBounds() on an Activity-context WindowManager returns the bounds of that window, not the physical display. In split-screen/multi-window/freeform mode (increasingly common on foldables/tablets — the exact device class this PR's rationale calls out), that's smaller than the full screen. The old Display.getRealSize() always returned the full physical display size regardless of windowing mode.

Per the IAB OpenRTB spec, Device Object (https://github.com/InteractiveAdvertisingBureau/openrtb2.x/blob/main/2.6.md):

Field Type Description
w integer Physical width of the screen in pixels.
h integer Physical height of the screen in pixels.

So on API 30+, device.w/device.h will now report the app's window size instead of the physical screen size when the app is in split-screen — which contradicts this PR's own description ("width and height sent in the bid request are unchanged").

For the AdWebView/webview-sizing use case, using window bounds is actually fine (arguably more correct, since that's the space the ad renders into) — no change needed there.

Suggested fix: don't apply one method to both consumers. For the device.w/device.h path specifically, use getMaximumWindowMetrics().getBounds() (or equivalent full-display bounds) so it stays spec-correct and matches prior behavior regardless of windowing mode. Happy to discuss if you'd prefer a different approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants