Execute Animated.js declarative animation on UIThread on Android.

Summary:This is the first from the series of PRs I'm going to be sending shorty that would let Animated.js animations to run off the JS thread (for Android only).

This PR introduce a new native module that will be used for offloading animations - NativeAnimatedModule. It has a simple API that allows for animated nodes management via methods like: create/drop animated node, connect/disconnect nodes, start animation of a value node, attach/detach animated from a native view.

Similarly to how we handle UIManager view hierarchy updates we create a queue of animated graph operations that are then executed on the UI thread. This isolates us from problems that may be caused by concurrent updates of animated graph while UI thread is "executing" the animation.

The most important class NativeAnimatedNodesManager.java implements a management interface for animated nodes graph as well as implements a graph traversal algorithm that is run for each animation frame. For each animation frame we visit animated nodes th
Closes https://github.com/facebook/react-native/pull/6466

Differential Revision: D3092739

Pulled By: astreet

fb-gh-sync-id: 665b49900b7367c91a93b9d8864f78fb90bb36ba
shipit-source-id: 665b49900b7367c91a93b9d8864f78fb90bb36ba
This commit is contained in:
Krzysztof Magiera
2016-03-24 06:18:39 -07:00
committed by Facebook Github Bot 5
parent bd8007300f
commit 65ccdffc8d
14 changed files with 1290 additions and 9 deletions

View File

@@ -0,0 +1,63 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.react.animated;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableMap;
/**
* Implementation of {@link AnimationDriver} which provides a support for simple time-based
* animations that are pre-calculate on the JS side. For each animation frame JS provides a value
* from 0 to 1 that indicates a progress of the animation at that frame.
*/
class FrameBasedAnimationDriver extends AnimationDriver {
private long mStartFrameTimeNanos = -1;
private final double[] mFrames;
private final double mToValue;
private double mFromValue;
FrameBasedAnimationDriver(ReadableMap config) {
ReadableArray frames = config.getArray("frames");
int numberOfFrames = frames.size();
mFrames = new double[numberOfFrames];
for (int i = 0; i < numberOfFrames; i++) {
mFrames[i] = frames.getDouble(i);
}
mToValue = config.getDouble("toValue");
}
@Override
public void runAnimationStep(long frameTimeNanos) {
if (mStartFrameTimeNanos < 0) {
mStartFrameTimeNanos = frameTimeNanos;
mFromValue = mAnimatedValue.mValue;
}
long timeFromStartNanos = (frameTimeNanos - mStartFrameTimeNanos);
// frames are calculated at 60FPS, to get index by a given time offset from the start of the
// animation, we take the time diff in millisecond and divide it by 60 frames per 1000ms.
int frameIndex = (int) (timeFromStartNanos / 1000000L * 60L / 1000L);
if (frameIndex < 0) {
throw new IllegalStateException("Calculated frame index should never be lower than 0");
} else if (mHasFinished) {
// nothing to do here
return;
}
double nextValue;
if (frameIndex >= mFrames.length - 1) {
// animation has completed, no more frames left
mHasFinished = true;
nextValue = mToValue;
} else {
nextValue = mFromValue + mFrames[frameIndex] * (mToValue - mFromValue);
}
mAnimatedValue.mValue = nextValue;
}
}