fix(Android): use per-display density for px→dp conversion in FabricEnabledViewGroup.updateState#4160
Open
ziponia wants to merge 1 commit into
Conversation
…Group.updateState Fabric mounts views using the density of the display the surface is attached to, but updateState converted the measured px size back to dp with the process-global density (PixelUtil), captured once from the device's main display. On displays with a different density (Samsung DeX, freeform multi-window, external monitors) every Screen pushed windowSize / mainDisplayDensity into the Shadow Tree, collapsing all stack/tab content into a 1/density-sized box. Convert with the view's own context density instead. On single-display devices both values are identical, so behavior there is unchanged. Fixes software-mansion#4159
This was referenced Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fabric mounts views using the density of the display the surface is attached to, but
FabricEnabledViewGroup.updateStateconverts the natively measured px size back to dp with the process-global density (PixelUtil), captured once from the device's main display.On a display whose density differs from the main one (Samsung DeX, freeform multi-window, external monitors), every
ScreenpusheswindowSize ÷ mainDisplayDensityinto the Shadow Tree — all stack/tab content collapses into a 1/density-sized top-left box, while plain RN views outside screens track the window correctly.Closes #4159.
Changes
FabricEnabledViewGroup.updateState(Android, Fabric): convert px→dp using the view's own context density (context.resources.displayMetrics.density), with a defensive fallback toPixelUtil.toDIPFromPixelif the density is not positive.Before & after - visual documentation
1/densitybox(The dark card is a diagnostic overlay that instruments
updateStatepushes. In the "after" screenshot the visible text rendering is correct because the app also applies a workaround for a separate react-native core bug — stale global density in text sp→px conversion — which is out of scope for this PR and reported to facebook/react-native.)Measured
updateStatepushes on a Galaxy S25 Ultra (main display density 2.8125) in DeX, window resized 6 times:Before the fix every push equals
window ÷ 2.8125; after the fix it equals the window content size at every tested window size.Test plan
ScreenStacksize and thewindow ÷ contentratio).yarn androidon a DeX-capable device → switch to Samsung DeX (or open a freeform window on a different-density display) → inside-stack content size now matches the window, ratio ≈ 1; resize the window and verify it keeps tracking.Checklist
Disclosure
This PR was authored by Claude (an AI coding agent) operating on behalf of and supervised by @ziponia, who hit this bug in a production app. The fix was validated on @ziponia's physical device, and this PR was reviewed and approved by them before submission.