Fix Android display metrics refresh on density changes#57295
Fix Android display metrics refresh on density changes#57295nikhilpakhloo wants to merge 2 commits into
Conversation
| synchronized(attachedSurfaces) { | ||
| attachedSurfaces.forEach { surface -> surface.view?.requestLayout() } | ||
| } | ||
| val didDisplayMetricsChange = DisplayMetricsHolder.updateDisplayMetricsIfChanged(context) |
There was a problem hiding this comment.
The onConfigurationChanged refresh here drops the enableFontScaleChangesUpdatingLayout() gate that the old ReactHostImpl path had, so on new arch the refresh, relayout and Dimensions emit now run unconditionally. ReactInstanceManager.onConfigurationChanged is also ungated. But ReactRootView.init still gates initDisplayMetrics on that same flag, so the init path stays gated while the refresh path does not.
Is bypassing the flag intended here? If it was a rollout gate, this ships the new relayout behavior to everyone. If that is the goal, would it make sense to gate init and refresh the same way (or drop the flag from both) so the two paths stay consistent?
There was a problem hiding this comment.
@fabriziocucci Good catch, this was not intended to bypass the rollout flag. I' ll update both ReactHostImpl and ReactInstanceManager so the display metrics refresh, relayout, and Dimensions emit stay gated by enableFontScaleChangesUpdatingLayout(), matching the init path.
There was a problem hiding this comment.
@fabriziocucci i have update ReactHostImpl and ReactInstanceManager so the display metrics refresh, relayout, and Dimensions emit stay gated by enableFontScaleChangesUpdatingLayout(), matching the init path.
…efresh, relayout, and Dimensions emit stay gated by enableFontScaleChangesUpdatingLayout(), matching the init path.
| val newFontScale = PixelUtil.toPixelFromSP(1.0) | ||
|
|
||
| if (previousFontScale != newFontScale) { | ||
| val didDisplayMetricsChange = DisplayMetricsHolder.updateDisplayMetricsIfChanged(context) |
There was a problem hiding this comment.
Thanks for gating both ReactHostImpl and ReactInstanceManager on enableFontScaleChangesUpdatingLayout(). That covers the consistency point.
One thing I noticed on the new arch path: setPixelDensity seems to be the only thing that sets the Fabric pixel density and it looks global (no surfaceId). The relayout here goes through setConstraints, which seems to carry width/height/offset/RTL but no scale factor. A relayout alone might not refresh the density. Old arch ReactInstanceManager pushes the new density via updateDisplayMetricDensity() but I don't see ReactHostImpl (or anything else in runtime/) doing the same. So on new arch a density change seems like it might relayout with a stale C++ pixel density, which would keep sp -> px wrong.
I might be missing something here. The test plan also doesn't seem to cover a device run. Did you get a chance to check the density actually updates on new arch (bridgeless)? If not, it seems like ReactHostImpl may also need to call updateDisplayMetricDensity().
Summary
Fixes Android display metrics getting stale when a React Native surface moves to a display/window with a different density, such as Samsung DeX, freeform windows, external monitors, or ChromeOS.
DisplayMetricsHolderwas initialized once and could keep using the main display density, while Fabric/root layout could use the current display density. This caused textsp -> pxconversion to use the wrong scale, making text render too large and clip.Changes
DisplayMetricsHolderwhen Android configuration/display metrics change.Changelog:
[ANDROID] [FIXED] - Keep display metrics in sync when Android display density changes
Test Plan
ktfmtFormat.git diff --check.buildCodegenCLI/tarpath handling.