From 921a36b484233f05505f3fb47199bbaca393ad90 Mon Sep 17 00:00:00 2001 From: Andrei Coman Date: Thu, 11 Feb 2016 06:32:40 -0800 Subject: [PATCH] Expose screen metrics and window metrics Summary: public https://github.com/facebook/react-native/pull/4935 changed the window dimensions for android by replacing them with the actual screen dimensions. This changes the window dimensions back to their original values and adds `Dimensions.get('screen')` for the actual screen dimensions of the device. Reviewed By: astreet Differential Revision: D2921584 fb-gh-sync-id: 5d2677029c71d50691691dc651a11e9c8b115e8f shipit-source-id: 5d2677029c71d50691691dc651a11e9c8b115e8f --- Libraries/Utilities/Dimensions.js | 15 +++++++++ .../react/ReactInstanceManagerImpl.java | 18 +++++----- .../com/facebook/react/ReactRootView.java | 4 +-- .../react/uimanager/DisplayMetricsHolder.java | 33 ++++++++++++++++--- .../facebook/react/uimanager/PixelUtil.java | 6 ++-- .../uimanager/UIManagerModuleConstants.java | 17 ++++++++-- .../react/views/art/ARTVirtualNode.java | 3 +- .../java/com/facebook/react/RootViewTest.java | 2 +- .../LayoutPropertyApplicatorTest.java | 8 +++-- .../uimanager/ReactPropConstantsTest.java | 3 +- .../UIManagerModuleConstantsTest.java | 3 +- .../react/uimanager/UIManagerModuleTest.java | 3 +- .../views/image/ReactImagePropertyTest.java | 4 +-- .../react/views/text/ReactTextTest.java | 3 +- .../textinput/ReactTextInputPropertyTest.java | 2 +- .../react/views/textinput/TextInputTest.java | 3 +- 16 files changed, 93 insertions(+), 34 deletions(-) diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js index 93e2cc21aa1503..f73853473dc29c 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 a92b151e1d17b0..a6a69810e5e3e9 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 @@ private static void initializeSoLoaderIfNecessary(Context applicationContext) { } 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 @@ private static void setDisplayMetrics(Context context) { // 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 @@ private static void setDisplayMetrics(Context context) { 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 2271b20fd46a87..300be54bcfcff1 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 @@ private KeyboardListener getKeyboardListener() { 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 void onGlobalLayout() { 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 18135146eeecbb..c465073f81a119 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 @@ /** * 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 bcb24667fc5dd6..6a3ecd0a592936 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 static float toPixelFromDIP(float value) { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, value, - DisplayMetricsHolder.getDisplayMetrics()); + DisplayMetricsHolder.getWindowDisplayMetrics()); } /** @@ -40,7 +40,7 @@ public static float toPixelFromSP(float value) { return TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_SP, value, - DisplayMetricsHolder.getDisplayMetrics()); + DisplayMetricsHolder.getWindowDisplayMetrics()); } /** @@ -54,7 +54,7 @@ public static float toPixelFromSP(double value) { * 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 8981d4354d2a6c..b8363917e12c00 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 @@ public static Map getConstants() { "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 @@ public static Map getConstants() { "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 289ad0b9851553..70dc6faaf2af14 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 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 7f3d96f30b1a7c..97e9d6e5392a2c 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 Object answer(InvocationOnMock invocation) throws Throwable { 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 5da10ac938e7df..f1944ec1225898 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 void testEnumerations() { 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 641e299920cb0c..bcc930fa63a801 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 void testNativePropsIncludeCorrectTypes() { 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 2652422e9834c6..0f8b7ec9195e79 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 void setUp() { 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 d409752caf8a88..3b9cd770647bd1 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 Object answer(InvocationOnMock invocation) throws Throwable { 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 c029d4653e32e4..186e4dca4fe9b8 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 void setup() { 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 f23128ab3dd55e..68734c4a502aec 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 @@ private void executePendingChoreographerCallbacks() { 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 08489bbc025727..5be0d0a79949dd 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 void setup() { 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 ef89b7df002954..630c80a723a9b3 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 UIManagerModule getUIManagerModule() { new ReactTextInputManager(), }); DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics(); - DisplayMetricsHolder.setDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setWindowDisplayMetrics(displayMetrics); + DisplayMetricsHolder.setScreenDisplayMetrics(displayMetrics); UIManagerModule uiManagerModule = new UIManagerModule( reactContext, viewManagers,