From 28cfd20f024a56a927014351c8bdf9d8552603e3 Mon Sep 17 00:00:00 2001 From: Doris Liu Date: Mon, 22 Feb 2016 16:51:40 -0800 Subject: [PATCH] Support running AVD on UI thread By default, AVD animates on RT thread. But since in some cases there's a need for a finer control on when the frame update for the animation should happen, such as coordiating the AVD animation with other animations that run on UI thread, we are providing a way to force the AVD to run on UI thread. Bug: 27278616 Change-Id: I372ecd3dc52e3fa0bdce3a1e9c19443f9b199027 --- core/java/android/view/RenderNode.java | 2 +- ...aphics_drawable_AnimatedVectorDrawable.cpp | 8 +- .../drawable/AnimatedVectorDrawable.java | 173 +++++++++++++++--- preloaded-classes | 2 +- 4 files changed, 154 insertions(+), 31 deletions(-) diff --git a/core/java/android/view/RenderNode.java b/core/java/android/view/RenderNode.java index a4cb7035f2f9e..a45c18d058cbe 100644 --- a/core/java/android/view/RenderNode.java +++ b/core/java/android/view/RenderNode.java @@ -779,7 +779,7 @@ public class RenderNode { return mOwningView != null && mOwningView.mAttachInfo != null; } - public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimator animatorSet) { + public void addAnimator(AnimatedVectorDrawable.VectorDrawableAnimatorRT animatorSet) { if (mOwningView == null || mOwningView.mAttachInfo == null) { throw new IllegalStateException("Cannot start this animator on a detached view!"); } diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp index 14badb72a1956..4b2a72d8e28e3 100644 --- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp +++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp @@ -175,13 +175,13 @@ static const JNINativeMethod gMethods[] = { {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder}, {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder}, {"nSetPropertyHolderData", "(J[FI)V", (void*)setPropertyHolderData}, - {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start}, - {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse}, + {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start}, + {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse}, {"nEnd", "!(J)V", (void*)end}, {"nReset", "!(J)V", (void*)reset}, }; -const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator"; +const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT"; int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) { gVectorDrawableAnimatorClassInfo.clazz = FindClassOrDie(env, kClassPathName); gVectorDrawableAnimatorClassInfo.clazz = MakeGlobalRefOrDie(env, @@ -189,7 +189,7 @@ int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) { gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie( env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished", - "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V"); + "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V"); return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable", gMethods, NELEM(gMethods)); } diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index c486c1fe17f06..3901af36be832 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -154,7 +154,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false; /** Local, mutable animator set. */ - private final VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimator(this); + private VectorDrawableAnimator mAnimatorSet = new VectorDrawableAnimatorRT(this); /** * The resources against which this drawable was created. Used to attempt @@ -164,8 +164,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private AnimatedVectorDrawableState mAnimatedVectorState; - /** Whether the animator set has been prepared. */ - private boolean mHasAnimatorSet; + /** The animator set that is parsed from the xml. */ + private AnimatorSet mAnimatorSetFromXml = null; private boolean mMutated; @@ -234,9 +234,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @Override public void draw(Canvas canvas) { - if (canvas.isHardwareAccelerated()) { - mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas); - } + mAnimatorSet.onDraw(canvas); mAnimatedVectorState.mVectorDrawable.draw(canvas); } @@ -392,6 +390,24 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mRes = state.mPendingAnims == null ? null : res; } + /** + * Force to animate on UI thread. + * @hide + */ + public void forceAnimationOnUI() { + if (mAnimatorSet instanceof VectorDrawableAnimatorRT) { + VectorDrawableAnimatorRT animator = (VectorDrawableAnimatorRT) mAnimatorSet; + if (animator.isRunning()) { + throw new UnsupportedOperationException("Cannot force Animated Vector Drawable to" + + " run on UI thread when the animation has started on RenderThread."); + } + mAnimatorSet = new VectorDrawableAnimatorUI(this); + if (mAnimatorSetFromXml != null) { + mAnimatorSet.init(mAnimatorSetFromXml); + } + } + } + @Override public boolean canApplyTheme() { return (mAnimatedVectorState != null && mAnimatedVectorState.canApplyTheme()) @@ -612,6 +628,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { * Resets the AnimatedVectorDrawable to the start state as specified in the animators. */ public void reset() { + ensureAnimatorSet(); mAnimatorSet.reset(); } @@ -623,13 +640,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { @NonNull private void ensureAnimatorSet() { - if (!mHasAnimatorSet) { + if (mAnimatorSetFromXml == null) { // TODO: Skip the AnimatorSet creation and init the VectorDrawableAnimator directly // with a list of LocalAnimators. - AnimatorSet set = new AnimatorSet(); - mAnimatedVectorState.prepareLocalAnimators(set, mRes); - mHasAnimatorSet = true; - mAnimatorSet.initWithAnimatorSet(set); + mAnimatorSetFromXml = new AnimatorSet(); + mAnimatedVectorState.prepareLocalAnimators(mAnimatorSetFromXml, mRes); + mAnimatorSet.init(mAnimatorSetFromXml); mRes = null; } } @@ -724,7 +740,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { // A helper function to clean up the animator listener in the mAnimatorSet. private void removeAnimatorSetListener() { if (mAnimatorListener != null) { - mAnimatorSet.removeListener(); + mAnimatorSet.removeListener(mAnimatorListener); mAnimatorListener = null; } } @@ -754,10 +770,100 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mAnimationCallbacks.clear(); } + private interface VectorDrawableAnimator { + void init(AnimatorSet set); + void start(); + void end(); + void reset(); + void reverse(); + boolean canReverse(); + void setListener(AnimatorListener listener); + void removeListener(AnimatorListener listener); + void onDraw(Canvas canvas); + boolean isStarted(); + boolean isRunning(); + } + + private static class VectorDrawableAnimatorUI implements VectorDrawableAnimator { + private AnimatorSet mSet = new AnimatorSet(); + private final Drawable mDrawable; + + VectorDrawableAnimatorUI(AnimatedVectorDrawable drawable) { + mDrawable = drawable; + } + + @Override + public void init(AnimatorSet set) { + mSet = set; + } + + @Override + public void start() { + if (mSet.isStarted()) { + return; + } + mSet.start(); + invalidateOwningView(); + } + + @Override + public void end() { + mSet.end(); + } + + @Override + public void reset() { + start(); + mSet.cancel(); + } + + @Override + public void reverse() { + mSet.reverse(); + invalidateOwningView(); + } + + @Override + public boolean canReverse() { + return mSet.canReverse(); + } + + @Override + public void setListener(AnimatorListener listener) { + mSet.addListener(listener); + } + + @Override + public void removeListener(AnimatorListener listener) { + mSet.removeListener(listener); + } + + @Override + public void onDraw(Canvas canvas) { + if (mSet.isStarted()) { + invalidateOwningView(); + } + } + + @Override + public boolean isStarted() { + return mSet.isStarted(); + } + + @Override + public boolean isRunning() { + return mSet.isRunning(); + } + + private void invalidateOwningView() { + mDrawable.invalidateSelf(); + } + } + /** * @hide */ - public static class VectorDrawableAnimator { + public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator { private static final int NONE = 0; private static final int START_ANIMATION = 1; private static final int REVERSE_ANIMATION = 2; @@ -779,7 +885,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private int mPendingAnimationAction = NONE; private final Drawable mDrawable; - VectorDrawableAnimator(AnimatedVectorDrawable drawable) { + VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) { mDrawable = drawable; mSetPtr = nCreateAnimatorSet(); // Increment ref count on native AnimatorSet, so it doesn't get released before Java @@ -787,7 +893,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mSetRefBasePtr = new VirtualRefBasePtr(mSetPtr); } - private void initWithAnimatorSet(AnimatorSet set) { + @Override + public void init(AnimatorSet set) { if (mInitialized) { // Already initialized throw new UnsupportedOperationException("VectorDrawableAnimator cannot be " + @@ -816,7 +923,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { ArrayList animators = set.getChildAnimations(); boolean playTogether = set.shouldPlayTogether(); - // Convert AnimatorSet to VectorDrawableAnimator + // Convert AnimatorSet to VectorDrawableAnimatorRT for (int i = 0; i < animators.size(); i++) { Animator animator = animators.get(i); // Here we only support ObjectAnimator @@ -1060,6 +1167,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { mDrawable.invalidateSelf(); } + @Override public void start() { if (!mInitialized) { return; @@ -1083,6 +1191,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } } + @Override public void end() { if (mInitialized && useLastSeenTarget()) { // If no target has ever been set, no-op @@ -1091,6 +1200,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } } + @Override public void reset() { if (mInitialized && useLastSeenTarget()) { // If no target has ever been set, no-op @@ -1101,7 +1211,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential // animators or when the animator set has a start delay - void reverse() { + @Override + public void reverse() { if (!mIsReversible || !mInitialized) { return; } @@ -1125,29 +1236,41 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { return mSetPtr; } - boolean canReverse() { + @Override + public boolean canReverse() { return mIsReversible; } - boolean isStarted() { + @Override + public boolean isStarted() { return mStarted; } - boolean isRunning() { + @Override + public boolean isRunning() { if (!mInitialized) { return false; } return mStarted; } - void setListener(AnimatorListener listener) { + @Override + public void setListener(AnimatorListener listener) { mListener = listener; } - void removeListener() { + @Override + public void removeListener(AnimatorListener listener) { mListener = null; } + @Override + public void onDraw(Canvas canvas) { + if (canvas.isHardwareAccelerated()) { + recordLastSeenTarget((DisplayListCanvas) canvas); + } + } + private void onAnimationEnd(int listenerId) { if (listenerId != mLastListenerId) { return; @@ -1162,7 +1285,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { } // onFinished: should be called from native - private static void callOnFinished(VectorDrawableAnimator set, int id) { + private static void callOnFinished(VectorDrawableAnimatorRT set, int id) { set.onAnimationEnd(id); } } @@ -1183,8 +1306,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 { private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue, float endValue); private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length); - private static native void nStart(long animatorSetPtr, VectorDrawableAnimator set, int id); - private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set, int id); + private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id); + private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id); private static native void nEnd(long animatorSetPtr); private static native void nReset(long animatorSetPtr); } diff --git a/preloaded-classes b/preloaded-classes index 9535cc29e107a..be645d24c7fb2 100644 --- a/preloaded-classes +++ b/preloaded-classes @@ -907,7 +907,7 @@ android.graphics.drawable.AnimatedVectorDrawable android.graphics.drawable.AnimatedVectorDrawable$1 android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState android.graphics.drawable.AnimatedVectorDrawable$AnimatedVectorDrawableState$PendingAnimator -android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimator +android.graphics.drawable.AnimatedVectorDrawable$VectorDrawableAnimatorRT android.graphics.drawable.AnimationDrawable android.graphics.drawable.AnimationDrawable$AnimationState android.graphics.drawable.BitmapDrawable