Skip to content

Commit 8c427b6

Browse files
committed
Rollback DisplayMetricsHolder changes (non breaking period)
1 parent 8d21ffd commit 8c427b6

5 files changed

Lines changed: 99 additions & 2 deletions

File tree

packages/react-native/ReactAndroid/api/ReactAndroid.api

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3284,10 +3284,13 @@ public abstract class com/facebook/react/uimanager/BaseViewManagerDelegate : com
32843284

32853285
public final class com/facebook/react/uimanager/DisplayMetricsHolder {
32863286
public static final field INSTANCE Lcom/facebook/react/uimanager/DisplayMetricsHolder;
3287+
public static final fun getDisplayMetricsWritableMap (D)Lcom/facebook/react/bridge/WritableMap;
32873288
public static final fun getScreenDisplayMetrics ()Landroid/util/DisplayMetrics;
3289+
public static final fun getWindowDisplayMetrics ()Landroid/util/DisplayMetrics;
32883290
public static final fun initDisplayMetrics (Landroid/content/Context;)V
32893291
public static final fun initDisplayMetricsIfNotInitialized (Landroid/content/Context;)V
32903292
public static final fun setScreenDisplayMetrics (Landroid/util/DisplayMetrics;)V
3293+
public static final fun setWindowDisplayMetrics (Landroid/util/DisplayMetrics;)V
32913294
}
32923295

