Android-specific LayoutAnimation integration

Summary:
Turn on Fabric LayoutAnimations on Android.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D21675809

fbshipit-source-id: 49fbd3094532c5b486ea12a58898b986964ddd6e
This commit is contained in:
Joshua Gross
2020-05-20 19:40:00 -07:00
committed by Facebook GitHub Bot
parent eb9b2cedb8
commit 483f84e881
5 changed files with 96 additions and 15 deletions
@@ -70,6 +70,8 @@ public class Binding {
boolean isRTL,
boolean doLeftAndRightSwapInRTL);
public native void driveCxxAnimations();
public void register(
@NonNull JavaScriptContextHolder jsContext,
@NonNull FabricUIManager fabricUIManager,
@@ -142,6 +142,8 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
*/
private volatile boolean mDestroyed = false;
private boolean mDriveCxxAnimations = false;
private long mRunStartTime = 0l;
private long mBatchedExecutionTime = 0l;
private long mDispatchViewUpdatesTime = 0l;
@@ -967,6 +969,20 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
// TODO T31905686: Remove this method and add support for multi-threading performance counters
}
// Called from Binding.cpp
@DoNotStrip
@AnyThread
public void onAnimationStarted() {
mDriveCxxAnimations = true;
}
// Called from Binding.cpp
@DoNotStrip
@AnyThread
public void onAllAnimationsComplete() {
mDriveCxxAnimations = false;
}
@Override
public Map<String, Long> getPerformanceCounters() {
HashMap<String, Long> performanceCounters = new HashMap<>();
@@ -1002,11 +1018,18 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
return;
}
// Drive any animations from C++.
// There is a race condition here between getting/setting
// `mDriveCxxAnimations` which shouldn't matter; it's safe to call
// the mBinding method, unless mBinding has gone away.
if (mDriveCxxAnimations && mBinding != null) {
mBinding.driveCxxAnimations();
}
try {
dispatchPreMountItems(frameTimeNanos);
tryDispatchMountItems();
} catch (Exception ex) {
FLog.e(TAG, "Exception thrown when executing UIFrameGuarded", ex);
stop();
@@ -29,6 +29,7 @@ rn_xplat_cxx_library(
deps = [
react_native_xplat_target("better:better"),
react_native_xplat_target("config:config"),
react_native_xplat_target("fabric/animations:animations"),
react_native_xplat_target("fabric/uimanager:uimanager"),
react_native_xplat_target("fabric/scheduler:scheduler"),
react_native_xplat_target("fabric/componentregistry:componentregistry"),
@@ -15,6 +15,7 @@
#include <fbjni/fbjni.h>
#include <jsi/JSIDynamic.h>
#include <jsi/jsi.h>
#include <react/animations/LayoutAnimationDriver.h>
#include <react/componentregistry/ComponentDescriptorFactory.h>
#include <react/components/scrollview/ScrollViewProps.h>
#include <react/core/EventBeat.h>
@@ -72,6 +73,10 @@ std::shared_ptr<Scheduler> Binding::getScheduler() {
return scheduler_;
}
LayoutAnimationDriver *Binding::getAnimationDriver() {
return (animationDriver_ ? animationDriver_.get() : nullptr);
}
void Binding::startSurface(
jint surfaceId,
jni::alias_ref<jstring> moduleName,
@@ -91,7 +96,8 @@ void Binding::startSurface(
moduleName->toStdString(),
initialProps->consume(),
{},
context);
context,
getAnimationDriver());
}
void Binding::startSurfaceWithConstraints(
@@ -137,7 +143,8 @@ void Binding::startSurfaceWithConstraints(
moduleName->toStdString(),
initialProps->consume(),
constraints,
context);
context,
getAnimationDriver());
}
void Binding::renderTemplateToSurface(jint surfaceId, jstring uiTemplate) {
@@ -276,19 +283,23 @@ void Binding::installFabricUIManager(
collapseDeleteCreateMountingInstructions_ = reactNativeConfig_->getBool(
"react_fabric:enabled_collapse_delete_create_mounting_instructions");
disableVirtualNodePreallocation_ = reactNativeConfig_->getBool(
"react_fabric:disable_virtual_node_preallocation");
disablePreallocateViews_ = reactNativeConfig_->getBool(
"react_fabric:disabled_view_preallocation_android");
bool enableLayoutAnimations_ = reactNativeConfig_->getBool(
"react_fabric:enabled_layout_animations_android");
auto toolbox = SchedulerToolbox{};
toolbox.contextContainer = contextContainer;
toolbox.componentRegistryFactory = componentsRegistry->buildRegistryFunction;
toolbox.runtimeExecutor = runtimeExecutor;
toolbox.synchronousEventBeatFactory = synchronousBeatFactory;
toolbox.asynchronousEventBeatFactory = asynchronousBeatFactory;
scheduler_ = std::make_shared<Scheduler>(toolbox, nullptr, this);
if (enableLayoutAnimations_) {
animationDriver_ = std::make_unique<LayoutAnimationDriver>(this);
}
scheduler_ = std::make_shared<Scheduler>(toolbox, getAnimationDriver(), this);
}
void Binding::uninstallFabricUIManager() {
@@ -870,6 +881,37 @@ void Binding::setPixelDensity(float pointScaleFactor) {
pointScaleFactor_ = pointScaleFactor;
}
void Binding::onAnimationStarted() {
jni::global_ref<jobject> localJavaUIManager = getJavaUIManager();
if (!localJavaUIManager) {
LOG(ERROR) << "Binding::animationsStarted: JavaUIManager disappeared";
return;
}
static auto layoutAnimationsStartedJNI =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void()>("onAnimationStarted");
layoutAnimationsStartedJNI(localJavaUIManager);
}
void Binding::onAllAnimationsComplete() {
jni::global_ref<jobject> localJavaUIManager = getJavaUIManager();
if (!localJavaUIManager) {
LOG(ERROR) << "Binding::allAnimationsComplete: JavaUIManager disappeared";
return;
}
static auto allAnimationsCompleteJNI =
jni::findClassStatic(UIManagerJavaDescriptor)
->getMethod<void()>("onAllAnimationsComplete");
allAnimationsCompleteJNI(localJavaUIManager);
}
void Binding::driveCxxAnimations() {
scheduler_->animationTick();
}
void Binding::schedulerDidRequestPreliminaryViewAllocation(
const SurfaceId surfaceId,
const ShadowView &shadowView) {
@@ -994,6 +1036,7 @@ void Binding::registerNatives() {
makeNativeMethod("stopSurface", Binding::stopSurface),
makeNativeMethod("setConstraints", Binding::setConstraints),
makeNativeMethod("setPixelDensity", Binding::setPixelDensity),
makeNativeMethod("driveCxxAnimations", Binding::driveCxxAnimations),
makeNativeMethod(
"uninstallFabricUIManager", Binding::uninstallFabricUIManager)});
}
@@ -8,10 +8,12 @@
#pragma once
#include <fbjni/fbjni.h>
#include <react/animations/LayoutAnimationDriver.h>
#include <react/jni/JMessageQueueThread.h>
#include <react/jni/ReadableNativeMap.h>
#include <react/scheduler/Scheduler.h>
#include <react/scheduler/SchedulerDelegate.h>
#include <react/uimanager/LayoutAnimationStatusDelegate.h>
#include <memory>
#include <mutex>
#include "ComponentFactoryDelegate.h"
@@ -22,7 +24,9 @@ namespace react {
class Instance;
class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
class Binding : public jni::HybridClass<Binding>,
public SchedulerDelegate,
public LayoutAnimationStatusDelegate {
public:
constexpr static const char *const kJavaDescriptor =
"Lcom/facebook/react/fabric/Binding;";
@@ -73,26 +77,28 @@ class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
void stopSurface(jint surfaceId);
void schedulerDidFinishTransaction(
MountingCoordinator::Shared const &mountingCoordinator);
MountingCoordinator::Shared const &mountingCoordinator) override;
void schedulerDidRequestPreliminaryViewAllocation(
const SurfaceId surfaceId,
const ShadowView &shadowView);
const ShadowView &shadowView) override;
void schedulerDidDispatchCommand(
const ShadowView &shadowView,
std::string const &commandName,
folly::dynamic const args);
void setPixelDensity(float pointScaleFactor);
folly::dynamic const args) override;
void schedulerDidSetJSResponder(
SurfaceId surfaceId,
const ShadowView &shadowView,
const ShadowView &initialShadowView,
bool blockNativeResponder);
bool blockNativeResponder) override;
void schedulerDidClearJSResponder();
void schedulerDidClearJSResponder() override;
void setPixelDensity(float pointScaleFactor);
void driveCxxAnimations();
void uninstallFabricUIManager();
@@ -100,6 +106,12 @@ class Binding : public jni::HybridClass<Binding>, public SchedulerDelegate {
jni::global_ref<jobject> javaUIManager_;
std::mutex javaUIManagerMutex_;
// LayoutAnimations
virtual void onAnimationStarted() override;
virtual void onAllAnimationsComplete() override;
LayoutAnimationDriver *getAnimationDriver();
std::unique_ptr<LayoutAnimationDriver> animationDriver_;
std::shared_ptr<Scheduler> scheduler_;
std::mutex schedulerMutex_;