Merge "Run RevealAnimator on RT" into lmp-dev

This commit is contained in:
John Reck
2014-08-21 14:23:26 +00:00
committed by Android (Google) Code Review
6 changed files with 116 additions and 286 deletions

View File

@@ -370,6 +370,7 @@ public abstract class Animator implements Cloneable {
* @hide
*/
public void reverse() {
throw new IllegalStateException("Reverse is not supported");
}
/**

View File

@@ -26,148 +26,21 @@ import android.view.View;
*
* @hide
*/
public class RevealAnimator extends ValueAnimator {
public class RevealAnimator extends RenderNodeAnimator {
private View mClipView;
private int mX, mY;
private float mStartRadius, mEndRadius;
private float mDelta;
private boolean mMayRunAsync;
// If this is null, we are running on the UI thread driven by the base
// ValueAnimator class. If this is not null, forward requests on to this
// Animator instead.
private RenderNodeAnimator mRtAnimator;
public RevealAnimator(View clipView, int x, int y,
float startRadius, float endRadius) {
super(x, y, startRadius, endRadius);
mClipView = clipView;
mStartRadius = startRadius;
mEndRadius = endRadius;
mDelta = endRadius - startRadius;
mX = x;
mY = y;
super.setValues(PropertyValuesHolder.ofFloat("radius", startRadius, endRadius));
setTarget(mClipView);
}
@Override
void animateValue(float fraction) {
super.animateValue(fraction);
fraction = getAnimatedFraction();
float radius = mStartRadius + (mDelta * fraction);
mClipView.setRevealClip(true, mX, mY, radius);
}
@Override
protected void endAnimation(AnimationHandler handler) {
protected void onFinished() {
mClipView.setRevealClip(false, 0, 0, 0);
super.endAnimation(handler);
super.onFinished();
}
@Override
public void setAllowRunningAsynchronously(boolean mayRunAsync) {
mMayRunAsync = mayRunAsync;
}
private boolean canRunAsync() {
if (!mMayRunAsync) {
return false;
}
if (mUpdateListeners != null && mUpdateListeners.size() > 0) {
return false;
}
// TODO: Have RNA support this
if (getRepeatCount() != 0) {
return false;
}
return true;
}
@Override
public void start() {
if (mRtAnimator != null) {
mRtAnimator.end();
mRtAnimator = null;
}
if (canRunAsync()) {
mRtAnimator = new RenderNodeAnimator(mX, mY, mStartRadius, mEndRadius);
mRtAnimator.setDuration(getDuration());
mRtAnimator.setInterpolator(getInterpolator());
mRtAnimator.setTarget(mClipView);
// TODO: Listeners
mRtAnimator.start();
} else {
super.start();
}
}
@Override
public void cancel() {
if (mRtAnimator != null) {
mRtAnimator.cancel();
} else {
super.cancel();
}
}
@Override
public void end() {
if (mRtAnimator != null) {
mRtAnimator.end();
} else {
super.end();
}
}
@Override
public void resume() {
if (mRtAnimator != null) {
// TODO: Support? Reject?
} else {
super.resume();
}
}
@Override
public void pause() {
if (mRtAnimator != null) {
// TODO: see resume()
} else {
super.pause();
}
}
@Override
public boolean isRunning() {
if (mRtAnimator != null) {
return mRtAnimator.isRunning();
} else {
return super.isRunning();
}
}
@Override
public boolean isStarted() {
if (mRtAnimator != null) {
return mRtAnimator.isStarted();
} else {
return super.isStarted();
}
}
@Override
public void reverse() {
if (mRtAnimator != null) {
// TODO support
} else {
super.reverse();
}
}
@Override
public RevealAnimator clone() {
RevealAnimator anim = (RevealAnimator) super.clone();
anim.mRtAnimator = null;
return anim;
}
}

View File

@@ -93,6 +93,14 @@ public class RenderNodeAnimator extends Animator {
private long mUnscaledDuration = 300;
private long mUnscaledStartDelay = 0;
// If this is true, we will run any start delays on the UI thread. This is
// the safe default, and is necessary to ensure start listeners fire at
// the correct time. Animators created by RippleDrawable (the
// CanvasProperty<> ones) do not have this expectation, and as such will
// set this to false so that the renderthread handles the startdelay instead
private final boolean mUiThreadHandlesDelay;
private long mStartDelay = 0;
private long mStartTime;
public static int mapViewPropertyToRenderProperty(int viewProperty) {
return sViewPropertyAnimatorMap.get(viewProperty);
@@ -101,6 +109,7 @@ public class RenderNodeAnimator extends Animator {
public RenderNodeAnimator(int property, float finalValue) {
mRenderProperty = property;
mFinalValue = finalValue;
mUiThreadHandlesDelay = true;
init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
property, finalValue));
}
@@ -109,6 +118,7 @@ public class RenderNodeAnimator extends Animator {
init(nCreateCanvasPropertyFloatAnimator(
new WeakReference<RenderNodeAnimator>(this),
property.getNativeContainer(), finalValue));
mUiThreadHandlesDelay = false;
}
/**
@@ -123,11 +133,13 @@ public class RenderNodeAnimator extends Animator {
init(nCreateCanvasPropertyPaintAnimator(
new WeakReference<RenderNodeAnimator>(this),
property.getNativeContainer(), paintField, finalValue));
mUiThreadHandlesDelay = false;
}
public RenderNodeAnimator(int x, int y, float startRadius, float endRadius) {
init(nCreateRevealAnimator(new WeakReference<RenderNodeAnimator>(this),
x, y, startRadius, endRadius));
mUiThreadHandlesDelay = true;
}
private void init(long ptr) {
@@ -169,6 +181,16 @@ public class RenderNodeAnimator extends Animator {
mStarted = true;
applyInterpolator();
if (mStartDelay <= 0 || !mUiThreadHandlesDelay) {
nSetStartDelay(mNativePtr.get(), mStartDelay);
doStart();
} else {
getHelper().addDelayedAnimation(this);
}
}
private void doStart() {
nStart(mNativePtr.get());
// Alpha is a special snowflake that has the canonical value stored
@@ -195,6 +217,7 @@ public class RenderNodeAnimator extends Animator {
@Override
public void cancel() {
if (!mFinished) {
getHelper().removeDelayedAnimation(this);
nEnd(mNativePtr.get());
final ArrayList<AnimatorListener> listeners = getListeners();
@@ -258,7 +281,7 @@ public class RenderNodeAnimator extends Animator {
throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
}
mUnscaledStartDelay = startDelay;
nSetStartDelay(mNativePtr.get(), (long) (startDelay * ValueAnimator.getDurationScale()));
mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
}
@Override
@@ -303,7 +326,7 @@ public class RenderNodeAnimator extends Animator {
return mInterpolator;
}
private void onFinished() {
protected void onFinished() {
mFinished = true;
final ArrayList<AnimatorListener> listeners = getListeners();
@@ -317,6 +340,82 @@ public class RenderNodeAnimator extends Animator {
return mNativePtr.get();
}
/**
* @return true if the animator was started, false if still delayed
*/
private boolean processDelayed(long frameTimeMs) {
if (mStartTime == 0) {
mStartTime = frameTimeMs;
} else if ((frameTimeMs - mStartTime) >= mStartDelay) {
doStart();
return true;
}
return false;
}
private static DelayedAnimationHelper getHelper() {
DelayedAnimationHelper helper = sAnimationHelper.get();
if (helper == null) {
helper = new DelayedAnimationHelper();
sAnimationHelper.set(helper);
}
return helper;
}
private static ThreadLocal<DelayedAnimationHelper> sAnimationHelper =
new ThreadLocal<DelayedAnimationHelper>();
private static class DelayedAnimationHelper implements Runnable {
private ArrayList<RenderNodeAnimator> mDelayedAnims = new ArrayList<RenderNodeAnimator>();
private final Choreographer mChoreographer;
private boolean mCallbackScheduled;
public DelayedAnimationHelper() {
mChoreographer = Choreographer.getInstance();
}
public void addDelayedAnimation(RenderNodeAnimator animator) {
mDelayedAnims.add(animator);
scheduleCallback();
}
public void removeDelayedAnimation(RenderNodeAnimator animator) {
mDelayedAnims.remove(animator);
}
private void scheduleCallback() {
if (!mCallbackScheduled) {
mCallbackScheduled = true;
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
}
}
@Override
public void run() {
long frameTimeMs = mChoreographer.getFrameTime();
mCallbackScheduled = false;
int end = 0;
for (int i = 0; i < mDelayedAnims.size(); i++) {
RenderNodeAnimator animator = mDelayedAnims.get(i);
if (!animator.processDelayed(frameTimeMs)) {
if (end != i) {
mDelayedAnims.set(end, animator);
}
end++;
}
}
while (mDelayedAnims.size() > end) {
mDelayedAnims.remove(mDelayedAnims.size() - 1);
}
if (mDelayedAnims.size() > 0) {
scheduleCallback();
}
}
}
// Called by native
private static void callOnFinished(WeakReference<RenderNodeAnimator> weakThis) {
RenderNodeAnimator animator = weakThis.get();
@@ -325,6 +424,11 @@ public class RenderNodeAnimator extends Animator {
}
}
@Override
public Animator clone() {
throw new IllegalStateException("Cannot clone this animator");
}
private static native long nCreateAnimator(WeakReference<RenderNodeAnimator> weakThis,
int property, float finalValue);
private static native long nCreateCanvasPropertyFloatAnimator(WeakReference<RenderNodeAnimator> weakThis,

View File

@@ -1,151 +0,0 @@
/*
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.view;
import android.animation.ValueAnimator;
import java.util.ArrayList;
/**
* This class provides compatibility for things like start listeners &
* start delays for use by ViewPropertyAnimator and ObjectAnimator
* @hide
*/
public class RenderNodeAnimatorCompat extends RenderNodeAnimator {
private long mUnscaledStartDelay = 0;
private long mStartDelay = 0;
private long mStartTime;
private boolean mCanceled;
private boolean mStarted;
public RenderNodeAnimatorCompat(int property, float finalValue) {
super(property, finalValue);
}
@Override
public void setStartDelay(long startDelay) {
mUnscaledStartDelay = startDelay;
mStartDelay = (long) (ValueAnimator.getDurationScale() * startDelay);
}
@Override
public long getStartDelay() {
return mUnscaledStartDelay;
}
@Override
public void start() {
mStarted = true;
if (mStartDelay <= 0) {
doStart();
} else {
getHelper().addDelayedAnimation(this);
}
}
@Override
public boolean isStarted() {
return mStarted;
}
private void doStart() {
if (!mCanceled) {
super.start();
}
}
@Override
public void cancel() {
mCanceled = true;
super.cancel();
}
/**
* @return true if the animator was started, false if still delayed
*/
private boolean processDelayed(long frameTimeMs) {
if (mCanceled) return true;
if (mStartTime == 0) {
mStartTime = frameTimeMs;
} else if ((frameTimeMs - mStartTime) >= mStartDelay) {
doStart();
return true;
}
return false;
}
private static AnimationHelper getHelper() {
AnimationHelper helper = sAnimationHelper.get();
if (helper == null) {
helper = new AnimationHelper();
sAnimationHelper.set(helper);
}
return helper;
}
private static ThreadLocal<AnimationHelper> sAnimationHelper =
new ThreadLocal<AnimationHelper>();
private static class AnimationHelper implements Runnable {
private ArrayList<RenderNodeAnimatorCompat> mDelayedAnims = new ArrayList<RenderNodeAnimatorCompat>();
private final Choreographer mChoreographer;
private boolean mCallbackScheduled;
public AnimationHelper() {
mChoreographer = Choreographer.getInstance();
}
public void addDelayedAnimation(RenderNodeAnimatorCompat animator) {
mDelayedAnims.add(animator);
scheduleCallback();
}
private void scheduleCallback() {
if (!mCallbackScheduled) {
mCallbackScheduled = true;
mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, this, null);
}
}
@Override
public void run() {
long frameTimeMs = mChoreographer.getFrameTime();
mCallbackScheduled = false;
int end = 0;
for (int i = 0; i < mDelayedAnims.size(); i++) {
RenderNodeAnimatorCompat animator = mDelayedAnims.get(i);
if (!animator.processDelayed(frameTimeMs)) {
if (end != i) {
mDelayedAnims.set(end, animator);
}
end++;
}
}
while (mDelayedAnims.size() > end) {
mDelayedAnims.remove(mDelayedAnims.size() - 1);
}
if (mDelayedAnims.size() > 0) {
scheduleCallback();
}
}
}
}

View File

@@ -30,6 +30,9 @@ public final class ViewAnimationUtils {
*
* Any shadow cast by the View will respect the circular clip from this animator.
*
* Note that the animation returned here is a one-shot animation. It cannot
* be re-used, and once started it cannot be paused or resumed.
*
* @param view The View will be clipped to the animating circle.
* @param centerX The x coordinate of the center of the animating circle.
* @param centerY The y coordinate of the center of the animating circle.

View File

@@ -81,7 +81,7 @@ class ViewPropertyAnimatorRT {
int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);
final float finalValue = holder.mFromValue + holder.mDeltaValue;
RenderNodeAnimator animator = new RenderNodeAnimatorCompat(property, finalValue);
RenderNodeAnimator animator = new RenderNodeAnimator(property, finalValue);
animator.setStartDelay(startDelay);
animator.setDuration(duration);
animator.setInterpolator(interpolator);