diff --git a/Libraries/Utilities/Dimensions.js b/Libraries/Utilities/Dimensions.js index b4e71b554..2204ba4fc 100644 --- a/Libraries/Utilities/Dimensions.js +++ b/Libraries/Utilities/Dimensions.js @@ -11,12 +11,15 @@ */ 'use strict'; +var EventEmitter = require('EventEmitter'); var Platform = require('Platform'); var UIManager = require('UIManager'); var RCTDeviceEventEmitter = require('RCTDeviceEventEmitter'); var invariant = require('fbjs/lib/invariant'); +var eventEmitter = new EventEmitter(); +var dimensionsInitialized = false; var dimensions = {}; class Dimensions { /** @@ -60,6 +63,15 @@ class Dimensions { } Object.assign(dimensions, dims); + if (dimensionsInitialized) { + // Don't fire 'change' the first time the dimensions are set. + eventEmitter.emit('change', { + window: dimensions.window, + screen: dimensions.screen + }); + } else { + dimensionsInitialized = true; + } } /** @@ -81,6 +93,39 @@ class Dimensions { invariant(dimensions[dim], 'No dimension set for key ' + dim); return dimensions[dim]; } + + /** + * Add an event handler. Supported events: + * + * - `change`: Fires when a property within the `Dimensions` object changes. The argument + * to the event handler is an object with `window` and `screen` properties whose values + * are the same as the return values of `Dimensions.get('window')` and + * `Dimensions.get('screen')`, respectively. + */ + static addEventListener( + type: string, + handler: Function + ) { + invariant( + 'change' === type, + 'Trying to subscribe to unknown event: "%s"', type + ); + eventEmitter.addListener(type, handler); + } + + /** + * Remove an event handler. + */ + static removeEventListener( + type: string, + handler: Function + ) { + invariant( + 'change' === type, + 'Trying to remove listener for unknown event: "%s"', type + ); + eventEmitter.removeListener(type, handler); + } } Dimensions.set(UIManager.Dimensions); diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java index b6172aee2..46ad7c6c4 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactRootView.java @@ -394,27 +394,10 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView } private void emitUpdateDimensionsEvent() { - DisplayMetrics windowDisplayMetrics = DisplayMetricsHolder.getWindowDisplayMetrics(); - DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics(); - - WritableMap windowDisplayMetricsMap = Arguments.createMap(); - windowDisplayMetricsMap.putInt("width", windowDisplayMetrics.widthPixels); - windowDisplayMetricsMap.putInt("height", windowDisplayMetrics.heightPixels); - windowDisplayMetricsMap.putDouble("scale", windowDisplayMetrics.density); - windowDisplayMetricsMap.putDouble("fontScale", windowDisplayMetrics.scaledDensity); - windowDisplayMetricsMap.putDouble("densityDpi", windowDisplayMetrics.densityDpi); - - WritableMap screenDisplayMetricsMap = Arguments.createMap(); - screenDisplayMetricsMap.putInt("width", screenDisplayMetrics.widthPixels); - screenDisplayMetricsMap.putInt("height", screenDisplayMetrics.heightPixels); - screenDisplayMetricsMap.putDouble("scale", screenDisplayMetrics.density); - screenDisplayMetricsMap.putDouble("fontScale", screenDisplayMetrics.scaledDensity); - screenDisplayMetricsMap.putDouble("densityDpi", screenDisplayMetrics.densityDpi); - - WritableMap dimensionsMap = Arguments.createMap(); - dimensionsMap.putMap("windowPhysicalPixels", windowDisplayMetricsMap); - dimensionsMap.putMap("screenPhysicalPixels", screenDisplayMetricsMap); - sendEvent("didUpdateDimensions", dimensionsMap); + mReactInstanceManager + .getCurrentReactContext() + .getNativeModule(UIManagerModule.class) + .emitUpdateDimensionsEvent(); } private void sendEvent(String eventName, @Nullable WritableMap params) { diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java index ffccabcc6..1d05aa267 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModule.java @@ -32,8 +32,10 @@ import com.facebook.react.bridge.ReactMarker; import com.facebook.react.bridge.ReactMethod; import com.facebook.react.bridge.ReadableArray; import com.facebook.react.bridge.ReadableMap; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.ReactConstants; import com.facebook.react.module.annotations.ReactModule; +import com.facebook.react.modules.core.DeviceEventManagerModule; import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener; import com.facebook.react.uimanager.events.EventDispatcher; import com.facebook.systrace.Systrace; @@ -88,6 +90,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements private final Map mModuleConstants; private final UIImplementation mUIImplementation; private final MemoryTrimCallback mMemoryTrimCallback = new MemoryTrimCallback(); + private float mFontScale; private int mNextRootViewTag = 1; private int mBatchId = 0; @@ -100,7 +103,8 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements super(reactContext); DisplayMetricsHolder.initDisplayMetricsIfNotInitialized(reactContext); mEventDispatcher = new EventDispatcher(reactContext); - mModuleConstants = createConstants(viewManagerList, lazyViewManagersEnabled); + mFontScale = getReactApplicationContext().getResources().getConfiguration().fontScale; + mModuleConstants = createConstants(viewManagerList, lazyViewManagersEnabled, mFontScale); mUIImplementation = uiImplementationProvider .createUIImplementation(reactContext, viewManagerList, mEventDispatcher); @@ -133,6 +137,12 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements @Override public void onHostResume() { mUIImplementation.onHostResume(); + + float fontScale = getReactApplicationContext().getResources().getConfiguration().fontScale; + if (mFontScale != fontScale) { + mFontScale = fontScale; + emitUpdateDimensionsEvent(); + } } @Override @@ -156,13 +166,15 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements private static Map createConstants( List viewManagerList, - boolean lazyViewManagersEnabled) { + boolean lazyViewManagersEnabled, + float fontScale) { ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_START); Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants"); try { return UIManagerModuleConstantsHelper.createConstants( viewManagerList, - lazyViewManagersEnabled); + lazyViewManagersEnabled, + fontScale); } finally { Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE); ReactMarker.logMarker(CREATE_UI_MANAGER_MODULE_CONSTANTS_END); @@ -541,6 +553,16 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements mUIImplementation.sendAccessibilityEvent(tag, eventType); } + public void emitUpdateDimensionsEvent() { + sendEvent("didUpdateDimensions", UIManagerModuleConstants.getDimensionsConstants(mFontScale)); + } + + private void sendEvent(String eventName, @Nullable WritableMap params) { + getReactApplicationContext() + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); + } + /** * Schedule a block to be executed on the UI thread. Useful if you need to execute * view logic after all currently queued view updates have completed. 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 506c0063a..7dc5602ae 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstants.java @@ -16,6 +16,8 @@ import android.util.DisplayMetrics; import android.view.accessibility.AccessibilityEvent; import android.widget.ImageView; +import com.facebook.react.bridge.Arguments; +import com.facebook.react.bridge.WritableMap; import com.facebook.react.common.MapBuilder; import com.facebook.react.uimanager.events.TouchEventType; @@ -81,7 +83,7 @@ import com.facebook.react.uimanager.events.TouchEventType; .build(); } - public static Map getConstants() { + public static Map getConstants(float fontScale) { HashMap constants = new HashMap(); constants.put( "UIView", @@ -95,35 +97,9 @@ import com.facebook.react.uimanager.events.TouchEventType; "ScaleAspectCenter", ImageView.ScaleType.CENTER_INSIDE.ordinal()))); - DisplayMetrics displayMetrics = DisplayMetricsHolder.getWindowDisplayMetrics(); - DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics(); constants.put( "Dimensions", - MapBuilder.of( - "windowPhysicalPixels", - MapBuilder.of( - "width", - displayMetrics.widthPixels, - "height", - displayMetrics.heightPixels, - "scale", - displayMetrics.density, - "fontScale", - displayMetrics.scaledDensity, - "densityDpi", - displayMetrics.densityDpi), - "screenPhysicalPixels", - MapBuilder.of( - "width", - screenDisplayMetrics.widthPixels, - "height", - screenDisplayMetrics.heightPixels, - "scale", - screenDisplayMetrics.density, - "fontScale", - screenDisplayMetrics.scaledDensity, - "densityDpi", - screenDisplayMetrics.densityDpi))); + getDimensionsConstants(fontScale)); constants.put( "StyleConstants", @@ -157,4 +133,29 @@ import com.facebook.react.uimanager.events.TouchEventType; return constants; } + + public static WritableMap getDimensionsConstants(float fontScale) { + DisplayMetrics windowDisplayMetrics = DisplayMetricsHolder.getWindowDisplayMetrics(); + DisplayMetrics screenDisplayMetrics = DisplayMetricsHolder.getScreenDisplayMetrics(); + + WritableMap windowDisplayMetricsMap = Arguments.createMap(); + windowDisplayMetricsMap.putInt("width", windowDisplayMetrics.widthPixels); + windowDisplayMetricsMap.putInt("height", windowDisplayMetrics.heightPixels); + windowDisplayMetricsMap.putDouble("scale", windowDisplayMetrics.density); + windowDisplayMetricsMap.putDouble("fontScale", fontScale); + windowDisplayMetricsMap.putDouble("densityDpi", windowDisplayMetrics.densityDpi); + + WritableMap screenDisplayMetricsMap = Arguments.createMap(); + screenDisplayMetricsMap.putInt("width", screenDisplayMetrics.widthPixels); + screenDisplayMetricsMap.putInt("height", screenDisplayMetrics.heightPixels); + screenDisplayMetricsMap.putDouble("scale", screenDisplayMetrics.density); + screenDisplayMetricsMap.putDouble("fontScale", fontScale); + screenDisplayMetricsMap.putDouble("densityDpi", screenDisplayMetrics.densityDpi); + + WritableMap dimensionsMap = Arguments.createMap(); + dimensionsMap.putMap("windowPhysicalPixels", windowDisplayMetricsMap); + dimensionsMap.putMap("screenPhysicalPixels", screenDisplayMetricsMap); + + return dimensionsMap; + } } diff --git a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java index 9c1afe2b2..dbbd283d0 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java +++ b/ReactAndroid/src/main/java/com/facebook/react/uimanager/UIManagerModuleConstantsHelper.java @@ -12,6 +12,7 @@ package com.facebook.react.uimanager; import java.util.List; import java.util.Map; +import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.common.MapBuilder; import com.facebook.systrace.Systrace; import com.facebook.systrace.SystraceMessage; @@ -42,8 +43,9 @@ import static com.facebook.systrace.Systrace.TRACE_TAG_REACT_JAVA_BRIDGE; */ /* package */ static Map createConstants( List viewManagers, - boolean lazyViewManagersEnabled) { - Map constants = UIManagerModuleConstants.getConstants(); + boolean lazyViewManagersEnabled, + float fontScale) { + Map constants = UIManagerModuleConstants.getConstants(fontScale); Map bubblingEventTypesConstants = UIManagerModuleConstants.getBubblingEventTypeConstants(); Map directEventTypesConstants = UIManagerModuleConstants.getDirectEventTypeConstants();