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:
Andrei Coman
2016-02-08 11:45:30 -08:00
committed by facebook-github-bot-5
parent 6b74535e97
commit 4254e8a0a9
11 changed files with 86 additions and 77 deletions

View File

@@ -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