Skip to content

Conversation

@zoontek
Copy link
Contributor

@zoontek zoontek commented Jul 21, 2025

Summary:

This PR (initially created for edge-to-edge opt-in support, rebased multiple times) fixes the Dimensions API window values on Android < 15, when edge-to-edge is enabled.

Currently the window height doesn't include the status and navigation bar heights (but it does on Android >= 15):

Screenshot 2025-06-27 at 16 23 02

Using WindowMetricsCalculator from AndroidX:

Screenshot 2025-06-27 at 16 34 01

Fixes #47080

Changelog:

[Android] [Fixed] Fix Dimensions window values on Android < 15 when edge-to-edge is enabled

Test Plan:

Run the example app on an Android < 15 device.

@meta-cla meta-cla bot added the CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. label Jul 21, 2025
@facebook-github-bot facebook-github-bot added the Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team. label Jul 21, 2025
@cortinico
Copy link
Contributor

@zoontek can you look into the test failures as they look related?

@cortinico
Copy link
Contributor

Specifically the first one:

RootViewTest > testCheckForKeyboardEvents FAILED
    java.lang.IllegalStateException at DisplayMetricsHolder.kt:36

RootViewTest > testTouchEmitter FAILED
    java.lang.IllegalStateException at RootViewTest.kt:111

372 tests completed, 2 failed

@zoontek
Copy link
Contributor Author

zoontek commented Jul 22, 2025

@cortinico It should fix it.

Thing is, the issue is that we cannot delay display metrics init until we get a non-null Activity instance. But if we keep initDisplayMetricsIfNotInitialized, it happens that the initial called is not an Ui context, then the second is, but the values are not updated (because already init).

So we need to make subsequent calls to initDisplayMetrics, and update window metrics only if within Ui context.

@facebook-github-bot
Copy link
Contributor

@cortinico has imported this pull request. If you are a Meta employee, you can view this in D78738516.

@zoontek zoontek force-pushed the fix-dimensions-api branch from f191ace to e9ac31c Compare July 27, 2025 14:11
@zoontek
Copy link
Contributor Author

zoontek commented Jul 27, 2025

Hey @cortinico

I wasn't super happy with the first proposed solution, did some extensive testing on Android 7 / 9 / 14, on old and new architecture (zoontek#2)

Like suggested on Discord:

The clean way to do it would be to properly separate the screen metrics and the window metrics init

So:

  • I splitted initDisplayMetrics into initScreenDisplayMetrics and initWindowDisplayMetrics
  • I splitted initDisplayMetricsIfNotInitialized into initScreenDisplayMetricsIfNotInitialized and initWindowDisplayMetricsIfNotInitialized
  • I made sure that initWindowDisplayMetrics and initWindowDisplayMetricsIfNotInitialized are always called with UI context (tested on Android 7 / 9 / 14, with: old & new arch, orientations changes)
  • And because it's kinda the same code, I also fixed this issue (just by removing the ReactNativeFeatureFlags.enableFontScaleChangesUpdatingLayout() checks that wrapped init*DisplayMetrics on configuration change)
demo.mp4

@efstathiosntonas
Copy link

hey folks, is there any chance this to be backported to 0.79.x? Seems like a big issue in the UI consistency. Thanks!

@cortinico cortinico requested a review from alanleedev July 29, 2025 11:02
@alanleedev
Copy link
Contributor

@zoontek Wanted to give you an update. I fixed some internal build errors but see this failing some tests. I haven't got around to look into it yet and want to be more cautious with this diff as past attempts has caused issues for us. Will try to get to this soon.

@facebook-github-bot
Copy link
Contributor

@alanleedev has imported this pull request. If you are a Meta employee, you can view this in D78738516.

@alanleedev
Copy link
Contributor

@zoontek Noticing the implementation changed a bit since we first imported this PR. What is the reason for splitting initScreenDisplayMetrics() and initWindowDisplayMetrics() instead of previous initDisplayMetrics()?

@zoontek
Copy link
Contributor Author

zoontek commented Aug 1, 2025

@alanleedev Since screenDisplayMetrics can be initialized with any type of context, but windowDisplayMetrics now requires a UI context, the initialization of both values may not happen at the same time (calls to initialize windowDisplayMetrics are sometimes wrapped in activity null checks).

Previously, both were initialized in the same method: initDisplayMetrics.

I initially added a new check, isUiContext, but for that to work, I had no choice but to remove initDisplayMetricsIfNotInitialized. That method only checked whether screenDisplayMetrics was set, and calling initDisplayMetrics no longer guaranteed both values would be initialized.

