Read screen size from WindowMetrics on API 30+ - #993
Conversation
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
left a comment
There was a problem hiding this comment.
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:
DeviceInfoImpl→DeviceInfoParameterBuilder(DeviceInfoParameterBuilder.java:54-55) setsdevice.w/device.hin the OpenRTB bid request.AdWebView.java:85-87/PrebidWebViewBase.java:253-254use 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.
Change log and rationale:
WindowManager.getDefaultDisplay()andDisplay.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 usegetMaximumWindowMetrics().getBounds(). This preserves the full physical-screen dimensions required by OpenRTBdevice.w/device.h, including when the Activity is in split-screen or freeform mode.New
Utils.getWindowWidth()/getWindowHeight()helpers usegetCurrentWindowMetrics().getBounds().AdWebViewandPrebidWebViewBaseuse 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
WindowManagerreturns zero.Partially addresses #956 (display metrics). The location permission and network connection items in that issue are handled separately.