Skip to content

Commit

Permalink
Android-specific LayoutAnimation integration
Browse files Browse the repository at this point in the history
Summary:
Turn on Fabric LayoutAnimations on Android.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D21675809

fbshipit-source-id: 49fbd3094532c5b486ea12a58898b986964ddd6e
  • Loading branch information
JoshuaGross authored and facebook-github-bot committed May 21, 2020
1 parent eb9b2ce commit 483f84e
Show file tree
Hide file tree
Showing 5 changed files with 96 additions and 15 deletions.
Expand Up @@ -70,6 +70,8 @@ public native void setConstraints(
boolean isRTL,
boolean doLeftAndRightSwapInRTL);

public native void driveCxxAnimations();

public void register(
@NonNull JavaScriptContextHolder jsContext,
@NonNull FabricUIManager fabricUIManager,
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -967,6 +969,20 @@ public void profileNextBatch() {
// 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<>();
Expand Down Expand Up @@ -1002,11 +1018,18 @@ public void doFrameGuarded(long frameTimeNanos) {
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();
Expand Down
Expand Up @@ -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"),
Expand Down
Expand Up @@ -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>
Expand Down Expand Up @@ -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,
Expand All @@ -91,7 +96,8 @@ void Binding::startSurface(
moduleName->toStdString(),
initialProps->consume(),
{},
context);
context,
getAnimationDriver());
}

void Binding::startSurfaceWithConstraints(
Expand Down Expand Up @@ -137,7 +143,8 @@ void Binding::startSurfaceWithConstraints(
moduleName->toStdString(),
initialProps->consume(),
constraints,
context);
context,
getAnimationDriver());
}

void Binding::renderTemplateToSurface(jint surfaceId, jstring uiTemplate) {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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)});
}
Expand Down
28 changes: 20 additions & 8 deletions ReactAndroid/src/main/java/com/facebook/react/fabric/jni/Binding.h
Expand Up @@ -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"
Expand All @@ -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;";
Expand Down Expand Up @@ -73,33 +77,41 @@ 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() override;

void schedulerDidClearJSResponder();
void setPixelDensity(float pointScaleFactor);

void driveCxxAnimations();

void uninstallFabricUIManager();

// Private member variables
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_;

Expand Down

0 comments on commit 483f84e

Please sign in to comment.