In the end, instead of relying on a suite of conditions, I opted to split the initialization into two separate methods. This makes the code much easier to maintain and reason about.

@alanleedev
Copy link
Contributor

alanleedev commented Aug 1, 2025

@zoontek That makes sense. I'm going to add some comments around this to make it clear.

Also link to previous comment on why UiContext is needed in case someone is curious.

@alanleedev
Copy link
Contributor

@zoontek I think the current PR adds behavior change which we may not be handled correctly.
One example of crash observed:

08-04 06:18:08.062 7793 7836 E AndroidRuntime: java.lang.IllegalStateException: DisplayMetricsHolder must be initialized with initWindowDisplayMetricsIfNotInitialized or initWindowDisplayMetrics
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.uimanager.DisplayMetricsHolder.getWindowDisplayMetrics(DisplayMetricsHolder.kt:37)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.uimanager.PixelUtil.getDisplayMetricDensity(PixelUtil.kt:69)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.fabric.FabricUIManagerBinding.register(FabricUIManagerBinding.kt:96)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.fabric.FabricUIManagerProviderImpl.createUIManager(FabricUIManagerProviderImpl.kt:56)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.panelapp.ReactNativeHost$getUIManagerProvider$1.createUIManager(ReactNativeHost.kt:156)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.ReactInstanceManager.createReactContext(ReactInstanceManager.java:1518)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.ReactInstanceManager.lambda$runCreateReactContextOnNewThread$2$com-facebook-react-ReactInstanceManager(ReactInstanceManager.java:1233)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at com.facebook.react.ReactInstanceManager$$ExternalSyntheticLambda1.run(D8$$SyntheticClass:0)
08-04 06:18:08.062 7793 7836 E AndroidRuntime: 	at java.lang.Thread.run(Thread.java:1012)

@zoontek
Copy link
Contributor Author

zoontek commented Aug 4, 2025

@alanleedev I think that some initWindowDisplayMetricsIfNotInitialized needs to be added / moved. Currently, they are next to initScreenDisplayMetricsIfNotInitialized.

Let me have a look. Do you know how can I reproduce?

zoontek added 8 commits August 4, 2025 10:26
# Conflicts:
#	packages/react-native/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java
#	packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.kt
@zoontek zoontek force-pushed the fix-dimensions-api branch from 60e278c to d618835 Compare August 4, 2025 08:26
@alanleedev
Copy link
Contributor

@zoontek It is with internal Meta app so you probably cannot repro. I'll have further look into this.
One concern with PixelUtil is that where we were calling initMetrics which we only can call initScreenMetrics then this could be a potential issue as PixelUtil could be called without proper initialization. Wondering if there is a better way to handle this.

@zoontek
Copy link
Contributor Author

zoontek commented Aug 4, 2025

@alanleedev If an additional initWindowDisplayMetricsIfNotInitialized is added immediately on Activity creation, whouldn't it solves the issue?

@alanleedev
Copy link
Contributor

@alanleedev If an additional initWindowDisplayMetricsIfNotInitialized is added immediately on Activity creation, whouldn't it solves the issue?

@zoontek App in question is partially RN and uses Fragments so will need to understand how things get initialized. But overall, PixelUtil has an unclear initialization dependency on DiplayMetricsHolder.windowDisplayMetrics which does not seem too desirable so wondering if there is a better way to handle this.

@zoontek
Copy link
Contributor Author

zoontek commented Aug 4, 2025

@alanleedev Nearly all calls to getWindowDisplayMetrics could be replaced with getScreenDisplayMetrics, as what matters is those contexts are scale / fontScale / densityDpi, not height and width (and those values are similar on both screen and window metrics).

The only valid usage is located in ReactRootView.java.
I can push the change if you want.

@alanleedev
Copy link
Contributor

alanleedev commented Aug 4, 2025

@alanleedev Nearly all calls to getWindowDisplayMetrics could be replaced with getScreenDisplayMetrics, as what matters is those contexts are scale / fontScale / densityDpi, not height and width (and those values are similar on both screen and window metrics).

@zoontek That is a good point. Looking at TypedValue.java following seems to be used;
metrics.density
metrics.fontScaleConverter
metrics.scaledDensity
metrics.xdpi

If you could post an update that would be great.
Actually, I'll do the update as I need to make also internal code changes anyway and need to re-apply additional internal changes if I re-import the PR.

@facebook-github-bot facebook-github-bot added the Merged This PR has been merged. label Aug 7, 2025
@facebook-github-bot
Copy link
Contributor

@alanleedev merged this pull request in 3b185e4.

