Skip to content

Commit fc7eb91

Browse files
ryancatfacebook-github-bot
authored andcommitted
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
1 parent 5341ad8 commit fc7eb91

File tree

8 files changed

+231
-113
lines changed

8 files changed

+231
-113
lines changed

ReactAndroid/src/main/java/com/facebook/react/common/SurfaceDelegate.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,7 @@ public interface SurfaceDelegate {
3737

3838
/** Hide the surface containing the React content view */
3939
void hide();
40+
41+
/** Check if the surface is currently showing */
42+
boolean isShowing();
4043
}

ReactAndroid/src/main/java/com/facebook/react/devsupport/DevSupportManagerBase.java

Lines changed: 38 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ public interface CallbackWithBundleLoader {
9797
private final DefaultNativeModuleCallExceptionHandler mDefaultNativeModuleCallExceptionHandler;
9898
private final DevLoadingViewController mDevLoadingViewController;
9999

100-
private @Nullable RedBoxDialog mRedBoxDialog;
100+
private @Nullable SurfaceDelegate mRedBoxSurfaceDelegate;
101101
private @Nullable AlertDialog mDevOptionsDialog;
102102
private @Nullable DebugOverlayController mDebugOverlayController;
103103
private boolean mDevLoadingViewVisible = false;
@@ -273,7 +273,8 @@ public void registerErrorCustomizer(ErrorCustomizer errorCustomizer) {
273273
mErrorCustomizers.add(errorCustomizer);
274274
}
275275

276-
private Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo) {
276+
@Override
277+
public Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo) {
277278
if (mErrorCustomizers == null) {
278279
return errorInfo;
279280
} else {
@@ -297,33 +298,25 @@ public void run() {
297298
// Since we only show the first JS error in a succession of JS errors, make sure we only
298299
// update the error message for that error message. This assumes that updateJSError
299300
// belongs to the most recent showNewJSError
300-
if (mRedBoxDialog == null
301-
|| !mRedBoxDialog.isShowing()
302-
|| errorCookie != mLastErrorCookie) {
301+
if (!mRedBoxSurfaceDelegate.isShowing() || errorCookie != mLastErrorCookie) {
303302
return;
304303
}
305-
StackFrame[] stack = StackTraceHelper.convertJsStackTrace(details);
306-
Pair<String, StackFrame[]> errorInfo =
307-
processErrorCustomizers(Pair.create(message, stack));
308-
mRedBoxDialog.setExceptionDetails(errorInfo.first, errorInfo.second);
309-
updateLastErrorInfo(message, stack, errorCookie, ErrorType.JS);
310-
// JS errors are reported here after source mapping.
311-
if (mRedBoxHandler != null) {
312-
mRedBoxHandler.handleRedbox(message, stack, ErrorType.JS);
313-
mRedBoxDialog.resetReporting();
314-
}
315-
mRedBoxDialog.show();
304+
305+
// The RedBox surface delegate will always show the latest error
306+
updateLastErrorInfo(
307+
message, StackTraceHelper.convertJsStackTrace(details), errorCookie, ErrorType.JS);
308+
mRedBoxSurfaceDelegate.show();
316309
}
317310
});
318311
}
319312

