Use SurfaceHandler in ReactSurface

Summary:
Changelog: [Internal]

Updates `ReactSurface` to use `SurfaceHandler` internally.
This removes most of the internal state in `ReactSurface` and propagates all the calls to the `SurfaceHandler`.

`FabricUIManager` now uses `SurfaceHandler` to start/stop the surface.
SurfaceId is still used for view operations. SurfaceId is also now mutable to play better with existing Android infra.

Reviewed By: shergin, mdvacca

Differential Revision: D26112992

fbshipit-source-id: 52e6860084d739381317035dc3011956d452063c
This commit is contained in:
Andrei Shikov
2021-03-08 12:20:41 -08:00
committed by Facebook GitHub Bot
parent 8b821f8f12
commit 8dc5ca6a6a
11 changed files with 423 additions and 15 deletions
@@ -100,4 +100,8 @@ public class Binding {
public void unregister() {
uninstallFabricUIManager();
}
public native void registerSurface(SurfaceHandlerBinding surfaceHandler);
public native void unregisterSurface(SurfaceHandlerBinding surfaceHandler);
}
@@ -269,6 +269,39 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
return rootTag;
}
public void startSurface(final View rootView, SurfaceHandler surfaceHandler) {
final int rootTag = ReactRootViewTagGenerator.getNextRootViewTag();
Context context = rootView.getContext();
ThemedReactContext reactContext =
new ThemedReactContext(
mReactApplicationContext, context, surfaceHandler.getModuleName(), rootTag);
mMountingManager.startSurface(rootTag, rootView, reactContext);
surfaceHandler.setSurfaceId(rootTag);
if (surfaceHandler instanceof SurfaceHandlerBinding) {
mBinding.registerSurface((SurfaceHandlerBinding) surfaceHandler);
}
surfaceHandler.start();
}
public void stopSurface(SurfaceHandler surfaceHandler) {
if (!surfaceHandler.isRunning()) {
ReactSoftException.logSoftException(
FabricUIManager.TAG,
new IllegalStateException("Trying to stop surface that hasn't started yet"));
return;
}
mMountingManager.stopSurface(surfaceHandler.getSurfaceId());
surfaceHandler.stop();
if (surfaceHandler instanceof SurfaceHandlerBinding) {
mBinding.unregisterSurface((SurfaceHandlerBinding) surfaceHandler);
}
}
/** Method called when an event has been dispatched on the C++ side. */
@DoNotStrip
@SuppressWarnings("unused")
@@ -0,0 +1,47 @@
/*
* Copyright (c) Facebook, Inc. and its 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.fabric;
import com.facebook.react.bridge.NativeMap;
import javax.annotation.concurrent.ThreadSafe;
/** Represents a Java variant of the surface, its status and inner data required to display it. */
@ThreadSafe
public interface SurfaceHandler {
/** Starts the surface if the surface is not running */
void start();
/** Stops the surface if it is currently running */
void stop();
void setProps(NativeMap props);
/**
* Provides current surface id. Id should be updated after each call to {@link
* SurfaceHandler#stop}
*/
int getSurfaceId();
/**
* Updates current surface id. Id should be updated after each call to {@link SurfaceHandler#stop}
*/
void setSurfaceId(int surfaceId);
boolean isRunning();
String getModuleName();
void setLayoutConstraints(
int widthMeasureSpec,
int heightMeasureSpec,
int offsetX,
int offsetY,
boolean doLeftAndRightSwapInRTL,
boolean isRTL);
}
@@ -0,0 +1,113 @@
/*
* Copyright (c) Facebook, Inc. and its 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.fabric;
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMaxSize;
import static com.facebook.react.fabric.mounting.LayoutMetricsConversions.getMinSize;
import com.facebook.jni.HybridData;
import com.facebook.proguard.annotations.DoNotStrip;
import com.facebook.react.bridge.NativeMap;
public class SurfaceHandlerBinding implements SurfaceHandler {
static {
FabricSoLoader.staticInit();
}
private static final int NO_SURFACE_ID = 0;
@DoNotStrip private final HybridData mHybridData;
private final float mPixelDensity;
private static native HybridData initHybrid(int surfaceId, String moduleName);
public SurfaceHandlerBinding(String moduleName, float pixelDensity) {
mHybridData = initHybrid(NO_SURFACE_ID, moduleName);
mPixelDensity = pixelDensity;
}
@Override
public int getSurfaceId() {
return getSurfaceIdNative();
}
private native int getSurfaceIdNative();
@Override
public void setSurfaceId(int surfaceId) {
setSurfaceIdNative(surfaceId);
}
private native void setSurfaceIdNative(int surfaceId);
@Override
public String getModuleName() {
return getModuleNameNative();
}
private native String getModuleNameNative();
@Override
public void start() {
startNative();
}
private native void startNative();
@Override
public void stop() {
stopNative();
}
private native void stopNative();
@Override
public boolean isRunning() {
return isRunningNative();
}
private native boolean isRunningNative();
@Override
public void setLayoutConstraints(
int widthMeasureSpec,
int heightMeasureSpec,
int offsetX,
int offsetY,
boolean doLeftAndRightSwapInRTL,
boolean isRTL) {
setLayoutConstraintsNative(
getMinSize(widthMeasureSpec) / mPixelDensity,
getMaxSize(widthMeasureSpec) / mPixelDensity,
getMinSize(heightMeasureSpec) / mPixelDensity,
getMaxSize(heightMeasureSpec) / mPixelDensity,
offsetX / mPixelDensity,
offsetY / mPixelDensity,
doLeftAndRightSwapInRTL,
isRTL,
mPixelDensity);
}
private native void setLayoutConstraintsNative(
float minWidth,
float maxWidth,
float minHeight,
float maxHeight,
float offsetX,
float offsetY,
boolean doLeftAndRightSwapInRTL,
boolean isRTL,
float pixelDensity);
@Override
public void setProps(NativeMap props) {
setPropsNative(props);
}
private native void setPropsNative(NativeMap props);
}
@@ -376,6 +376,14 @@ void Binding::stopSurface(jint surfaceId) {
}
}
void Binding::registerSurface(SurfaceHandlerBinding *surfaceHandler) {
surfaceHandler->registerScheduler(getScheduler());
}
void Binding::unregisterSurface(SurfaceHandlerBinding *surfaceHandler) {
surfaceHandler->unregisterScheduler(getScheduler());
}
static inline float scale(Float value, Float pointScaleFactor) {
std::feclearexcept(FE_ALL_EXCEPT);
float result = value * pointScaleFactor;
@@ -1214,21 +1222,24 @@ void Binding::schedulerDidSetIsJSResponder(
}
void Binding::registerNatives() {
registerHybrid(
{makeNativeMethod("initHybrid", Binding::initHybrid),
makeNativeMethod(
"installFabricUIManager", Binding::installFabricUIManager),
makeNativeMethod("startSurface", Binding::startSurface),
makeNativeMethod(
"startSurfaceWithConstraints", Binding::startSurfaceWithConstraints),
makeNativeMethod(
"renderTemplateToSurface", Binding::renderTemplateToSurface),
makeNativeMethod("stopSurface", Binding::stopSurface),
makeNativeMethod("setConstraints", Binding::setConstraints),
makeNativeMethod("setPixelDensity", Binding::setPixelDensity),
makeNativeMethod("driveCxxAnimations", Binding::driveCxxAnimations),
makeNativeMethod(
"uninstallFabricUIManager", Binding::uninstallFabricUIManager)});
registerHybrid({
makeNativeMethod("initHybrid", Binding::initHybrid),
makeNativeMethod(
"installFabricUIManager", Binding::installFabricUIManager),
makeNativeMethod("startSurface", Binding::startSurface),
makeNativeMethod(
"startSurfaceWithConstraints", Binding::startSurfaceWithConstraints),
makeNativeMethod(
"renderTemplateToSurface", Binding::renderTemplateToSurface),
makeNativeMethod("stopSurface", Binding::stopSurface),
makeNativeMethod("setConstraints", Binding::setConstraints),
makeNativeMethod("setPixelDensity", Binding::setPixelDensity),
makeNativeMethod("driveCxxAnimations", Binding::driveCxxAnimations),
makeNativeMethod(
"uninstallFabricUIManager", Binding::uninstallFabricUIManager),
makeNativeMethod("registerSurface", Binding::registerSurface),
makeNativeMethod("unregisterSurface", Binding::unregisterSurface),
});
}
} // namespace react
@@ -20,6 +20,7 @@
#include "ComponentFactory.h"
#include "EventBeatManager.h"
#include "JBackgroundExecutor.h"
#include "SurfaceHandlerBinding.h"
namespace facebook {
namespace react {
@@ -124,6 +125,10 @@ class Binding : public jni::HybridClass<Binding>,
void stopSurface(jint surfaceId);
void registerSurface(SurfaceHandlerBinding *surfaceHandler);
void unregisterSurface(SurfaceHandlerBinding *surfaceHandler);
void schedulerDidFinishTransaction(
MountingCoordinator::Shared const &mountingCoordinator) override;
@@ -13,6 +13,7 @@
#include "EventBeatManager.h"
#include "EventEmitterWrapper.h"
#include "StateWrapperImpl.h"
#include "SurfaceHandlerBinding.h"
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
return facebook::jni::initialize(vm, [] {
@@ -22,5 +23,6 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *) {
facebook::react::StateWrapperImpl::registerNatives();
facebook::react::ComponentFactory::registerNatives();
facebook::react::CoreComponentsRegistry::registerNatives();
facebook::react::SurfaceHandlerBinding::registerNatives();
});
}
@@ -0,0 +1,123 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#include "SurfaceHandlerBinding.h"
#include <react/renderer/scheduler/Scheduler.h>
namespace facebook {
namespace react {
SurfaceHandlerBinding::SurfaceHandlerBinding(
SurfaceId surfaceId,
std::string const &moduleName)
: surfaceHandler_(moduleName, surfaceId) {}
void SurfaceHandlerBinding::start() {
std::unique_lock<better::shared_mutex> lock(lifecycleMutex_);
surfaceHandler_.setDisplayMode(SurfaceHandler::DisplayMode::Visible);
if (surfaceHandler_.getStatus() != SurfaceHandler::Status::Running) {
surfaceHandler_.start();
}
}
void SurfaceHandlerBinding::stop() {
std::unique_lock<better::shared_mutex> lock(lifecycleMutex_);
if (surfaceHandler_.getStatus() == SurfaceHandler::Status::Running) {
surfaceHandler_.stop();
}
}
jint SurfaceHandlerBinding::getSurfaceId() {
return surfaceHandler_.getSurfaceId();
}
void SurfaceHandlerBinding::setSurfaceId(jint surfaceId) {
surfaceHandler_.setSurfaceId(surfaceId);
}
jboolean SurfaceHandlerBinding::isRunning() {
return surfaceHandler_.getStatus() == SurfaceHandler::Status::Running;
}
jni::local_ref<jstring> SurfaceHandlerBinding::getModuleName() {
return jni::make_jstring(surfaceHandler_.getModuleName());
}
jni::local_ref<SurfaceHandlerBinding::jhybriddata>
SurfaceHandlerBinding::initHybrid(
jni::alias_ref<jclass>,
jint surfaceId,
jni::alias_ref<jstring> moduleName) {
auto env = jni::Environment::current();
const char *moduleNameValue =
env->GetStringUTFChars(moduleName.get(), JNI_FALSE);
env->ReleaseStringUTFChars(moduleName.get(), moduleNameValue);
return makeCxxInstance(surfaceId, moduleNameValue);
}
void SurfaceHandlerBinding::registerScheduler(
std::shared_ptr<Scheduler> scheduler) {
scheduler->registerSurface(surfaceHandler_);
}
void SurfaceHandlerBinding::unregisterScheduler(
std::shared_ptr<Scheduler> scheduler) {
scheduler->unregisterSurface(surfaceHandler_);
}
void SurfaceHandlerBinding::setLayoutConstraints(
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean doLeftAndRightSwapInRTL,
jboolean isRTL,
jfloat pixelDensity) {
LayoutConstraints constraints = {};
constraints.minimumSize = {minWidth, minHeight};
constraints.maximumSize = {maxWidth, maxHeight};
constraints.layoutDirection =
isRTL ? LayoutDirection::RightToLeft : LayoutDirection::LeftToRight;
LayoutContext context = {};
context.swapLeftAndRightInRTL = doLeftAndRightSwapInRTL;
context.pointScaleFactor = pixelDensity;
context.viewportOffset = {offsetX, offsetY};
surfaceHandler_.constraintLayout(constraints, context);
}
void SurfaceHandlerBinding::setProps(NativeMap *props) {
surfaceHandler_.setProps(props->consume());
}
void SurfaceHandlerBinding::registerNatives() {
registerHybrid({
makeNativeMethod("initHybrid", SurfaceHandlerBinding::initHybrid),
makeNativeMethod(
"getSurfaceIdNative", SurfaceHandlerBinding::getSurfaceId),
makeNativeMethod(
"setSurfaceIdNative", SurfaceHandlerBinding::setSurfaceId),
makeNativeMethod("isRunningNative", SurfaceHandlerBinding::isRunning),
makeNativeMethod(
"getModuleNameNative", SurfaceHandlerBinding::getModuleName),
makeNativeMethod("startNative", SurfaceHandlerBinding::start),
makeNativeMethod("stopNative", SurfaceHandlerBinding::stop),
makeNativeMethod(
"setLayoutConstraintsNative",
SurfaceHandlerBinding::setLayoutConstraints),
makeNativeMethod("setPropsNative", SurfaceHandlerBinding::setProps),
});
}
} // namespace react
} // namespace facebook
@@ -0,0 +1,64 @@
/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <fbjni/fbjni.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/renderer/scheduler/SurfaceHandler.h>
namespace facebook {
namespace react {
class SurfaceHandlerBinding : public jni::HybridClass<SurfaceHandlerBinding> {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/SurfaceHandlerBinding;";
static void registerNatives();
SurfaceHandlerBinding(SurfaceId surfaceId, std::string const &moduleName);
void start();
void stop();
void registerScheduler(std::shared_ptr<Scheduler> scheduler);
void unregisterScheduler(std::shared_ptr<Scheduler> scheduler);
jint getSurfaceId();
void setSurfaceId(jint surfaceId);
jni::local_ref<jstring> getModuleName();
jboolean isRunning();
void setLayoutConstraints(
jfloat minWidth,
jfloat maxWidth,
jfloat minHeight,
jfloat maxHeight,
jfloat offsetX,
jfloat offsetY,
jboolean doLeftAndRightSwapInRTL,
jboolean isRTL,
jfloat pixelDensity);
void setProps(NativeMap *props);
private:
mutable better::shared_mutex lifecycleMutex_;
const SurfaceHandler surfaceHandler_;
jni::alias_ref<SurfaceHandlerBinding::jhybriddata> jhybridobject_;
static jni::local_ref<jhybriddata> initHybrid(
jni::alias_ref<jclass>,
jint surfaceId,
jni::alias_ref<jstring> moduleName);
};
} // namespace react
} // namespace facebook