Skip to content

Commit 652cb54

Browse files
ryancatfacebook-github-bot
authored andcommitted
Adding interface to wrap surface interactions for LogBox
Summary: This diff introduces a new interface named `SurfaceDelegate`. The interface abstracts the API for interacting with a surface, which is required for platforms other than mobile to implement how it wants to show and hide a surface. For existing Mobile use cases, the `LogBoxDialogSurfaceDelegate` is provided as a fallback solution so everything still works. Changelog: [Android][Added] - Add SurfaceDelegate abstraction to support interaction in multiple platforms and provide default implementation in LogBoxModule Reviewed By: mdvacca Differential Revision: D31132285 fbshipit-source-id: 13315a8bc5b7bcaee9b5e53ef5c6f6cc8cb01f31
1 parent f2eecae commit 652cb54

14 files changed

+288
-53
lines changed

ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@
7676
import com.facebook.react.bridge.queue.ReactQueueConfigurationSpec;
7777
import com.facebook.react.common.LifecycleState;
7878
import com.facebook.react.common.ReactConstants;
79+
import com.facebook.react.common.SurfaceDelegateFactory;
7980
import com.facebook.react.common.annotations.VisibleForTesting;
8081
import com.facebook.react.config.ReactFeatureFlags;
8182
import com.facebook.react.devsupport.DevSupportManagerFactory;
@@ -232,7 +233,8 @@ public static ReactInstanceManagerBuilder builder() {
232233
int minTimeLeftInFrameForNonBatchedOperationMs,
233234
@Nullable JSIModulePackage jsiModulePackage,
234235
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
235-
@Nullable ReactPackageTurboModuleManagerDelegate.Builder tmmDelegateBuilder) {
236+
@Nullable ReactPackageTurboModuleManagerDelegate.Builder tmmDelegateBuilder,
237+
@Nullable SurfaceDelegateFactory surfaceDelegateFactory) {
236238
FLog.d(TAG, "ReactInstanceManager.ctor()");
237239
initializeSoLoaderIfNecessary(applicationContext);
238240

@@ -259,7 +261,8 @@ public static ReactInstanceManagerBuilder builder() {
259261
redBoxHandler,
260262
devBundleDownloadListener,
261263
minNumShakes,
262-
customPackagerCommandHandlers);
264+
customPackagerCommandHandlers,
265+
surfaceDelegateFactory);
263266
Systrace.endSection(TRACE_TAG_REACT_JAVA_BRIDGE);
264267
mBridgeIdleDebugListener = bridgeIdleDebugListener;
265268
mLifecycleState = initialLifecycleState;

ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManagerBuilder.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.facebook.react.bridge.NativeModuleCallExceptionHandler;
2323
import com.facebook.react.bridge.NotThreadSafeBridgeIdleDebugListener;
2424
import com.facebook.react.common.LifecycleState;
25+
import com.facebook.react.common.SurfaceDelegateFactory;
2526
import com.facebook.react.devsupport.DefaultDevSupportManagerFactory;
2627
import com.facebook.react.devsupport.DevSupportManagerFactory;
2728
import com.facebook.react.devsupport.RedBoxHandler;
@@ -63,6 +64,7 @@ public class ReactInstanceManagerBuilder {
6364
private @Nullable JSIModulePackage mJSIModulesPackage;
6465
private @Nullable Map<String, RequestHandler> mCustomPackagerCommandHandlers;
6566
private @Nullable ReactPackageTurboModuleManagerDelegate.Builder mTMMDelegateBuilder;
67+
private @Nullable SurfaceDelegateFactory mSurfaceDelegateFactory;
6668

6769
/* package protected */ ReactInstanceManagerBuilder() {}
6870

@@ -195,6 +197,20 @@ public ReactInstanceManagerBuilder setRequireActivity(boolean requireActivity) {
195197
return this;
196198
}
197199

200+
/**
201+
* When the {@link SurfaceDelegateFactory} is provided, it will be used for native modules to get
202+
* a {@link SurfaceDelegate} to interact with the platform specific surface that they that needs
203+
* to be rendered in. For mobile platform this is default to be null so that these modules will
204+
* need to provide a default surface delegate. One example of such native module is LogBoxModule,
205+
* which is rendered in mobile platform with LogBoxDialog, while in VR platform with custom layer
206+
* provided by runtime.
207+
*/
208+
public ReactInstanceManagerBuilder setSurfaceDelegateFactory(
209+
@Nullable final SurfaceDelegateFactory surfaceDelegateFactory) {
210+
mSurfaceDelegateFactory = surfaceDelegateFactory;
211+
return this;
212+
}
213+
198214
/**
199215
* Sets the initial lifecycle state of the host. For example, if the host is already resumed at
200216
* creation time, we wouldn't expect an onResume call until we get an onPause call.
@@ -322,7 +338,8 @@ public ReactInstanceManager build() {
322338
mMinTimeLeftInFrameForNonBatchedOperationMs,
323339
mJSIModulesPackage,
324340
mCustomPackagerCommandHandlers,
325-
mTMMDelegateBuilder);
341+
mTMMDelegateBuilder,
342+
mSurfaceDelegateFactory);
326343
}
327344

328345
private JavaScriptExecutorFactory getDefaultJSExecutorFactory(

ReactAndroid/src/main/java/com/facebook/react/ReactNativeHost.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
import com.facebook.react.bridge.ReactMarker;
1616
import com.facebook.react.bridge.ReactMarkerConstants;
1717
import com.facebook.react.common.LifecycleState;
18+
import com.facebook.react.common.SurfaceDelegate;
19+
import com.facebook.react.common.SurfaceDelegateFactory;
1820
import com.facebook.react.devsupport.DevSupportManagerFactory;
1921
import com.facebook.react.devsupport.RedBoxHandler;
2022
import com.facebook.react.uimanager.UIImplementationProvider;
@@ -71,6 +73,7 @@ protected ReactInstanceManager createReactInstanceManager() {
7173
.setUseDeveloperSupport(getUseDeveloperSupport())
7274
.setDevSupportManagerFactory(getDevSupportManagerFactory())
7375
.setRequireActivity(getShouldRequireActivity())
76+
.setSurfaceDelegateFactory(getSurfaceDelegateFactory())
7477
.setRedBoxHandler(getRedBoxHandler())
7578
.setJavaScriptExecutorFactory(getJavaScriptExecutorFactory())
7679
.setUIImplementationProvider(getUIImplementationProvider())
@@ -132,6 +135,21 @@ public boolean getShouldRequireActivity() {
132135
return true;
133136
}
134137

138+
/**
139+
* Return the {@link SurfaceDelegateFactory} used by NativeModules to get access to a {@link
140+
* SurfaceDelegate} to interact with a surface. By default in the mobile platform the {@link
141+
* SurfaceDelegate} it returns is null, and the NativeModule needs to implement its own {@link
142+
* SurfaceDelegate} to decide how it would interact with its own container surface.
143+
*/
144+
public SurfaceDelegateFactory getSurfaceDelegateFactory() {
145+
return new SurfaceDelegateFactory() {
146+
@Override
147+
public @Nullable SurfaceDelegate createSurfaceDelegate(String moduleName) {
148+
return null;
149+
}
150+
};
151+
}
152+
135153
/**
136154
* Returns the name of the main module. Determines the URL used to fetch the JS bundle from Metro.
137155
* It is only used when dev support is enabled. This is the first file to be executed once the
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.common;
9+
10+
/**
11+
* Interface for handling a surface in React Native. In mobile platform a surface can be any
12+
* container that holds some {@link View}. For example, a Dialog can be a surface to wrap content
13+
* view object as needed. In VR platform, a surface is provided by Shell panel app sdk, which
14+
* requires custom logic to show/hide. NativeModules requires a surface will delegate interactions
15+
* with the surface to a SurfaceDelegate.
16+
*/
17+
public interface SurfaceDelegate {
18+
/**
19+
* Create the React content view that uses the appKey as the React application name
20+
*
21+
* @param appKey
22+
*/
23+
void createContentView(String appKey);
24+
25+
/**
26+
* Check if the content view is created and ready to be shown
27+
*
28+
* @return true if the content view is ready to be shown
29+
*/
30+
boolean isContentViewReady();
31+
32+
/** Destroy the React content view to avoid memory leak */
33+
void destroyContentView();
34+
35+
/** Show the surface containing the React content view */
36+
void show();
37+
38+
/** Hide the surface containing the React content view */
39+
void hide();
40+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
package com.facebook.react.common;
9+
10+
/**
11+
* Factory to create a {@link SurfaceDelegate}. The moduleName is needed to help the factory decide
12+
* which surface to return {@link SurfaceDelegate} that the given module should use to interact
13+
* with.
14+
*/
15+
public interface SurfaceDelegateFactory {
16+
/**
17+
* Create a {@link SurfaceDelegate} instance which is used to interact with a surface of platform
18+
* the app is running in.
19+
*
20+
* @param moduleName the module name that will be using the surface
21+
* @return {@link SurfaceDelegate} instance
22+
*/
23+
SurfaceDelegate createSurfaceDelegate(String moduleName);
24+
}

ReactAndroid/src/main/java/com/facebook/react/devsupport/BUCK

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ rn_android_library(
5757
react_native_dep("third-party/android/androidx:annotation"),
5858
react_native_dep("third-party/java/jsr-305:jsr-305"),
5959
react_native_target("java/com/facebook/react/bridge:bridge"),
60+
react_native_target("java/com/facebook/react/common:common"),
6061
react_native_target("java/com/facebook/react/modules/debug:interfaces"),
6162
],
6263
)

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

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import com.facebook.react.bridge.ReactMarkerConstants;
2323
import com.facebook.react.bridge.UiThreadUtil;
2424
import com.facebook.react.common.ReactConstants;
25+
import com.facebook.react.common.SurfaceDelegateFactory;
2526
import com.facebook.react.common.futures.SimpleSettableFuture;
2627
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
2728
import com.facebook.react.devsupport.interfaces.DevOptionHandler;
@@ -71,7 +72,8 @@ public BridgeDevSupportManager(
7172
@Nullable RedBoxHandler redBoxHandler,
7273
@Nullable DevBundleDownloadListener devBundleDownloadListener,
7374
int minNumShakes,
74-
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers) {
75+
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
76+
@Nullable SurfaceDelegateFactory surfaceDelegateFactory) {
7577
super(
7678
applicationContext,
7779
reactInstanceManagerHelper,
@@ -80,7 +82,8 @@ public BridgeDevSupportManager(
8082
redBoxHandler,
8183
devBundleDownloadListener,
8284
minNumShakes,
83-
customPackagerCommandHandlers);
85+
customPackagerCommandHandlers,
86+
surfaceDelegateFactory);
8487

8588
if (getDevSettings().isStartSamplingProfilerOnInit()) {
8689
// Only start the profiler. If its already running, there is an error

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import android.content.Context;
1111
import androidx.annotation.Nullable;
12+
import com.facebook.react.common.SurfaceDelegateFactory;
1213
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
1314
import com.facebook.react.devsupport.interfaces.DevSupportManager;
1415
import com.facebook.react.packagerconnection.RequestHandler;
@@ -41,6 +42,7 @@ public DevSupportManager create(
4142
null,
4243
null,
4344
minNumShakes,
45+
null,
4446
null);
4547
}
4648

@@ -53,7 +55,8 @@ public DevSupportManager create(
5355
@Nullable RedBoxHandler redBoxHandler,
5456
@Nullable DevBundleDownloadListener devBundleDownloadListener,
5557
int minNumShakes,
56-
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers) {
58+
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
59+
@Nullable SurfaceDelegateFactory surfaceDelegateFactory) {
5760
if (!enableOnCreate) {
5861
return new DisabledDevSupportManager();
5962
}
@@ -76,7 +79,8 @@ public DevSupportManager create(
7679
RedBoxHandler.class,
7780
DevBundleDownloadListener.class,
7881
int.class,
79-
Map.class);
82+
Map.class,
83+
SurfaceDelegateFactory.class);
8084
return (DevSupportManager)
8185
constructor.newInstance(
8286
applicationContext,
@@ -86,7 +90,8 @@ public DevSupportManager create(
8690
redBoxHandler,
8791
devBundleDownloadListener,
8892
minNumShakes,
89-
customPackagerCommandHandlers);
93+
customPackagerCommandHandlers,
94+
surfaceDelegateFactory);
9095
} catch (Exception e) {
9196
throw new RuntimeException(
9297
"Requested enabled DevSupportManager, but BridgeDevSupportManager class was not found"

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@
4141
import com.facebook.react.common.DebugServerException;
4242
import com.facebook.react.common.ReactConstants;
4343
import com.facebook.react.common.ShakeDetector;
44+
import com.facebook.react.common.SurfaceDelegate;
45+
import com.facebook.react.common.SurfaceDelegateFactory;
4446
import com.facebook.react.devsupport.DevServerHelper.PackagerCommandListener;
4547
import com.facebook.react.devsupport.interfaces.BundleLoadCallback;
4648
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
@@ -118,6 +120,7 @@ public interface CallbackWithBundleLoader {
118120
private @Nullable Map<String, RequestHandler> mCustomPackagerCommandHandlers;
119121

120122
private @Nullable Activity currentActivity;
123+
private @Nullable final SurfaceDelegateFactory mSurfaceDelegateFactory;
121124

122125
public DevSupportManagerBase(
123126
Context applicationContext,
@@ -127,7 +130,8 @@ public DevSupportManagerBase(
127130
@Nullable RedBoxHandler redBoxHandler,
128131
@Nullable DevBundleDownloadListener devBundleDownloadListener,
129132
int minNumShakes,
130-
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers) {
133+
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
134+
@Nullable SurfaceDelegateFactory surfaceDelegateFactory) {
131135
mReactInstanceDevHelper = reactInstanceDevHelper;
132136
mApplicationContext = applicationContext;
133137
mJSAppBundleName = packagerPathForJSBundleName;
@@ -202,7 +206,8 @@ public void onReceive(Context context, Intent intent) {
202206

203207
mRedBoxHandler = redBoxHandler;
204208
mDevLoadingViewController = new DevLoadingViewController(reactInstanceDevHelper);
205-
}
209+
mSurfaceDelegateFactory = surfaceDelegateFactory;
210+
};
206211

207212
protected abstract String getUniqueTag();
208213

@@ -1204,4 +1209,18 @@ public void setPackagerLocationCustomizer(
12041209
DevSupportManager.PackagerLocationCustomizer packagerLocationCustomizer) {
12051210
mPackagerLocationCustomizer = packagerLocationCustomizer;
12061211
}
1212+
1213+
@Override
1214+
public @Nullable Activity getCurrentActivity() {
1215+
return mReactInstanceDevHelper.getCurrentActivity();
1216+
}
1217+
1218+
@Override
1219+
public @Nullable SurfaceDelegate createSurfaceDelegate(String moduleName) {
1220+
if (mSurfaceDelegateFactory == null) {
1221+
return null;
1222+
}
1223+
1224+
return mSurfaceDelegateFactory.createSurfaceDelegate(moduleName);
1225+
}
12071226
}

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
import android.content.Context;
1111
import androidx.annotation.Nullable;
12+
import com.facebook.react.common.SurfaceDelegateFactory;
1213
import com.facebook.react.devsupport.interfaces.DevBundleDownloadListener;
1314
import com.facebook.react.devsupport.interfaces.DevSupportManager;
1415
import com.facebook.react.packagerconnection.RequestHandler;
@@ -23,5 +24,6 @@ DevSupportManager create(
2324
@Nullable RedBoxHandler redBoxHandler,
2425
@Nullable DevBundleDownloadListener devBundleDownloadListener,
2526
int minNumShakes,
26-
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers);
27+
@Nullable Map<String, RequestHandler> customPackagerCommandHandlers,
28+
@Nullable SurfaceDelegateFactory surfaceDelegateFactory);
2729
}

0 commit comments

Comments
 (0)