320313
@Override
321314
public void hideRedboxDialog() {
322-
// dismiss redbox if exists
323-
if (mRedBoxDialog != null) {
324-
mRedBoxDialog.dismiss();
325-
mRedBoxDialog = null;
315+
if (mRedBoxSurfaceDelegate == null) {
316+
return;
326317
}
318+
319+
mRedBoxSurfaceDelegate.hide();
327320
}
328321

329322
public @Nullable View createRootView(String appKey) {
@@ -350,41 +343,27 @@ private void showNewError(
350343
new Runnable() {
351344
@Override
352345
public void run() {
353-
Activity context = mReactInstanceDevHelper.getCurrentActivity();
354-
if (context != null && !context.isFinishing() && currentActivity != context) {
355-
currentActivity = context;
356-
// Create a new RedBox when currentActivity get updated
357-
mRedBoxDialog =
358-
new RedBoxDialog(currentActivity, DevSupportManagerBase.this, mRedBoxHandler);
359-
}
360-
if (currentActivity == null || currentActivity.isFinishing()) {
361-
FLog.e(
362-
ReactConstants.TAG,
363-
"Unable to launch redbox because react activity "
364-
+ "is not available, here is the error that redbox would've displayed: "
365-
+ message);
366-
return;
367-
}
368-
if (mRedBoxDialog == null) {
369-
mRedBoxDialog =
370-
new RedBoxDialog(currentActivity, DevSupportManagerBase.this, mRedBoxHandler);
346+
if (mRedBoxSurfaceDelegate == null) {
347+
@Nullable SurfaceDelegate redBoxSurfaceDelegate = createSurfaceDelegate("RedBox");
348+
if (redBoxSurfaceDelegate != null) {
349+
mRedBoxSurfaceDelegate = redBoxSurfaceDelegate;
350+
} else {
351+
mRedBoxSurfaceDelegate =
352+
new RedBoxDialogSurfaceDelegate(DevSupportManagerBase.this);
353+
}
354+
355+
mRedBoxSurfaceDelegate.createContentView("RedBox");
371356
}
372-
if (mRedBoxDialog.isShowing()) {
357+
358+
if (mRedBoxSurfaceDelegate.isShowing()) {
373359
// Sometimes errors cause multiple errors to be thrown in JS in quick succession. Only
374360
// show the first and most actionable one.
375361
return;
376362
}
377-
Pair<String, StackFrame[]> errorInfo =
378-
processErrorCustomizers(Pair.create(message, stack));
379-
mRedBoxDialog.setExceptionDetails(errorInfo.first, errorInfo.second);
363+
364+
// The RedBox surface delegate will always show the latest error
380365
updateLastErrorInfo(message, stack, errorCookie, errorType);
381-
// Only report native errors here. JS errors are reported
382-
// inside {@link #updateJSError} after source mapping.
383-
if (mRedBoxHandler != null && errorType == ErrorType.NATIVE) {
384-
mRedBoxHandler.handleRedbox(message, stack, ErrorType.NATIVE);
385-
}
386-
mRedBoxDialog.resetReporting();
387-
mRedBoxDialog.show();
366+
mRedBoxSurfaceDelegate.show();
388367
}
389368
});
390369
}
@@ -623,6 +602,11 @@ public DevInternalSettings getDevSettings() {
623602
return mDevSettings;
624603
}
625604

605+
@Override
606+
public RedBoxHandler getRedBoxHandler() {
607+
return mRedBoxHandler;
608+
}
609+
626610
@Override
627611
public void onNewReactContextCreated(ReactContext reactContext) {
628612
resetCurrentContext(reactContext);
@@ -888,6 +872,11 @@ public void run() {
888872
return mLastErrorStack;
889873
}
890874

875+
@Override
876+
public int getLastErrorCookie() {
877+
return mLastErrorCookie;
878+
}
879+
891880
@Override
892881
public @Nullable ErrorType getLastErrorType() {
893882
return mLastErrorType;

ReactAndroid/src/main/java/com/facebook/react/devsupport/DisabledDevSupportManager.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
package com.facebook.react.devsupport;
99

1010
import android.app.Activity;
11+
import android.util.Pair;
1112
import android.view.View;
1213
import androidx.annotation.Nullable;
1314
import com.facebook.react.bridge.DefaultNativeModuleCallExceptionHandler;
@@ -21,6 +22,7 @@
2122
import com.facebook.react.devsupport.interfaces.ErrorCustomizer;
2223
import com.facebook.react.devsupport.interfaces.ErrorType;
2324
import com.facebook.react.devsupport.interfaces.PackagerStatusCallback;
25+
import com.facebook.react.devsupport.interfaces.RedBoxHandler;
2426
import com.facebook.react.devsupport.interfaces.StackFrame;
2527
import com.facebook.react.modules.debug.interfaces.DeveloperSettings;
2628
import java.io.File;
@@ -94,6 +96,11 @@ public DeveloperSettings getDevSettings() {
9496
return null;
9597
}
9698

99+
@Override
100+
public RedBoxHandler getRedBoxHandler() {
101+
return null;
102+
}
103+
97104
@Override
98105
public void onNewReactContextCreated(ReactContext reactContext) {}
99106

@@ -166,9 +173,19 @@ public void isPackagerRunning(final PackagerStatusCallback callback) {
166173
return null;
167174
}
168175

176+
@Override
177+
public int getLastErrorCookie() {
178+
return 0;
179+
}
180+
169181
@Override
170182
public void registerErrorCustomizer(ErrorCustomizer errorCustomizer) {}
171183

184+
@Override
185+
public Pair<String, StackFrame[]> processErrorCustomizers(Pair<String, StackFrame[]> errorInfo) {
186+
return errorInfo;
187+
}
188+
172189
@Override
173190
public void setPackagerLocationCustomizer(
174191
DevSupportManager.PackagerLocationCustomizer packagerLocationCustomizer) {}

ReactAndroid/src/main/java/com/facebook/react/devsupport/DoubleTapReloadRecognizer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
/**
1616
* A class allows recognizing double key tap of "R", used to reload JS in {@link
17-
* AbstractReactActivity}, {@link RedBoxDialog} and {@link ReactActivity}.
17+
* AbstractReactActivity}, {@link RedBoxDialogSurfaceDelegate} and {@link ReactActivity}.
1818
*/
1919
public class DoubleTapReloadRecognizer {
2020
private boolean mDoRefresh = false;

ReactAndroid/src/main/java/com/facebook/react/devsupport/LogBoxDialogSurfaceDelegate.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public void destroyContentView() {
5555

5656
@Override
5757
public void show() {
58-
if (isSurfaceVisible() || !isContentViewReady()) {
58+
if (isShowing() || !isContentViewReady()) {
5959
return;
6060
}
6161

@@ -74,7 +74,7 @@ public void show() {
7474

7575
@Override
7676
public void hide() {
77-
if (!isSurfaceVisible()) {
77+
if (!isShowing()) {
7878
return;
7979
}
8080

@@ -86,7 +86,8 @@ public void hide() {
8686
mDialog = null;
8787
}
8888

89-
private boolean isSurfaceVisible() {
90-
return mDialog != null;
89+
@Override
90+
public boolean isShowing() {
91+
return mDialog != null && mDialog.isShowing();
9192
}
9293
}

0 commit comments

Comments
 (0)