32933296
public final class com/facebook/react/uimanager/FloatUtil {

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.kt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ import android.util.DisplayMetrics
1414
import android.view.WindowManager
1515
import androidx.core.view.ViewCompat
1616
import androidx.core.view.WindowInsetsCompat
17+
import com.facebook.react.bridge.WritableMap
18+
import com.facebook.react.bridge.WritableNativeMap
1719
import com.facebook.react.uimanager.PixelUtil.pxToDp
1820

1921
/**
@@ -24,8 +26,21 @@ public object DisplayMetricsHolder {
2426
private const val INITIALIZATION_MISSING_MESSAGE =
2527
"DisplayMetricsHolder must be initialized with initDisplayMetricsIfNotInitialized or initDisplayMetrics"
2628

29+
@JvmStatic private var windowDisplayMetrics: DisplayMetrics? = null
2730
@JvmStatic private var screenDisplayMetrics: DisplayMetrics? = null
2831

32+
/** The metrics of the window associated to the Context used to initialize ReactNative */
33+
@JvmStatic
34+
public fun getWindowDisplayMetrics(): DisplayMetrics {
35+
checkNotNull(windowDisplayMetrics) { INITIALIZATION_MISSING_MESSAGE }
36+
return windowDisplayMetrics as DisplayMetrics
37+
}
38+
39+
@JvmStatic
40+
public fun setWindowDisplayMetrics(displayMetrics: DisplayMetrics?) {
41+
windowDisplayMetrics = displayMetrics
42+
}
43+
2944
/** Screen metrics returns the metrics of the default screen on the device. */
3045
@JvmStatic
3146
public fun getScreenDisplayMetrics(): DisplayMetrics {
@@ -47,10 +62,11 @@ public object DisplayMetricsHolder {
4762
}
4863

4964
@JvmStatic
50-
@SuppressLint("DeprecatedMethod") // for Android Lint
65+
@SuppressLint("DeprecatedMethod") // for Andriod Lint
5166
@Suppress("DEPRECATION") // for Kotlin compiler
5267
public fun initDisplayMetrics(context: Context) {
5368
val displayMetrics = context.resources.displayMetrics
69+
windowDisplayMetrics = displayMetrics
5470
val screenDisplayMetrics = DisplayMetrics()
5571
screenDisplayMetrics.setTo(displayMetrics)
5672
try {
@@ -68,6 +84,35 @@ public object DisplayMetricsHolder {
6884
DisplayMetricsHolder.screenDisplayMetrics = screenDisplayMetrics
6985
}
7086

87+
@JvmStatic
88+
public fun getDisplayMetricsWritableMap(fontScale: Double): WritableMap {
89+
checkNotNull(windowDisplayMetrics) { INITIALIZATION_MISSING_MESSAGE }
90+
checkNotNull(screenDisplayMetrics) { INITIALIZATION_MISSING_MESSAGE }
91+
92+
return WritableNativeMap().apply {
93+
putMap(
94+
"windowPhysicalPixels",
95+
getPhysicalPixelsWritableMap(windowDisplayMetrics as DisplayMetrics, fontScale),
96+
)
97+
putMap(
98+
"screenPhysicalPixels",
99+
getPhysicalPixelsWritableMap(screenDisplayMetrics as DisplayMetrics, fontScale),
100+
)
101+
}
102+
}
103+
104+
private fun getPhysicalPixelsWritableMap(
105+
displayMetrics: DisplayMetrics,
106+
fontScale: Double,
107+
): WritableMap =
108+
WritableNativeMap().apply {
109+
putInt("width", displayMetrics.widthPixels)
110+
putInt("height", displayMetrics.heightPixels)
111+
putDouble("scale", displayMetrics.density.toDouble())
112+
putDouble("fontScale", fontScale)
113+
putDouble("densityDpi", displayMetrics.densityDpi.toDouble())
114+
}
115+
71116
internal fun getStatusBarHeightPx(activity: Activity?): Int {
72117
val windowInsets = activity?.window?.decorView?.let(ViewCompat::getRootWindowInsets) ?: return 0
73118
return windowInsets

packages/react-native/ReactAndroid/src/main/java/com/facebook/react/views/text/TextLayoutManager.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1333,7 +1333,7 @@ internal object TextLayoutManager {
13331333
return FontMetricsUtil.getFontMetrics(
13341334
layout.text,
13351335
layout,
1336-
DisplayMetricsHolder.getScreenDisplayMetrics(),
1336+
DisplayMetricsHolder.getWindowDisplayMetrics(),
13371337
)
13381338
}
13391339

packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/DisplayMetricsHolderTest.kt

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import android.view.View
1717
import android.view.Window
1818
import android.view.WindowInsets
1919
import androidx.annotation.RequiresApi
20+
import com.facebook.react.bridge.WritableMap
2021
import com.facebook.testutils.shadows.ShadowNativeLoader
2122
import com.facebook.testutils.shadows.ShadowNativeMap
2223
import com.facebook.testutils.shadows.ShadowReadableNativeMap
@@ -54,19 +55,33 @@ class DisplayMetricsHolderTest {
5455
fun setUp() {
5556
context = RuntimeEnvironment.getApplication()
5657
displayMetrics = context.resources.displayMetrics
58+
DisplayMetricsHolder.setWindowDisplayMetrics(null)
5759
DisplayMetricsHolder.setScreenDisplayMetrics(null)
5860
}
5961

6062
@After
6163
fun tearDown() {
64+
DisplayMetricsHolder.setWindowDisplayMetrics(null)
6265
DisplayMetricsHolder.setScreenDisplayMetrics(null)
6366
}
6467

68+
@Test(expected = IllegalStateException::class)
69+
fun getWindowDisplayMetrics_failsIfDisplayMetricsIsNotInitialized() {
70+
DisplayMetricsHolder.getWindowDisplayMetrics()
71+
}
72+
6573
@Test(expected = IllegalStateException::class)
6674
fun getScreenDisplayMetrics_failsIfDisplayMetricsIsNotInitialized() {
6775
DisplayMetricsHolder.getScreenDisplayMetrics()
6876
}
6977

78+
@Test
79+
fun setAndGetWindowDisplayMetrics_returnsSetValue() {
80+
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics)
81+
val result = DisplayMetricsHolder.getWindowDisplayMetrics()
82+
assertThat(result).isEqualTo(displayMetrics)
83+
}
84+
7085
@Test
7186
fun setAndGetScreenDisplayMetrics_returnsSetValue() {
7287
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics)
@@ -77,19 +92,46 @@ class DisplayMetricsHolderTest {
7792
@Test
7893
fun initDisplayMetrics_setsMetrics() {
7994
DisplayMetricsHolder.initDisplayMetrics(context)
95+
assertThat(DisplayMetricsHolder.getWindowDisplayMetrics()).isNotNull()
8096
assertThat(DisplayMetricsHolder.getScreenDisplayMetrics()).isNotNull()
8197
}
8298

8399
@Test
84100
fun initDisplayMetricsIfNotInitialized_onlyInitializesOnce() {
85101
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)
102+
val firstWindow = DisplayMetricsHolder.getWindowDisplayMetrics()
86103
val firstScreen = DisplayMetricsHolder.getScreenDisplayMetrics()
87104
// Should not reinitialize
88105
DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(context)
106+
val secondWindow = DisplayMetricsHolder.getWindowDisplayMetrics()
89107
val secondScreen = DisplayMetricsHolder.getScreenDisplayMetrics()
108+
assertThat(secondWindow).isEqualTo(firstWindow)
90109
assertThat(secondScreen).isEqualTo(firstScreen)
91110
}
92111

112+
@Test(expected = IllegalStateException::class)
113+
fun getDisplayMetricsWritableMap_failsIfNotInitialized() {
114+
DisplayMetricsHolder.getDisplayMetricsWritableMap(1.0)
115+
}
116+
117+
@Test
118+
fun getDisplayMetricsWritableMap_returnsCorrectMap() {
119+
// Use the official initialization method to ensure both metrics are set
120+
DisplayMetricsHolder.initDisplayMetrics(context)
121+
val map: WritableMap = DisplayMetricsHolder.getDisplayMetricsWritableMap(1.0)
122+
assertThat(map.hasKey("windowPhysicalPixels")).isTrue()
123+
assertThat(map.hasKey("screenPhysicalPixels")).isTrue()
124+
val windowMap = map.getMap("windowPhysicalPixels")
125+
val screenMap = map.getMap("screenPhysicalPixels")
126+
checkNotNull(windowMap)
127+
checkNotNull(screenMap)
128+
assertThat(windowMap.hasKey("width")).isTrue()
129+
assertThat(windowMap.hasKey("height")).isTrue()
130+
assertThat(windowMap.hasKey("scale")).isTrue()
131+
assertThat(windowMap.hasKey("fontScale")).isTrue()
132+
assertThat(windowMap.hasKey("densityDpi")).isTrue()
133+
}
134+
93135
@Test
94136
@RequiresApi(30)
95137
fun getEncodedScreenSizeWithoutVerticalInsets_returnsEncodedValue() {
@@ -162,6 +204,7 @@ class DisplayMetricsHolderTest {
162204
DisplayMetricsHolder.initDisplayMetrics(mockContext)
163205

164206
// Metrics should still be set from resource display metrics
207+
assertThat(DisplayMetricsHolder.getWindowDisplayMetrics()).isNotNull()
165208
assertThat(DisplayMetricsHolder.getScreenDisplayMetrics()).isNotNull()
166209
}
167210
}

packages/react-native/ReactAndroid/src/test/java/com/facebook/react/uimanager/PixelUtilTest.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,13 @@ class PixelUtilTest {
3737
@Before
3838
fun setUp() {
3939
context = RuntimeEnvironment.getApplication()
40+
DisplayMetricsHolder.setWindowDisplayMetrics(null)
4041
DisplayMetricsHolder.setScreenDisplayMetrics(null)
4142
}
4243

4344
@After
4445
fun tearDown() {
46+
DisplayMetricsHolder.setWindowDisplayMetrics(null)
4547
DisplayMetricsHolder.setScreenDisplayMetrics(null)
4648
}
4749

@@ -55,6 +57,7 @@ class PixelUtilTest {
5557
displayMetrics.heightPixels = 1920
5658
displayMetrics.densityDpi = DisplayMetrics.DENSITY_XXHIGH
5759

60+
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics)
5861
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics)
5962

6063
// Test that toPixelFromSP respects fontScale < 1.0
@@ -77,6 +80,7 @@ class PixelUtilTest {
7780
displayMetrics.heightPixels = 1920
7881
displayMetrics.densityDpi = DisplayMetrics.DENSITY_XXHIGH
7982

83+
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics)
8084
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics)
8185

8286
// Test that toPixelFromSP respects fontScale > 1.0
@@ -99,6 +103,7 @@ class PixelUtilTest {
99103
displayMetrics.heightPixels = 1920
100104
displayMetrics.densityDpi = DisplayMetrics.DENSITY_XXHIGH
101105

106+
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics)
102107
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics)
103108

104109
// Test that maxFontScale limits the scaling
@@ -123,6 +128,7 @@ class PixelUtilTest {
123128
displayMetrics.heightPixels = 1920
124129
displayMetrics.densityDpi = DisplayMetrics.DENSITY_XXHIGH
125130

131+
DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics)
126132
DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics)
127133

128134
// Test that maxFontScale doesn't prevent scaling down

0 commit comments

Comments
 (0)