LayoutAnimations: implement LayoutAnimationStatusDelegate for platform-specific integrations

Summary:
The LayoutAnimationStatusDelegate exists so that platforms can get a signal when animations are starting or have all completed.

This signal is meant to be used ONLY for driving animations at 60fps, or stopping that process, on the platform side.

Changelog: [Internal]

Reviewed By: mdvacca

Differential Revision: D21583109

fbshipit-source-id: 234496841bde226fcd6623c74c1a500e5cd00d99
This commit is contained in:
Joshua Gross
2020-05-20 14:11:18 -07:00
committed by Facebook GitHub Bot
parent 46310c1976
commit f0c595b57c
4 changed files with 76 additions and 1 deletions
@@ -23,6 +23,9 @@ namespace react {
class LayoutAnimationDriver : public LayoutAnimationKeyFrameManager {
public:
LayoutAnimationDriver(LayoutAnimationStatusDelegate *delegate)
: LayoutAnimationKeyFrameManager(delegate) {}
virtual ~LayoutAnimationDriver() {}
protected:
@@ -212,6 +212,12 @@ void LayoutAnimationKeyFrameManager::uiManagerDidConfigureNextLayoutAnimation(
}
}
void LayoutAnimationKeyFrameManager::setLayoutAnimationStatusDelegate(
LayoutAnimationStatusDelegate *delegate) const {
std::lock_guard<std::mutex> lock(layoutAnimationStatusDelegateMutex_);
layoutAnimationStatusDelegate_ = delegate;
}
bool LayoutAnimationKeyFrameManager::shouldOverridePullTransaction() const {
return shouldAnimateFrame();
}
@@ -341,6 +347,8 @@ LayoutAnimationKeyFrameManager::pullTransaction(
std::chrono::high_resolution_clock::now().time_since_epoch())
.count();
bool inflightAnimationsExistInitially = !inflightAnimations_.empty();
if (!mutations.empty()) {
#ifdef RN_SHADOW_TREE_INTROSPECTION
{
@@ -817,6 +825,21 @@ LayoutAnimationKeyFrameManager::pullTransaction(
mutationsForAnimation.begin(),
mutationsForAnimation.end());
// Signal to delegate if all animations are complete, or if we were not
// animating anything and now some animation exists.
if (inflightAnimationsExistInitially && inflightAnimations_.empty()) {
std::lock_guard<std::mutex> lock(layoutAnimationStatusDelegateMutex_);
if (layoutAnimationStatusDelegate_ != nullptr) {
layoutAnimationStatusDelegate_->onAllAnimationsComplete();
}
} else if (
!inflightAnimationsExistInitially && !inflightAnimations_.empty()) {
std::lock_guard<std::mutex> lock(layoutAnimationStatusDelegateMutex_);
if (layoutAnimationStatusDelegate_ != nullptr) {
layoutAnimationStatusDelegate_->onAnimationStarted();
}
}
// TODO: fill in telemetry
return MountingTransaction{
surfaceId, transactionNumber, std::move(mutations), {}};
@@ -14,6 +14,7 @@
#include <react/mounting/MountingOverrideDelegate.h>
#include <react/mounting/MountingTransaction.h>
#include <react/mounting/ShadowViewMutation.h>
#include <react/uimanager/LayoutAnimationStatusDelegate.h>
#include <react/uimanager/UIManagerAnimationDelegate.h>
namespace facebook {
@@ -37,7 +38,7 @@ enum class AnimationProperty {
};
enum class AnimationConfigurationType {
Noop, // for animation placeholders that are not animated, and should be
// executed once other animations have completed
// executed once other animations have completed
Create,
Update,
Delete
@@ -97,6 +98,12 @@ struct LayoutAnimation {
class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
public MountingOverrideDelegate {
public:
LayoutAnimationKeyFrameManager(LayoutAnimationStatusDelegate *delegate)
: layoutAnimationStatusDelegate_(delegate) {
// This is the ONLY place where we set or access
// layoutAnimationStatusDelegate_ without a mutex.
}
void uiManagerDidConfigureNextLayoutAnimation(
RawValue const &config,
std::shared_ptr<EventTarget const> successCallback,
@@ -118,7 +125,19 @@ class LayoutAnimationKeyFrameManager : public UIManagerAnimationDelegate,
MountingTelemetry const &telemetry,
ShadowViewMutationList mutations) const override;
// LayoutAnimationStatusDelegate - this is for the platform to get
// signal when animations start and complete. Setting and resetting this
// delegate is protected by a mutex; ALL method calls into this delegate are
// also protected by the mutex! The only way to set this without a mutex is
// via a constructor.
public:
void setLayoutAnimationStatusDelegate(
LayoutAnimationStatusDelegate *delegate) const;
private:
mutable std::mutex layoutAnimationStatusDelegateMutex_;
mutable LayoutAnimationStatusDelegate *layoutAnimationStatusDelegate_{};
void adjustDelayedMutationIndicesForMutation(
SurfaceId surfaceId,
ShadowViewMutation const &mutation) const;
@@ -0,0 +1,30 @@
/*
* 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
namespace facebook {
namespace react {
class LayoutAnimationStatusDelegate {
public:
/**
* Called when the LayoutAnimation engine state changes from animation nothing
* to animating something. This will only be called when you go from 0 to N>0
* active animations, N to N+1 animations will not result in this being
* called.
*/
virtual void onAnimationStarted() = 0;
/**
* Called when the LayoutAnimation engine completes all pending animations.
*/
virtual void onAllAnimationsComplete() = 0;
};
} // namespace react
} // namespace facebook