mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Add RedBoxSurfaceDelegate to DevSupportManagerBase to abstract surface logic to show RedBox
Summary: This diff adds `RedBoxSurfaceDelegate` to replace existing logic in `DevSupportManagerBase` to abstract how we show/hide the RedBox surface. The delegate will wrap a RedBoxDialog instance, which is used to show/hide the dialog for default behavior (when there is no surface delegate for redbox got provided). I also updated the interface for delegate to accomodate new use cases: - Add `isShowing` for the `SurfaceDelegate` - Add a list of getters for `DevSupportManager` for data access in the delegate - (Update 2/7) Separate Dialog from `RedBoxDialog`, and re-named it to `RedBoxContentView`. This is to make it clear that the delegate is responsible to provide actual surface implementation (Dialog). The content view is meant to be shared. Changelog: [Android][Internal] Reviewed By: javache Differential Revision: D33987835 fbshipit-source-id: 57c20648e7f2ec8238963feca27ccd5518e7931d
This commit is contained in:
committed by
Facebook GitHub Bot
parent
5341ad8962
commit
fc7eb91f56
@@ -37,4 +37,7 @@ public interface SurfaceDelegate {
|
||||
|
||||
/** Hide the surface containing the React content view */
|
||||
void hide();
|
||||
|
||||
/** Check if the surface is currently showing */
|
||||
boolean isShowing();
|
||||
}
|
||||
|
||||
+38
-49
@@ -97,7 +97,7 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
private final DefaultNativeModuleCallExceptionHandler mDefaultNativeModuleCallExceptionHandler;
|
||||
private final DevLoadingViewController mDevLoadingViewController;
|
||||
|
||||
private @Nullable RedBoxDialog mRedBoxDialog;
|
||||
private @Nullable SurfaceDelegate mRedBoxSurfaceDelegate;
|
||||
private @Nullable AlertDialog mDevOptionsDialog;
|
||||
private @Nullable DebugOverlayController mDebugOverlayController;
|
||||
private boolean mDevLoadingViewVisible = false;
|
||||
@@ -273,7 +273,8 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
mErrorCustomizers.add(errorCustomizer);
|
||||
}
|
||||
|
||||
private Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo) {
|
||||
@Override
|
||||
public Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo) {
|
||||
if (mErrorCustomizers == null) {
|
||||
return errorInfo;
|
||||
} else {
|
||||
@@ -297,33 +298,25 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
// Since we only show the first JS error in a succession of JS errors, make sure we only
|
||||
// update the error message for that error message. This assumes that updateJSError
|
||||
// belongs to the most recent showNewJSError
|
||||
if (mRedBoxDialog == null
|
||||
|| !mRedBoxDialog.isShowing()
|
||||
|| errorCookie != mLastErrorCookie) {
|
||||
if (!mRedBoxSurfaceDelegate.isShowing() || errorCookie != mLastErrorCookie) {
|
||||
return;
|
||||
}
|
||||
StackFrame[] stack = StackTraceHelper.convertJsStackTrace(details);
|
||||
Pair<String, StackFrame[]> errorInfo =
|
||||
processErrorCustomizers(Pair.create(message, stack));
|
||||
mRedBoxDialog.setExceptionDetails(errorInfo.first, errorInfo.second);
|
||||
updateLastErrorInfo(message, stack, errorCookie, ErrorType.JS);
|
||||
// JS errors are reported here after source mapping.
|
||||
if (mRedBoxHandler != null) {
|
||||
mRedBoxHandler.handleRedbox(message, stack, ErrorType.JS);
|
||||
mRedBoxDialog.resetReporting();
|
||||
}
|
||||
mRedBoxDialog.show();
|
||||
|
||||
// The RedBox surface delegate will always show the latest error
|
||||
updateLastErrorInfo(
|
||||
message, StackTraceHelper.convertJsStackTrace(details), errorCookie, ErrorType.JS);
|
||||
mRedBoxSurfaceDelegate.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hideRedboxDialog() {
|
||||
// dismiss redbox if exists
|
||||
if (mRedBoxDialog != null) {
|
||||
mRedBoxDialog.dismiss();
|
||||
mRedBoxDialog = null;
|
||||
if (mRedBoxSurfaceDelegate == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mRedBoxSurfaceDelegate.hide();
|
||||
}
|
||||
|
||||
public @Nullable View createRootView(String appKey) {
|
||||
@@ -350,41 +343,27 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Activity context = mReactInstanceDevHelper.getCurrentActivity();
|
||||
if (context != null && !context.isFinishing() && currentActivity != context) {
|
||||
currentActivity = context;
|
||||
// Create a new RedBox when currentActivity get updated
|
||||
mRedBoxDialog =
|
||||
new RedBoxDialog(currentActivity, DevSupportManagerBase.this, mRedBoxHandler);
|
||||
if (mRedBoxSurfaceDelegate == null) {
|
||||
@Nullable SurfaceDelegate redBoxSurfaceDelegate = createSurfaceDelegate("RedBox");
|
||||
if (redBoxSurfaceDelegate != null) {
|
||||
mRedBoxSurfaceDelegate = redBoxSurfaceDelegate;
|
||||
} else {
|
||||
mRedBoxSurfaceDelegate =
|
||||
new RedBoxDialogSurfaceDelegate(DevSupportManagerBase.this);
|
||||
}
|
||||
|
||||
mRedBoxSurfaceDelegate.createContentView("RedBox");
|
||||
}
|
||||
if (currentActivity == null || currentActivity.isFinishing()) {
|
||||
FLog.e(
|
||||
ReactConstants.TAG,
|
||||
"Unable to launch redbox because react activity "
|
||||
+ "is not available, here is the error that redbox would've displayed: "
|
||||
+ message);
|
||||
return;
|
||||
}
|
||||
if (mRedBoxDialog == null) {
|
||||
mRedBoxDialog =
|
||||
new RedBoxDialog(currentActivity, DevSupportManagerBase.this, mRedBoxHandler);
|
||||
}
|
||||
if (mRedBoxDialog.isShowing()) {
|
||||
|
||||
if (mRedBoxSurfaceDelegate.isShowing()) {
|
||||
// Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
|
||||
// show the first and most actionable one.
|
||||
return;
|
||||
}
|
||||
Pair<String, StackFrame[]> errorInfo =
|
||||
processErrorCustomizers(Pair.create(message, stack));
|
||||
mRedBoxDialog.setExceptionDetails(errorInfo.first, errorInfo.second);
|
||||
|
||||
// The RedBox surface delegate will always show the latest error
|
||||
updateLastErrorInfo(message, stack, errorCookie, errorType);
|
||||
// Only report native errors here. JS errors are reported
|
||||
// inside {@link #updateJSError} after source mapping.
|
||||
if (mRedBoxHandler != null && errorType == ErrorType.NATIVE) {
|
||||
mRedBoxHandler.handleRedbox(message, stack, ErrorType.NATIVE);
|
||||
}
|
||||
mRedBoxDialog.resetReporting();
|
||||
mRedBoxDialog.show();
|
||||
mRedBoxSurfaceDelegate.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -623,6 +602,11 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
return mDevSettings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedBoxHandler getRedBoxHandler() {
|
||||
return mRedBoxHandler;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewReactContextCreated(ReactContext reactContext) {
|
||||
resetCurrentContext(reactContext);
|
||||
@@ -888,6 +872,11 @@ public abstract class DevSupportManagerBase implements DevSupportManager {
|
||||
return mLastErrorStack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLastErrorCookie() {
|
||||
return mLastErrorCookie;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable ErrorType getLastErrorType() {
|
||||
return mLastErrorType;
|
||||
|
||||
+17
@@ -8,6 +8,7 @@
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
|
||||
@@ -21,6 +22,7 @@ import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.ErrorCustomizer;
|
||||
import com.facebook.react.devsupport.interfaces.ErrorType;
|
||||
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
|
||||
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
|
||||
import com.facebook.react.devsupport.interfaces.StackFrame;
|
||||
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
|
||||
import java.io.File;
|
||||
@@ -94,6 +96,11 @@ public class DisabledDevSupportManager implements DevSupportManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RedBoxHandler getRedBoxHandler() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewReactContextCreated(ReactContext reactContext) {}
|
||||
|
||||
@@ -166,9 +173,19 @@ public class DisabledDevSupportManager implements DevSupportManager {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLastErrorCookie() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerErrorCustomizer(ErrorCustomizer errorCustomizer) {}
|
||||
|
||||
@Override
|
||||
public Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo) {
|
||||
return errorInfo;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPackagerLocationCustomizer(
|
||||
DevSupportManager.PackagerLocationCustomizer packagerLocationCustomizer) {}
|
||||
|
||||
+1
-1
@@ -14,7 +14,7 @@ import android.widget.EditText;
|
||||
|
||||
/**
|
||||
* A class allows recognizing double key tap of "R", used to reload JS in {@link
|
||||
* AbstractReactActivity}, {@link RedBoxDialog} and {@link ReactActivity}.
|
||||
* AbstractReactActivity}, {@link RedBoxDialogSurfaceDelegate} and {@link ReactActivity}.
|
||||
*/
|
||||
public class DoubleTapReloadRecognizer {
|
||||
private boolean mDoRefresh = false;
|
||||
|
||||
+5
-4
@@ -55,7 +55,7 @@ public class LogBoxDialogSurfaceDelegate implements SurfaceDelegate {
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
if (isSurfaceVisible() || !isContentViewReady()) {
|
||||
if (isShowing() || !isContentViewReady()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class LogBoxDialogSurfaceDelegate implements SurfaceDelegate {
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
if (!isSurfaceVisible()) {
|
||||
if (!isShowing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -86,7 +86,8 @@ public class LogBoxDialogSurfaceDelegate implements SurfaceDelegate {
|
||||
mDialog = null;
|
||||
}
|
||||
|
||||
private boolean isSurfaceVisible() {
|
||||
return mDialog != null;
|
||||
@Override
|
||||
public boolean isShowing() {
|
||||
return mDialog != null && mDialog.isShowing();
|
||||
}
|
||||
}
|
||||
|
||||
+44
-60
@@ -7,21 +7,20 @@
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.text.SpannedString;
|
||||
import android.text.method.LinkMovementMethod;
|
||||
import android.view.KeyEvent;
|
||||
import android.util.Pair;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
@@ -32,6 +31,7 @@ import com.facebook.react.R;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.ErrorType;
|
||||
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
|
||||
import com.facebook.react.devsupport.interfaces.RedBoxHandler.ReportCompletedListener;
|
||||
import com.facebook.react.devsupport.interfaces.StackFrame;
|
||||
@@ -42,15 +42,10 @@ import okhttp3.RequestBody;
|
||||
import org.json.JSONObject;
|
||||
|
||||
/** Dialog for displaying JS errors in an eye-catching form (red box). */
|
||||
/* package */ class RedBoxDialog implements AdapterView.OnItemClickListener {
|
||||
public class RedBoxContentView extends LinearLayout implements AdapterView.OnItemClickListener {
|
||||
|
||||
private final DevSupportManager mDevSupportManager;
|
||||
private final DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;
|
||||
private final @Nullable RedBoxHandler mRedBoxHandler;
|
||||
private final View mContentView;
|
||||
private final Context mContext;
|
||||
|
||||
private @Nullable Dialog mDialog;
|
||||
private @Nullable RedBoxHandler mRedBoxHandler;
|
||||
private DevSupportManager mDevSupportManager;
|
||||
private ListView mStackView;
|
||||
private Button mReloadJsButton;
|
||||
private Button mDismissButton;
|
||||
@@ -239,42 +234,50 @@ import org.json.JSONObject;
|
||||
}
|
||||
}
|
||||
|
||||
protected RedBoxDialog(
|
||||
Context context, DevSupportManager devSupportManager, @Nullable RedBoxHandler redBoxHandler) {
|
||||
mContext = context;
|
||||
mContentView = (View) LayoutInflater.from(context).inflate(R.layout.redbox_view, null);
|
||||
public RedBoxContentView(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public RedBoxContentView setDevSupportManager(DevSupportManager devSupportManager) {
|
||||
mDevSupportManager = devSupportManager;
|
||||
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
|
||||
mRedBoxHandler = redBoxHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
mStackView = (ListView) mContentView.findViewById(R.id.rn_redbox_stack);
|
||||
public RedBoxContentView setRedBoxHandler(@Nullable RedBoxHandler redBoxHandler) {
|
||||
mRedBoxHandler = redBoxHandler;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
LayoutInflater.from(getContext()).inflate(R.layout.redbox_view, this);
|
||||
|
||||
mStackView = (ListView) findViewById(R.id.rn_redbox_stack);
|
||||
mStackView.setOnItemClickListener(this);
|
||||
|
||||
mReloadJsButton = (Button) mContentView.findViewById(R.id.rn_redbox_reload_button);
|
||||
mReloadJsButton = (Button) findViewById(R.id.rn_redbox_reload_button);
|
||||
mReloadJsButton.setOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
mDevSupportManager.handleReloadJS();
|
||||
Assertions.assertNotNull(mDevSupportManager).handleReloadJS();
|
||||
}
|
||||
});
|
||||
mDismissButton = (Button) mContentView.findViewById(R.id.rn_redbox_dismiss_button);
|
||||
mDismissButton = (Button) findViewById(R.id.rn_redbox_dismiss_button);
|
||||
mDismissButton.setOnClickListener(
|
||||
new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dismiss();
|
||||
Assertions.assertNotNull(mDevSupportManager).hideRedboxDialog();
|
||||
}
|
||||
});
|
||||
|
||||
if (mRedBoxHandler != null && mRedBoxHandler.isReportEnabled()) {
|
||||
mLoadingIndicator = (ProgressBar) mContentView.findViewById(R.id.rn_redbox_loading_indicator);
|
||||
mLineSeparator = (View) mContentView.findViewById(R.id.rn_redbox_line_separator);
|
||||
mReportTextView = (TextView) mContentView.findViewById(R.id.rn_redbox_report_label);
|
||||
mLoadingIndicator = (ProgressBar) findViewById(R.id.rn_redbox_loading_indicator);
|
||||
mLineSeparator = (View) findViewById(R.id.rn_redbox_line_separator);
|
||||
mReportTextView = (TextView) findViewById(R.id.rn_redbox_report_label);
|
||||
mReportTextView.setMovementMethod(LinkMovementMethod.getInstance());
|
||||
mReportTextView.setHighlightColor(Color.TRANSPARENT);
|
||||
mReportButton = (Button) mContentView.findViewById(R.id.rn_redbox_report_button);
|
||||
mReportButton = (Button) findViewById(R.id.rn_redbox_report_button);
|
||||
mReportButton.setOnClickListener(mReportButtonOnClickListener);
|
||||
}
|
||||
}
|
||||
@@ -298,44 +301,25 @@ import org.json.JSONObject;
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
new OpenStackFrameTask(mDevSupportManager)
|
||||
new OpenStackFrameTask(Assertions.assertNotNull(mDevSupportManager))
|
||||
.executeOnExecutor(
|
||||
AsyncTask.THREAD_POOL_EXECUTOR, (StackFrame) mStackView.getAdapter().getItem(position));
|
||||
}
|
||||
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
mDevSupportManager.showDevOptionsDialog();
|
||||
return true;
|
||||
/** Refresh the content view with latest errors from dev support manager */
|
||||
public void refreshContentView() {
|
||||
@Nullable String message = mDevSupportManager.getLastErrorTitle();
|
||||
@Nullable StackFrame[] stack = mDevSupportManager.getLastErrorStack();
|
||||
@Nullable ErrorType errorType = mDevSupportManager.getLastErrorType();
|
||||
Pair<String, StackFrame[]> errorInfo =
|
||||
mDevSupportManager.processErrorCustomizers(Pair.create(message, stack));
|
||||
setExceptionDetails(errorInfo.first, errorInfo.second);
|
||||
|
||||
// JS errors are reported here after source mapping.
|
||||
RedBoxHandler redBoxHandler = mDevSupportManager.getRedBoxHandler();
|
||||
if (redBoxHandler != null) {
|
||||
redBoxHandler.handleRedbox(message, stack, errorType);
|
||||
resetReporting();
|
||||
}
|
||||
if (mDoubleTapReloadRecognizer.didDoubleTapR(keyCode, mDialog.getCurrentFocus())) {
|
||||
mDevSupportManager.handleReloadJS();
|
||||
}
|
||||
return mDialog.onKeyUp(keyCode, event);
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public View getContentView() {
|
||||
return mContentView;
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mDialog.isShowing();
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (mDialog == null) {
|
||||
mDialog = new Dialog(mContext, R.style.Theme_Catalyst_RedBox);
|
||||
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
}
|
||||
mDialog.setContentView(mContentView);
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
mDialog.dismiss();
|
||||
}
|
||||
}
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (c) Meta Platforms, Inc. and affiliates.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.Window;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.common.logging.FLog;
|
||||
import com.facebook.react.R;
|
||||
import com.facebook.react.common.ReactConstants;
|
||||
import com.facebook.react.common.SurfaceDelegate;
|
||||
import com.facebook.react.devsupport.interfaces.DevSupportManager;
|
||||
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
|
||||
|
||||
/**
|
||||
* The implementation of SurfaceDelegate with {@link Activity}. This is the default SurfaceDelegate
|
||||
* for Mobile.
|
||||
*/
|
||||
public class RedBoxDialogSurfaceDelegate implements SurfaceDelegate {
|
||||
|
||||
private final DoubleTapReloadRecognizer mDoubleTapReloadRecognizer;
|
||||
private final DevSupportManager mDevSupportManager;
|
||||
|
||||
private @Nullable Dialog mDialog;
|
||||
private @Nullable RedBoxContentView mRedBoxContentView;
|
||||
|
||||
public RedBoxDialogSurfaceDelegate(DevSupportManager devSupportManager) {
|
||||
mDevSupportManager = devSupportManager;
|
||||
mDoubleTapReloadRecognizer = new DoubleTapReloadRecognizer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createContentView(String appKey) {
|
||||
// The content view is created in android instead of using react app. Hence the appKey is not
|
||||
// used here.
|
||||
RedBoxHandler redBoxHandler = mDevSupportManager.getRedBoxHandler();
|
||||
Activity context = mDevSupportManager.getCurrentActivity();
|
||||
// Create a new RedBox when currentActivity get updated
|
||||
mRedBoxContentView = new RedBoxContentView(context);
|
||||
mRedBoxContentView
|
||||
.setDevSupportManager(mDevSupportManager)
|
||||
.setRedBoxHandler(redBoxHandler)
|
||||
.init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isContentViewReady() {
|
||||
return mRedBoxContentView != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroyContentView() {
|
||||
mRedBoxContentView = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
@Nullable String message = mDevSupportManager.getLastErrorTitle();
|
||||
Activity context = mDevSupportManager.getCurrentActivity();
|
||||
if (context == null || context.isFinishing()) {
|
||||
FLog.e(
|
||||
ReactConstants.TAG,
|
||||
"Unable to launch redbox because react activity "
|
||||
+ "is not available, here is the error that redbox would've displayed: "
|
||||
+ (message != null ? message : "N/A"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRedBoxContentView == null || mRedBoxContentView.getContext() != context) {
|
||||
// Create a new RedBox when currentActivity get updated
|
||||
createContentView("RedBox");
|
||||
}
|
||||
|
||||
mRedBoxContentView.refreshContentView();
|
||||
if (mDialog == null) {
|
||||
mDialog =
|
||||
new Dialog(context, R.style.Theme_Catalyst_RedBox) {
|
||||
@Override
|
||||
public boolean onKeyUp(int keyCode, KeyEvent event) {
|
||||
if (keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
mDevSupportManager.showDevOptionsDialog();
|
||||
return true;
|
||||
}
|
||||
if (mDoubleTapReloadRecognizer.didDoubleTapR(keyCode, getCurrentFocus())) {
|
||||
mDevSupportManager.handleReloadJS();
|
||||
}
|
||||
return super.onKeyUp(keyCode, event);
|
||||
}
|
||||
};
|
||||
mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
mDialog.setContentView(mRedBoxContentView);
|
||||
}
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
// dismiss redbox if exists
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
destroyContentView();
|
||||
mDialog = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowing() {
|
||||
return mDialog != null && mDialog.isShowing();
|
||||
}
|
||||
}
|
||||
+7
@@ -8,6 +8,7 @@
|
||||
package com.facebook.react.devsupport.interfaces;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.util.Pair;
|
||||
import android.view.View;
|
||||
import androidx.annotation.Nullable;
|
||||
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
|
||||
@@ -51,6 +52,8 @@ public interface DevSupportManager extends NativeModuleCallExceptionHandler {
|
||||
|
||||
DeveloperSettings getDevSettings();
|
||||
|
||||
RedBoxHandler getRedBoxHandler();
|
||||
|
||||
void onNewReactContextCreated(ReactContext reactContext);
|
||||
|
||||
void onReactInstanceDestroyed(ReactContext reactContext);
|
||||
@@ -97,8 +100,12 @@ public interface DevSupportManager extends NativeModuleCallExceptionHandler {
|
||||
@Nullable
|
||||
ErrorType getLastErrorType();
|
||||
|
||||
int getLastErrorCookie();
|
||||
|
||||
void registerErrorCustomizer(ErrorCustomizer errorCustomizer);
|
||||
|
||||
Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo);
|
||||
|
||||
/**
|
||||
* The PackagerLocationCustomizer allows you to have a dynamic packager location that is
|
||||
* determined right before loading the packager. Your customizer must call |callback|, as loading
|
||||
|
||||
Reference in New Issue
Block a user