Merge "Run RevealAnimator on RT" into lmp-dev
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 5f80ed7..3720c81 100644
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -370,6 +370,7 @@
* @hide
*/
public void reverse() {
+ throw new IllegalStateException("Reverse is not supported");
}
/**
diff --git a/core/java/android/animation/RevealAnimator.java b/core/java/android/animation/RevealAnimator.java
index e363a77..0f85f49 100644
--- a/core/java/android/animation/RevealAnimator.java
+++ b/core/java/android/animation/RevealAnimator.java
@@ -26,148 +26,21 @@
*
* @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;
- }
}
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index c7f16e0..a56d448 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -93,6 +93,14 @@
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 RenderNodeAnimator(int property, float finalValue) {
mRenderProperty = property;
mFinalValue = finalValue;
+ mUiThreadHandlesDelay = true;
init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
property, finalValue));
}
@@ -109,6 +118,7 @@
init(nCreateCanvasPropertyFloatAnimator(
new WeakReference<RenderNodeAnimator>(this),
property.getNativeContainer(), finalValue));
+ mUiThreadHandlesDelay = false;
}
/**
@@ -123,11 +133,13 @@
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 @@
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 @@
@Override
public void cancel() {
if (!mFinished) {
+ getHelper().removeDelayedAnimation(this);
nEnd(mNativePtr.get());
final ArrayList<AnimatorListener> listeners = getListeners();
@@ -258,7 +281,7 @@
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 @@
return mInterpolator;
}
- private void onFinished() {
+ protected void onFinished() {
mFinished = true;
final ArrayList<AnimatorListener> listeners = getListeners();
@@ -317,6 +340,82 @@
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 @@
}
}
+ @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,
diff --git a/core/java/android/view/RenderNodeAnimatorCompat.java b/core/java/android/view/RenderNodeAnimatorCompat.java
deleted file mode 100644
index 8103f47..0000000
--- a/core/java/android/view/RenderNodeAnimatorCompat.java
+++ /dev/null
@@ -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();
- }
- }
- }
-}
diff --git a/core/java/android/view/ViewAnimationUtils.java b/core/java/android/view/ViewAnimationUtils.java
index ea3efb1..eeff90a 100644
--- a/core/java/android/view/ViewAnimationUtils.java
+++ b/core/java/android/view/ViewAnimationUtils.java
@@ -30,6 +30,9 @@
*
* 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.
diff --git a/core/java/android/view/ViewPropertyAnimatorRT.java b/core/java/android/view/ViewPropertyAnimatorRT.java
index 20f5182..de96887 100644
--- a/core/java/android/view/ViewPropertyAnimatorRT.java
+++ b/core/java/android/view/ViewPropertyAnimatorRT.java
@@ -81,7 +81,7 @@
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);