diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js index 93e2cc21a..f73853473 100644 --- a/Libraries/Utilities/Dimensions.js +++ b/Libraries/Utilities/Dimensions.js @@ -11,6 +11,7 @@ */ 'use strict'; +var Platform = require('Platform'); var UIManager = require('UIManager'); var invariant = require('invariant'); @@ -31,7 +32,21 @@ if (dimensions && dimensions.windowPhysicalPixels) { scale: windowPhysicalPixels.scale, fontScale: windowPhysicalPixels.fontScale, }; + if (Platform.OS === 'android') { + // Screen and window dimensions are different on android + var screenPhysicalPixels = dimensions.screenPhysicalPixels; + dimensions.screen = { + width: screenPhysicalPixels.width / screenPhysicalPixels.scale, + height: screenPhysicalPixels.height / screenPhysicalPixels.scale, + scale: screenPhysicalPixels.scale, + fontScale: screenPhysicalPixels.fontScale, + }; + // delete so no callers rely on this existing + delete dimensions.screenPhysicalPixels; + } else { + dimensions.screen = dimensions.window; + } // delete so no callers rely on this existing delete dimensions.windowPhysicalPixels; } diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java index a92b151e1..a6a69810e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerImpl.java @@ -308,8 +308,11 @@ import static com.facebook.react.bridge.ReactMarkerConstants.*; } private static void setDisplayMetrics(Context context) { - DisplayMetrics displayMetrics = new DisplayMetrics(); - displayMetrics.setTo(context.getResources().getDisplayMetrics()); + DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); + + DisplayMetrics screenDisplayMetrics = new DisplayMetrics(); + screenDisplayMetrics.setTo(displayMetrics); WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = wm.getDefaultDisplay(); @@ -317,9 +320,8 @@ import static com.facebook.react.bridge.ReactMarkerConstants.*; // The real metrics include system decor elements (e.g. soft menu bar). // // See: http://developer.android.com/reference/android/view/Display.html#getRealMetrics(android.util.DisplayMetrics) - if (Build.VERSION.SDK_INT >= 17){ - display.getRealMetrics(displayMetrics); - + if (Build.VERSION.SDK_INT >= 17) { + display.getRealMetrics(screenDisplayMetrics); } else { // For 14 <= API level <= 16, we need to invoke getRawHeight and getRawWidth to get the real dimensions. // Since react-native only supports API level 16+ we don't have to worry about other cases. @@ -330,13 +332,13 @@ import static com.facebook.react.bridge.ReactMarkerConstants.*; try { Method mGetRawH = Display.class.getMethod("getRawHeight"); Method mGetRawW = Display.class.getMethod("getRawWidth"); - displayMetrics.widthPixels = (Integer) mGetRawW.invoke(display); - displayMetrics.heightPixels = (Integer) mGetRawH.invoke(display); + screenDisplayMetrics.widthPixels = (Integer) mGetRawW.invoke(display); + screenDisplayMetrics.heightPixels = (Integer) mGetRawH.invoke(display); } catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) { throw new RuntimeException("Error getting real dimensions for API level < 17", e); } } - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setScreenDisplayMetrics(screenDisplayMetrics); } /** diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index 2271b20fd..300be54bc 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -390,7 +390,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView private class KeyboardListener implements ViewTreeObserver.OnGlobalLayoutListener { private final Rect mVisibleViewArea; private final int mMinKeyboardHeightDetected; - + private int mKeyboardHeight = 0; /* package */ KeyboardListener() { @@ -410,7 +410,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView getRootView().getWindowVisibleDisplayFrame(mVisibleViewArea); final int heightDiff = - DisplayMetricsHolder.getDisplayMetrics().heightPixels - mVisibleViewArea.bottom; + DisplayMetricsHolder.getWindowDisplayMetrics().heightPixels - mVisibleViewArea.bottom; if (mKeyboardHeight != heightDiff && heightDiff > mMinKeyboardHeightDetected) { // keyboard is now showing, or the keyboard height has changed mKeyboardHeight = heightDiff; diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java index 18135146e..c465073f8 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/DisplayMetricsHolder.java @@ -14,16 +14,39 @@ import android.util.DisplayMetrics; /** * Holds an instance of the current DisplayMetrics so we don't have to thread it through all the * classes that need it. + * Note: windowDisplayMetrics are deprecated in favor of ScreenDisplayMetrics: window metrics + * are supposed to return the drawable area but there's no guarantee that they correspond to the + * actual size of the {@link ReactRootView}. Moreover, they are not consistent with what iOS + * returns. Screen metrics returns the metrics of the entire screen, is consistent with iOS and + * should be used instead. */ public class DisplayMetricsHolder { - private static DisplayMetrics sCurrentDisplayMetrics; + private static DisplayMetrics sWindowDisplayMetrics; + private static DisplayMetrics sScreenDisplayMetrics; - public static void setDisplayMetrics(DisplayMetrics displayMetrics) { - sCurrentDisplayMetrics = displayMetrics; + /** + * @deprecated Use {@link #setScreenDisplayMetrics(DisplayMetrics)} instead. See comment above as + * to why this is not correct to use. + */ + public static void setWindowDisplayMetrics(DisplayMetrics displayMetrics) { + sWindowDisplayMetrics = displayMetrics; } - public static DisplayMetrics getDisplayMetrics() { - return sCurrentDisplayMetrics; + /** + * @deprecated Use {@link #getScreenDisplayMetrics()} instead. See comment above as to why this + * is not correct to use. + */ + @Deprecated + public static DisplayMetrics getWindowDisplayMetrics() { + return sWindowDisplayMetrics; + } + + public static void setScreenDisplayMetrics(DisplayMetrics screenDisplayMetrics) { + sScreenDisplayMetrics = screenDisplayMetrics; + } + + public static DisplayMetrics getScreenDisplayMetrics() { + return sScreenDisplayMetrics; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java index bcb24667f..6a3ecd0a5 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/PixelUtil.java @@ -23,7 +23,7 @@ public class PixelUtil { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, value, - DisplayMetricsHolder.getDisplayMetrics()); + DisplayMetricsHolder.getWindowDisplayMetrics()); } /** @@ -40,7 +40,7 @@ public class PixelUtil { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, value, - DisplayMetricsHolder.getDisplayMetrics()); + DisplayMetricsHolder.getWindowDisplayMetrics()); } /** @@ -54,7 +54,7 @@ public class PixelUtil { * Convert from PX to DP */ public static float toDIPFromPixel(float value) { - return value / DisplayMetricsHolder.getDisplayMetrics().density; + return value / DisplayMetricsHolder.getWindowDisplayMetrics().density; } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java index 8981d4354..b8363917e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java @@ -91,7 +91,8 @@ import com.facebook.react.uimanager.events.TouchEventType; "ScaleAspectFill", ImageView.ScaleType.CENTER_CROP.ordinal()))); - DisplayMetrics displayMetrics = DisplayMetricsHolder.getDisplayMetrics(); + DisplayMetrics displayMetrics = DisplayMetricsHolder.getWindowDisplayMetrics(); + DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics(); constants.put( "Dimensions", MapBuilder.of( @@ -106,7 +107,19 @@ import com.facebook.react.uimanager.events.TouchEventType; "fontScale", displayMetrics.scaledDensity, "densityDpi", - displayMetrics.densityDpi))); + displayMetrics.densityDpi), + "screenPhysicalPixels", + MapBuilder.of( + "width", + screenDisplayMetrics.widthPixels, + "height", + screenDisplayMetrics.heightPixels, + "scale", + screenDisplayMetrics.density, + "fontScale", + screenDisplayMetrics.scaledDensity, + "densityDpi", + screenDisplayMetrics.densityDpi))); constants.put( "StyleConstants", diff --git a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java index 289ad0b98..70dc6faaf 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java +++ b/ReactAndroid/src/main/java/com/facebook/react/views/art/ARTVirtualNode.java @@ -17,7 +17,6 @@ import android.graphics.Paint; import com.facebook.react.bridge.JSApplicationIllegalArgumentException; import com.facebook.react.bridge.ReadableArray; -import com.facebook.react.uimanager.ReactStylesDiffMap; import com.facebook.react.uimanager.DisplayMetricsHolder; import com.facebook.react.uimanager.annotations.ReactProp; import com.facebook.react.uimanager.ReactShadowNode; @@ -39,7 +38,7 @@ public abstract class ARTVirtualNode extends ReactShadowNode { protected final float mScale; public ARTVirtualNode() { - mScale = DisplayMetricsHolder.getDisplayMetrics().density; + mScale = DisplayMetricsHolder.getWindowDisplayMetrics().density; } @Override diff --git a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java index 7f3d96f30..97e9d6e53 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/RootViewTest.java @@ -82,7 +82,7 @@ public class RootViewTest { mReactContext = new ReactApplicationContext(RuntimeEnvironment.application); mReactContext.initializeWithInstance(mCatalystInstanceMock); DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics(); - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class); when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class)) diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java index 5da10ac93..f1944ec12 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/LayoutPropertyApplicatorTest.java @@ -54,12 +54,14 @@ public class LayoutPropertyApplicatorTest { @Before public void setup() { - DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics()); + DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics()); + DisplayMetricsHolder.setScreenDisplayMetrics(new DisplayMetrics()); } @After public void teardown() { - DisplayMetricsHolder.setDisplayMetrics(null); + DisplayMetricsHolder.setWindowDisplayMetrics(null); + DisplayMetricsHolder.setScreenDisplayMetrics(null); } public ReactStylesDiffMap buildStyles(Object... keysAndValues) { @@ -309,7 +311,7 @@ public class LayoutPropertyApplicatorTest { public void testPropertiesResetToDefault() { DisplayMetrics displayMetrics = new DisplayMetrics(); displayMetrics.density = 1.0f; - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); LayoutShadowNode reactShadowNode = spy(new LayoutShadowNode()); ReactStylesDiffMap map = buildStyles( diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java index 641e29992..bcc930fa6 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/ReactPropConstantsTest.java @@ -147,7 +147,8 @@ public class ReactPropConstantsTest { List viewManagers = Arrays.asList(new ViewManagerUnderTest()); ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application); DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics(); - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics); UIManagerModule uiManagerModule = new UIManagerModule( reactContext, viewManagers, diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java index 2652422e9..0f8b7ec91 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleConstantsTest.java @@ -60,7 +60,8 @@ public class UIManagerModuleConstantsTest { mUIImplementation = mock(UIImplementation.class); DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics(); - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics); } @Test diff --git a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java index d409752ca..3b9cd7706 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/uimanager/UIManagerModuleTest.java @@ -109,7 +109,8 @@ public class UIManagerModuleTest { mReactContext.initializeWithInstance(mCatalystInstanceMock); DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics(); - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics); UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class); when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class)) diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java index c029d4653..186e4dca4 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/image/ReactImagePropertyTest.java @@ -59,12 +59,12 @@ public class ReactImagePropertyTest { mContext.initializeWithInstance(mCatalystInstanceMock); mThemeContext = new ThemedReactContext(mContext, mContext); Fresco.initialize(mContext); - DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics()); + DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics()); } @After public void teardown() { - DisplayMetricsHolder.setDisplayMetrics(null); + DisplayMetricsHolder.setWindowDisplayMetrics(null); } public ReactStylesDiffMap buildStyles(Object... keysAndValues) { diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java index f23128ab3..68734c4a5 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/text/ReactTextTest.java @@ -373,7 +373,8 @@ public class ReactTextTest { public UIManagerModule getUIManagerModule() { ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest(); DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics(); - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics); List viewManagers = Arrays.asList( new ViewManager[] { new ReactTextViewManager(), diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java index 08489bbc0..5be0d0a79 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/ReactTextInputPropertyTest.java @@ -60,7 +60,7 @@ public class ReactTextInputPropertyTest { mContext.initializeWithInstance(mCatalystInstanceMock); mThemedContext = new ThemedReactContext(mContext, mContext); mManager = new ReactTextInputManager(); - DisplayMetricsHolder.setDisplayMetrics(new DisplayMetrics()); + DisplayMetricsHolder.setWindowDisplayMetrics(new DisplayMetrics()); } public ReactStylesDiffMap buildStyles(Object... keysAndValues) { diff --git a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java index ef89b7df0..630c80a72 100644 --- a/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java +++ b/ReactAndroid/src/test/java/com/facebook/react/views/textinput/TextInputTest.java @@ -183,7 +183,8 @@ public class TextInputTest { new ReactTextInputManager(), }); DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics(); - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics); UIManagerModule uiManagerModule = new UIManagerModule( reactContext, viewManagers,