mirror of
https://github.com/status-im/react-native.git
synced 2025-02-26 08:05:34 +00:00
Fix DisplayMetrics KeyboardListener dependency
Summary: public KeyboardListener needs DisplayMetrics to be initialized when it is attached. At the moment, this breaks easily whenever we change these components, since DisplayMetrics are intialized in a module and KeyboardListener is created eagerly in ReactRootView, whereas ReactRootView can exist without the instance. This changes to create DisplayMetrics as soon as possible, when the react instance is built. The KeyboardListener is created and attached after the ReactRootView is attached to an existing instance, point at which DisplayMetrics have to be initialized. Reviewed By: dmmiller Differential Revision: D2911351 fb-gh-sync-id: 64d1805c5d5b2f6876adb694b565a2df059b381d
This commit is contained in:
parent
6b74535e97
commit
4254e8a0a9
@ -11,6 +11,8 @@ package com.facebook.react;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
@ -21,8 +23,12 @@ import android.app.Application;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
@ -58,6 +64,7 @@ import com.facebook.react.devsupport.ReactInstanceDevCommandsHandler;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.uimanager.AppRegistry;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.UIImplementationProvider;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewManager;
|
||||
@ -261,6 +268,7 @@ import static com.facebook.react.bridge.ReactMarkerConstants.*;
|
||||
|
||||
// TODO(9577825): remove this
|
||||
ApplicationHolder.setApplication((Application) applicationContext.getApplicationContext());
|
||||
setDisplayMetrics(applicationContext);
|
||||
|
||||
mApplicationContext = applicationContext;
|
||||
mJSBundleFile = jsBundleFile;
|
||||
@ -299,6 +307,38 @@ import static com.facebook.react.bridge.ReactMarkerConstants.*;
|
||||
SoLoader.init(applicationContext, /* native exopackage */ false);
|
||||
}
|
||||
|
||||
private static void setDisplayMetrics(Context context) {
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
displayMetrics.setTo(context.getResources().getDisplayMetrics());
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
|
||||
// Get the real display metrics if we are using API level 17 or higher.
|
||||
// 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);
|
||||
|
||||
} 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.
|
||||
//
|
||||
// Reflection exceptions are rethrown at runtime.
|
||||
//
|
||||
// See: http://stackoverflow.com/questions/14341041/how-to-get-real-screen-height-and-width/23861333#23861333
|
||||
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);
|
||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||
throw new RuntimeException("Error getting real dimensions for API level < 17", e);
|
||||
}
|
||||
}
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
}
|
||||
|
||||
/**
|
||||
* Trigger react context initialization asynchronously in a background async task. This enables
|
||||
* applications to pre-load the application JS, and execute global code before
|
||||
|
@ -55,11 +55,10 @@ import com.facebook.react.uimanager.events.TouchEventType;
|
||||
*/
|
||||
public class ReactRootView extends SizeMonitoringFrameLayout implements RootView {
|
||||
|
||||
private final KeyboardListener mKeyboardListener = new KeyboardListener();
|
||||
|
||||
private @Nullable ReactInstanceManager mReactInstanceManager;
|
||||
private @Nullable String mJSModuleName;
|
||||
private @Nullable Bundle mLaunchOptions;
|
||||
private @Nullable KeyboardListener mKeyboardListener;
|
||||
private int mTargetTag = -1;
|
||||
private final float[] mTargetCoordinates = new float[2];
|
||||
private boolean mChildIsHandlingNativeGesture = false;
|
||||
@ -107,7 +106,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
|
||||
Assertions.assertNotNull(mReactInstanceManager)
|
||||
.attachMeasuredRootView(ReactRootView.this);
|
||||
mIsAttachedToInstance = true;
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(getKeyboardListener());
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -298,7 +297,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
|
||||
if (mReactInstanceManager != null && !mAttachScheduled) {
|
||||
mReactInstanceManager.detachRootView(this);
|
||||
mIsAttachedToInstance = false;
|
||||
getViewTreeObserver().removeOnGlobalLayoutListener(mKeyboardListener);
|
||||
getViewTreeObserver().removeOnGlobalLayoutListener(getKeyboardListener());
|
||||
}
|
||||
}
|
||||
|
||||
@ -356,7 +355,7 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
|
||||
if (mWasMeasured && mIsAttachedToWindow) {
|
||||
mReactInstanceManager.attachMeasuredRootView(this);
|
||||
mIsAttachedToInstance = true;
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(mKeyboardListener);
|
||||
getViewTreeObserver().addOnGlobalLayoutListener(getKeyboardListener());
|
||||
} else {
|
||||
mAttachScheduled = true;
|
||||
}
|
||||
@ -381,9 +380,21 @@ public class ReactRootView extends SizeMonitoringFrameLayout implements RootView
|
||||
mWasMeasured = true;
|
||||
}
|
||||
|
||||
private KeyboardListener getKeyboardListener() {
|
||||
if (mKeyboardListener == null) {
|
||||
mKeyboardListener = new KeyboardListener();
|
||||
}
|
||||
return mKeyboardListener;
|
||||
}
|
||||
|
||||
private class KeyboardListener implements ViewTreeObserver.OnGlobalLayoutListener {
|
||||
private final Rect mVisibleViewArea;
|
||||
|
||||
private int mKeyboardHeight = 0;
|
||||
private final Rect mVisibleViewArea = new Rect();
|
||||
|
||||
/* package */ KeyboardListener() {
|
||||
mVisibleViewArea = new Rect();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
|
@ -11,22 +11,10 @@ package com.facebook.react.uimanager;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Display;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.csslayout.CSSLayoutContext;
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.animation.Animation;
|
||||
import com.facebook.react.bridge.Arguments;
|
||||
import com.facebook.react.bridge.Callback;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.OnBatchCompleteListener;
|
||||
@ -35,7 +23,6 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.uimanager.debug.NotThreadSafeViewHierarchyUpdateDebugListener;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.systrace.Systrace;
|
||||
@ -90,11 +77,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
||||
UIImplementation uiImplementation) {
|
||||
super(reactContext);
|
||||
mEventDispatcher = new EventDispatcher(reactContext);
|
||||
|
||||
DisplayMetrics displayMetrics = getDisplayMetrics();
|
||||
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
mModuleConstants = createConstants(displayMetrics, viewManagerList);
|
||||
mModuleConstants = createConstants(viewManagerList);
|
||||
mUIImplementation = uiImplementation;
|
||||
|
||||
reactContext.addLifecycleEventListener(this);
|
||||
@ -131,14 +114,10 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
||||
mEventDispatcher.onCatalystInstanceDestroyed();
|
||||
}
|
||||
|
||||
private static Map<String, Object> createConstants(
|
||||
DisplayMetrics displayMetrics,
|
||||
List<ViewManager> viewManagerList) {
|
||||
private static Map<String, Object> createConstants(List<ViewManager> viewManagerList) {
|
||||
Systrace.beginSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE, "CreateUIManagerConstants");
|
||||
try {
|
||||
return UIManagerModuleConstantsHelper.createConstants(
|
||||
displayMetrics,
|
||||
viewManagerList);
|
||||
return UIManagerModuleConstantsHelper.createConstants(viewManagerList);
|
||||
} finally {
|
||||
Systrace.endSection(Systrace.TRACE_TAG_REACT_JAVA_BRIDGE);
|
||||
}
|
||||
@ -460,40 +439,4 @@ public class UIManagerModule extends ReactContextBaseJavaModule implements
|
||||
public void sendAccessibilityEvent(int tag, int eventType) {
|
||||
mUIImplementation.sendAccessibilityEvent(tag, eventType);
|
||||
}
|
||||
|
||||
private DisplayMetrics getDisplayMetrics() {
|
||||
Context context = getReactApplicationContext();
|
||||
|
||||
DisplayMetrics displayMetrics = new DisplayMetrics();
|
||||
displayMetrics.setTo(context.getResources().getDisplayMetrics());
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
|
||||
// Get the real display metrics if we are using API level 17 or higher.
|
||||
// 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);
|
||||
|
||||
} 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.
|
||||
//
|
||||
// Reflection exceptions are rethrown at runtime.
|
||||
//
|
||||
// See: http://stackoverflow.com/questions/14341041/how-to-get-real-screen-height-and-width/23861333#23861333
|
||||
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);
|
||||
} catch (InvocationTargetException | IllegalAccessException | NoSuchMethodException e) {
|
||||
throw new RuntimeException("Error getting real dimensions for API level < 17", e);
|
||||
}
|
||||
}
|
||||
|
||||
return displayMetrics;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -12,7 +12,6 @@ package com.facebook.react.uimanager;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import android.text.InputType;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.ImageView;
|
||||
@ -80,7 +79,7 @@ import com.facebook.react.uimanager.events.TouchEventType;
|
||||
.build();
|
||||
}
|
||||
|
||||
public static Map<String, Object> getConstants(DisplayMetrics displayMetrics) {
|
||||
public static Map<String, Object> getConstants() {
|
||||
HashMap<String, Object> constants = new HashMap<String, Object>();
|
||||
constants.put(
|
||||
"UIView",
|
||||
@ -92,6 +91,7 @@ import com.facebook.react.uimanager.events.TouchEventType;
|
||||
"ScaleAspectFill",
|
||||
ImageView.ScaleType.CENTER_CROP.ordinal())));
|
||||
|
||||
DisplayMetrics displayMetrics = DisplayMetricsHolder.getDisplayMetrics();
|
||||
constants.put(
|
||||
"Dimensions",
|
||||
MapBuilder.of(
|
||||
|
@ -9,12 +9,9 @@
|
||||
|
||||
package com.facebook.react.uimanager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
|
||||
/**
|
||||
@ -39,10 +36,8 @@ import com.facebook.react.common.MapBuilder;
|
||||
* {@link UIManagerModuleConstants}.
|
||||
* TODO(6845124): Create a test for this
|
||||
*/
|
||||
/* package */ static Map<String, Object> createConstants(
|
||||
DisplayMetrics displayMetrics,
|
||||
List<ViewManager> viewManagers) {
|
||||
Map<String, Object> constants = UIManagerModuleConstants.getConstants(displayMetrics);
|
||||
/* package */ static Map<String, Object> createConstants(List<ViewManager> viewManagers) {
|
||||
Map<String, Object> constants = UIManagerModuleConstants.getConstants();
|
||||
Map bubblingEventTypesConstants = UIManagerModuleConstants.getBubblingEventTypeConstants();
|
||||
Map directEventTypesConstants = UIManagerModuleConstants.getDirectEventTypeConstants();
|
||||
|
||||
|
@ -29,18 +29,17 @@ import android.view.inputmethod.EditorInfo;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.bridge.JSApplicationCausedNativeException;
|
||||
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.uimanager.BaseViewManager;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewDefaults;
|
||||
import com.facebook.react.uimanager.ViewProps;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.views.text.DefaultStyleValuesUtil;
|
||||
import com.facebook.react.views.text.ReactTextUpdate;
|
||||
|
@ -13,6 +13,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.View;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
@ -145,6 +146,8 @@ public class ReactPropConstantsTest {
|
||||
public void testNativePropsIncludeCorrectTypes() {
|
||||
List<ViewManager> viewManagers = Arrays.<ViewManager>asList(new ViewManagerUnderTest());
|
||||
ReactApplicationContext reactContext = new ReactApplicationContext(RuntimeEnvironment.application);
|
||||
DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
reactContext,
|
||||
viewManagers,
|
||||
|
@ -13,6 +13,8 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
|
||||
@ -56,6 +58,9 @@ public class UIManagerModuleConstantsTest {
|
||||
public void setUp() {
|
||||
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
|
||||
mUIImplementation = mock(UIImplementation.class);
|
||||
|
||||
DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -14,6 +14,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.graphics.Color;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Choreographer;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
@ -107,9 +108,13 @@ public class UIManagerModuleTest {
|
||||
mReactContext = new ReactApplicationContext(RuntimeEnvironment.application);
|
||||
mReactContext.initializeWithInstance(mCatalystInstanceMock);
|
||||
|
||||
DisplayMetrics displayMetrics = mReactContext.getResources().getDisplayMetrics();
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
|
||||
UIManagerModule uiManagerModuleMock = mock(UIManagerModule.class);
|
||||
when(mCatalystInstanceMock.getNativeModule(UIManagerModule.class))
|
||||
.thenReturn(uiManagerModuleMock);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -21,6 +21,7 @@ import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.Spanned;
|
||||
import android.text.TextUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.text.style.AbsoluteSizeSpan;
|
||||
import android.view.Choreographer;
|
||||
import android.widget.TextView;
|
||||
@ -31,6 +32,7 @@ import com.facebook.react.bridge.ReactTestHelper;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.SimpleArray;
|
||||
import com.facebook.react.bridge.SimpleMap;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.ReactChoreographer;
|
||||
import com.facebook.react.uimanager.UIImplementation;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
@ -371,6 +373,8 @@ public class ReactTextTest {
|
||||
|
||||
public UIManagerModule getUIManagerModule() {
|
||||
ReactApplicationContext reactContext = ReactTestHelper.createCatalystContextForTest();
|
||||
DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
List<ViewManager> viewManagers = Arrays.asList(
|
||||
new ViewManager[] {
|
||||
new ReactTextViewManager(),
|
||||
|
@ -13,6 +13,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Choreographer;
|
||||
import android.widget.EditText;
|
||||
|
||||
@ -22,6 +23,7 @@ import com.facebook.react.bridge.ReactTestHelper;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.SimpleArray;
|
||||
import com.facebook.react.bridge.SimpleMap;
|
||||
import com.facebook.react.uimanager.DisplayMetricsHolder;
|
||||
import com.facebook.react.uimanager.ReactChoreographer;
|
||||
import com.facebook.react.uimanager.UIImplementation;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
@ -181,6 +183,8 @@ public class TextInputTest {
|
||||
new ViewManager[] {
|
||||
new ReactTextInputManager(),
|
||||
});
|
||||
DisplayMetrics displayMetrics = reactContext.getResources().getDisplayMetrics();
|
||||
DisplayMetricsHolder.setDisplayMetrics(displayMetrics);
|
||||
UIManagerModule uiManagerModule = new UIManagerModule(
|
||||
reactContext,
|
||||
viewManagers,
|
||||
|
Loading…
x
Reference in New Issue
Block a user