alanleedev added a commit to alanleedev/react-native that referenced this pull request Aug 7, 2025
Summary:
Reverting PR facebook#52738

Changelog: [Internal]
reverting D78738516

Original commit changeset: fdb22f3cc76b

Original Phabricator Diff: D78738516

Rollback Plan:

Differential Revision: D79835424
alanleedev added a commit to alanleedev/react-native that referenced this pull request Aug 7, 2025
Summary:



Reverting PR facebook#52738

Changelog: [Internal]
reverting D78738516

Original commit changeset: fdb22f3cc76b

Original Phabricator Diff: D78738516

Reviewed By: lenaic, Abbondanzo

Differential Revision: D79835424
alanleedev added a commit to alanleedev/react-native that referenced this pull request Aug 7, 2025
Summary:
Pull Request resolved: facebook#53149

Reverting PR facebook#52738

Changelog: [Internal]
reverting D78738516

Original commit changeset: fdb22f3cc76b

Original Phabricator Diff: D78738516

Reviewed By: mdvacca, lenaic, Abbondanzo

Differential Revision: D79835424
alanleedev added a commit to alanleedev/react-native that referenced this pull request Aug 7, 2025
Summary:



Reverting PR facebook#52738

Changelog: [Internal]
reverting D78738516

Original commit changeset: fdb22f3cc76b

Original Phabricator Diff: D78738516

Reviewed By: mdvacca, lenaic, Abbondanzo

Differential Revision: D79835424
alanleedev added a commit to alanleedev/react-native that referenced this pull request Aug 7, 2025
Summary:
Pull Request resolved: facebook#53149

Reverting PR facebook#52738

Changelog: [Internal]
reverting D78738516

Original commit changeset: fdb22f3cc76b

Original Phabricator Diff: D78738516

Reviewed By: mdvacca, lenaic, Abbondanzo

Differential Revision: D79835424
facebook-github-bot pushed a commit that referenced this pull request Aug 8, 2025
Summary:
Pull Request resolved: #53149

Reverting PR #52738

Changelog: [Internal]
reverting D78738516

Original commit changeset: fdb22f3cc76b

Original Phabricator Diff: D78738516

Reviewed By: mdvacca, lenaic, Abbondanzo

Differential Revision: D79835424

fbshipit-source-id: 44b5ee34b4df6752e5a6f959a54e104eef20ffca
@facebook-github-bot
Copy link
Contributor

This pull request has been reverted by 352e440.

@zoontek zoontek deleted the fix-dimensions-api branch August 13, 2025 17:38
kikoso pushed a commit to kikoso/react-native that referenced this pull request Aug 26, 2025
Summary:
This PR (initially created for edge-to-edge opt-in support, rebased multiple times) fixes the `Dimensions` API `window` values on Android < 15, when edge-to-edge is enabled.

Currently the window height doesn't include the status and navigation bar heights (but it does on Android >= 15):

<img width="300" alt="Screenshot 2025-06-27 at 16 23 02" src="https://github.com/user-attachments/assets/c7d11334-9298-4f7f-a75c-590df8cc2d8a" />

Using `WindowMetricsCalculator` from AndroidX:

<img width="300" alt="Screenshot 2025-06-27 at 16 34 01" src="https://github.com/user-attachments/assets/7a4e3dc7-a83b-421b-8f6d-fd1344f5fe81" />

Fixes facebook#47080

## Changelog:

[Android] [Fixed] Fix `Dimensions` `window` values on Android < 15 when edge-to-edge is enabled

Pull Request resolved: facebook#52738

Test Plan:
Run the example app on an Android < 15 device.

Rollback Plan:

Reviewed By: cipolleschi, Abbondanzo

Differential Revision: D78738516

Pulled By: alanleedev

fbshipit-source-id: fdb22f3cc76b0bda987db426cb015124bcacdc84
kikoso pushed a commit to kikoso/react-native that referenced this pull request Aug 26, 2025
Summary:
Pull Request resolved: facebook#53149

Reverting PR facebook#52738

Changelog: [Internal]
reverting D78738516

Original commit changeset: fdb22f3cc76b

Original Phabricator Diff: D78738516

Reviewed By: mdvacca, lenaic, Abbondanzo

Differential Revision: D79835424

fbshipit-source-id: 44b5ee34b4df6752e5a6f959a54e104eef20ffca
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Facebook bot. Authors need to sign the CLA before a PR can be reviewed. Merged This PR has been merged. Reverted Shared with Meta Applied via automation to indicate that an Issue or Pull Request has been shared with the team.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dimensions.get('window').height not consistent in Android 14 and Android 15

5 participants