Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 940eba12 authored by Doris Liu's avatar Doris Liu Committed by android-build-merger
Browse files

Merge "VectorDrawable native rendering - Step 5 of MANY" into nyc-dev am: 0a1cdee3

am: 1a6d0bbe

* commit '1a6d0bbe':
  VectorDrawable native rendering - Step 5 of MANY
parents aa401afb 1a6d0bbe
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -807,6 +807,8 @@ public final class AnimatorSet extends Animator {
    }

    /**
     * AnimatorSet is only reversible when the set contains no sequential animation, and no child
     * animators have a start delay.
     * @hide
     */
    @Override
+15 −12
Original line number Diff line number Diff line
@@ -43,12 +43,13 @@ static JNIEnv* getEnv(JavaVM* vm) {
    return env;
}

static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener) {
static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishListener, jint id) {
    class AnimationListenerBridge : public AnimationListener {
    public:
        AnimationListenerBridge(JNIEnv* env, jobject finishListener) {
        AnimationListenerBridge(JNIEnv* env, jobject finishListener, jint id) {
            mFinishListener = env->NewGlobalRef(finishListener);
            env->GetJavaVM(&mJvm);
            mId = id;
        }

        virtual ~AnimationListenerBridge() {
@@ -63,7 +64,7 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis
            env->CallStaticVoidMethod(
                    gVectorDrawableAnimatorClassInfo.clazz,
                    gVectorDrawableAnimatorClassInfo.callOnFinished,
                    mFinishListener);
                    mFinishListener, mId);
            releaseJavaObject();
        }

@@ -76,8 +77,9 @@ static AnimationListener* createAnimationListener(JNIEnv* env, jobject finishLis

        JavaVM* mJvm;
        jobject mFinishListener;
        jint mId;
    };
    return new AnimationListenerBridge(env, finishListener);
    return new AnimationListenerBridge(env, finishListener, id);
}

static void addAnimator(JNIEnv*, jobject, jlong animatorSetPtr, jlong propertyHolderPtr,
@@ -142,15 +144,16 @@ static void setPropertyHolderData(JNIEnv* env, jobject, jlong propertyHolderPtr,
    holder->setPropertyDataSource(propertyData, length);
    env->ReleaseFloatArrayElements(srcData, propertyData, JNI_ABORT);
}
static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
static void start(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
    // TODO: keep a ref count in finish listener
    AnimationListener* listener = createAnimationListener(env, finishListener);
    AnimationListener* listener = createAnimationListener(env, finishListener, id);
    set->start(listener);
}

static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener) {
    // TODO: implement reverse
static void reverse(JNIEnv* env, jobject, jlong animatorSetPtr, jobject finishListener, jint id) {
    PropertyValuesAnimatorSet* set = reinterpret_cast<PropertyValuesAnimatorSet*>(animatorSetPtr);
    AnimationListener* listener = createAnimationListener(env, finishListener, id);
    set->reverse(listener);
}

static void end(JNIEnv*, jobject, jlong animatorSetPtr) {
@@ -172,8 +175,8 @@ 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;)V", (void*)start},
    {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V", (void*)reverse},
    {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)start},
    {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V", (void*)reverse},
    {"nEnd", "!(J)V", (void*)end},
    {"nReset", "!(J)V", (void*)reset},
};
@@ -186,7 +189,7 @@ int register_android_graphics_drawable_AnimatedVectorDrawable(JNIEnv* env) {

    gVectorDrawableAnimatorClassInfo.callOnFinished = GetStaticMethodIDOrDie(
            env, gVectorDrawableAnimatorClassInfo.clazz, "callOnFinished",
            "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;)V");
            "(Landroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimator;I)V");
    return RegisterMethodsOrDie(env, "android/graphics/drawable/AnimatedVectorDrawable",
            gMethods, NELEM(gMethods));
}
+1 −1
Original line number Diff line number Diff line
@@ -184,7 +184,7 @@ static void start(JNIEnv* env, jobject clazz, jlong animatorPtr) {

static void end(JNIEnv* env, jobject clazz, jlong animatorPtr) {
    BaseRenderNodeAnimator* animator = reinterpret_cast<BaseRenderNodeAnimator*>(animatorPtr);
    animator->end();
    animator->cancel();
}

// ----------------------------------------------------------------------------
+49 −57
Original line number Diff line number Diff line
@@ -238,9 +238,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
            mAnimatorSet.recordLastSeenTarget((DisplayListCanvas) canvas);
        }
        mAnimatedVectorState.mVectorDrawable.draw(canvas);
        if (isStarted()) {
            invalidateSelf();
        }
    }

    @Override
@@ -611,10 +608,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
        return mAnimatorSet.isRunning();
    }

    private boolean isStarted() {
        return mAnimatorSet.isStarted();
    }

    /**
     * Resets the AnimatedVectorDrawable to the start state as specified in the animators.
     */
@@ -626,12 +619,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    @Override
    public void start() {
        ensureAnimatorSet();

        // If any one of the animator has not ended, do nothing.
        if (isStarted()) {
            return;
        }

        mAnimatorSet.start();
        invalidateSelf();
    }
@@ -652,6 +639,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
    @Override
    public void stop() {
        mAnimatorSet.end();
        invalidateSelf();
    }

    /**
@@ -774,6 +762,9 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
     * @hide
     */
    public static class VectorDrawableAnimator {
        private static final int NONE = 0;
        private static final int START_ANIMATION = 1;
        private static final int REVERSE_ANIMATION = 2;
        private AnimatorListener mListener = null;
        private final LongArray mStartDelays = new LongArray();
        private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -782,7 +773,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
        private boolean mContainsSequentialAnimators = false;
        private boolean mStarted = false;
        private boolean mInitialized = false;
        private boolean mAnimationPending = false;
        private boolean mIsReversible = false;
        // This needs to be set before parsing starts.
        private boolean mShouldIgnoreInvalidAnim;
@@ -790,7 +780,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
        private final VirtualRefBasePtr mSetRefBasePtr;
        private WeakReference<RenderNode> mTarget = null;
        private WeakReference<RenderNode> mLastSeenTarget = null;

        private int mLastListenerId = 0;
        private int mPendingAnimationAction = NONE;

        VectorDrawableAnimator() {
            mSetPtr = nCreateAnimatorSet();
@@ -810,6 +801,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
            mInitialized = true;

            // Check reversible.
            mIsReversible = true;
            if (mContainsSequentialAnimators) {
                mIsReversible = false;
            } else {
@@ -821,7 +813,6 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
                    }
                }
            }
            mIsReversible = true;
        }

        private void parseAnimatorSet(AnimatorSet set, long startTime) {
@@ -1042,27 +1033,22 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
         * to the last seen RenderNode target and start right away.
         */
        protected void recordLastSeenTarget(DisplayListCanvas canvas) {
            if (mAnimationPending) {
            mLastSeenTarget = new WeakReference<RenderNode>(
                    RenderNodeAnimatorSetHelper.getTarget(canvas));
            if (mPendingAnimationAction != NONE) {
                if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                    Log.d(LOGTAG, "Target is set in the next frame");
                }
                mAnimationPending = false;
                if (mPendingAnimationAction == START_ANIMATION) {
                    start();
            } else {
                mLastSeenTarget = new WeakReference<RenderNode>(
                        RenderNodeAnimatorSetHelper.getTarget(canvas));
                } else if (mPendingAnimationAction == REVERSE_ANIMATION) {
                    reverse();
                }

                mPendingAnimationAction = NONE;
            }

        private boolean setTarget(RenderNode node) {
            if (mTarget != null && mTarget.get() != null) {
                // TODO: Maybe we want to support target change.
                throw new IllegalStateException("Target already set!");
        }

        private boolean setTarget(RenderNode node) {
            node.addAnimator(this);
            mTarget = new WeakReference<RenderNode>(node);
            return true;
@@ -1081,12 +1067,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
                return;
            }

            if (mStarted) {
                return;
            }

            if (!useLastSeenTarget()) {
                mAnimationPending = true;
                mPendingAnimationAction = START_ANIMATION;
                return;
            }

@@ -1094,38 +1076,45 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
                Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
            }

           nStart(mSetPtr, this);
            mStarted = true;
            nStart(mSetPtr, this, ++mLastListenerId);
            if (mListener != null) {
                mListener.onAnimationStart(null);
            }
            mStarted = true;
        }

        public void end() {
            if (mInitialized && mStarted) {
            if (mInitialized && useLastSeenTarget()) {
                // If no target has ever been set, no-op
                nEnd(mSetPtr);
                onAnimationEnd();
            }
        }

        void reset() {
            if (!mInitialized) {
                return;
            }
            // TODO: Need to implement reset.
            Log.w(LOGTAG, "Reset is yet to be implemented");
        public void reset() {
            if (mInitialized && useLastSeenTarget()) {
                // If no target has ever been set, no-op
                nReset(mSetPtr);
            }
        }

        // Current (imperfect) Java AnimatorSet cannot be reversed when the set contains sequential
        // animators or when the animator set has a start delay
        void reverse() {
            if (!mIsReversible) {
            if (!mIsReversible || !mInitialized) {
                return;
            }
            // TODO: Need to support reverse (non-public API)
            Log.w(LOGTAG, "Reverse is yet to be implemented");
            nReverse(mSetPtr, this);
            if (!useLastSeenTarget()) {
                mPendingAnimationAction = REVERSE_ANIMATION;
                return;
            }
            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
            }
            mStarted = true;
            nReverse(mSetPtr, this, ++mLastListenerId);
            if (mListener != null) {
                mListener.onAnimationStart(null);
            }
        }

        public long getAnimatorNativePtr() {
@@ -1155,7 +1144,13 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
            mListener = null;
        }

        private void onAnimationEnd() {
        private void onAnimationEnd(int listenerId) {
            if (listenerId != mLastListenerId) {
                return;
            }
            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                Log.d(LOGTAG, "on finished called from native");
            }
            mStarted = false;
            if (mListener != null) {
                mListener.onAnimationEnd(null);
@@ -1164,11 +1159,8 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
        }

        // onFinished: should be called from native
        private static void callOnFinished(VectorDrawableAnimator set) {
            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                Log.d(LOGTAG, "on finished called from native");
            }
            set.onAnimationEnd();
        private static void callOnFinished(VectorDrawableAnimator set, int id) {
            set.onAnimationEnd(id);
        }
    }

@@ -1188,8 +1180,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);
    private static native void nReverse(long animatorSetPtr, VectorDrawableAnimator set);
    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 nEnd(long animatorSetPtr);
    private static native void nReset(long animatorSetPtr);
}
+119 −25
Original line number Diff line number Diff line
@@ -42,7 +42,8 @@ BaseRenderNodeAnimator::BaseRenderNodeAnimator(float finalValue)
        , mStartTime(0)
        , mDuration(300)
        , mStartDelay(0)
        , mMayRunAsync(true) {
        , mMayRunAsync(true)
        , mPlayTime(0) {
}

BaseRenderNodeAnimator::~BaseRenderNodeAnimator() {
@@ -85,20 +86,113 @@ void BaseRenderNodeAnimator::attach(RenderNode* target) {
    onAttached();
}

void BaseRenderNodeAnimator::start() {
    mStagingPlayState = PlayState::Running;
    mStagingRequests.push_back(Request::Start);
    onStagingPlayStateChanged();
}

void BaseRenderNodeAnimator::cancel() {
    mStagingPlayState = PlayState::Finished;
    mStagingRequests.push_back(Request::Cancel);
    onStagingPlayStateChanged();
}

void BaseRenderNodeAnimator::reset() {
    mStagingPlayState = PlayState::Finished;
    mStagingRequests.push_back(Request::Reset);
    onStagingPlayStateChanged();
}

void BaseRenderNodeAnimator::reverse() {
    mStagingPlayState = PlayState::Reversing;
    mStagingRequests.push_back(Request::Reverse);
    onStagingPlayStateChanged();
}

void BaseRenderNodeAnimator::end() {
    mStagingPlayState = PlayState::Finished;
    mStagingRequests.push_back(Request::End);
    onStagingPlayStateChanged();
}

void BaseRenderNodeAnimator::resolveStagingRequest(Request request) {
    switch (request) {
    case Request::Start:
        mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
                        mPlayTime : 0;
        mPlayState = PlayState::Running;
        break;
    case Request::Reverse:
        mPlayTime = (mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) ?
                        mPlayTime : mDuration;
        mPlayState = PlayState::Reversing;
        break;
    case Request::Reset:
        mPlayTime = 0;
        mPlayState = PlayState::Finished;
        break;
    case Request::Cancel:
        mPlayState = PlayState::Finished;
        break;
    case Request::End:
        mPlayTime = mPlayState == PlayState::Reversing ? 0 : mDuration;
        mPlayState = PlayState::Finished;
        break;
    default:
        LOG_ALWAYS_FATAL("Invalid staging request: %d", static_cast<int>(request));
    };
}

void BaseRenderNodeAnimator::pushStaging(AnimationContext& context) {
    if (!mHasStartValue) {
        doSetStartValue(getValue(mTarget));
    }
    if (mStagingPlayState > mPlayState) {
        if (mStagingPlayState == PlayState::Restarted) {
            mStagingPlayState = PlayState::Running;

    if (!mStagingRequests.empty()) {
        // Keep track of the play state and play time before they are changed when
        // staging requests are resolved.
        nsecs_t currentPlayTime = mPlayTime;
        PlayState prevFramePlayState = mPlayState;

        // Resolve staging requests one by one.
        for (Request request : mStagingRequests) {
            resolveStagingRequest(request);
        }
        mPlayState = mStagingPlayState;
        // Oh boy, we're starting! Man the battle stations!
        if (mPlayState == PlayState::Running) {
            transitionToRunning(context);
        } else if (mPlayState == PlayState::Finished) {
        mStagingRequests.clear();

        if (mStagingPlayState == PlayState::Finished) {
            // Set the staging play time and end the animation
            updatePlayTime(mPlayTime);
            callOnFinishedListener(context);
        } else if (mStagingPlayState == PlayState::Running
                || mStagingPlayState == PlayState::Reversing) {
            bool changed = currentPlayTime != mPlayTime || prevFramePlayState != mStagingPlayState;
            if (prevFramePlayState != mStagingPlayState) {
                transitionToRunning(context);
            }
            if (changed) {
                // Now we need to seek to the stagingPlayTime (i.e. the animation progress that was
                // requested from UI thread). It is achieved by modifying mStartTime, such that
                // current time - mStartTime = stagingPlayTime (or mDuration -stagingPlayTime in the
                // case of reversing)
                nsecs_t currentFrameTime = context.frameTimeMs();
                if (mPlayState == PlayState::Reversing) {
                    // Reverse is not supported for animations with a start delay, so here we
                    // assume no start delay.
                    mStartTime = currentFrameTime  - (mDuration - mPlayTime);
                } else {
                    // Animation should play forward
                    if (mPlayTime == 0) {
                        // If the request is to start from the beginning, include start delay.
                        mStartTime = currentFrameTime + mStartDelay;
                    } else {
                        // If the request is to seek to a non-zero play time, then we skip start
                        // delay.
                        mStartTime = currentFrameTime - mPlayTime;
                    }
                }
            }
        }
    }
}
@@ -136,37 +230,37 @@ bool BaseRenderNodeAnimator::animate(AnimationContext& context) {

    // This should be set before setValue() so animators can query this time when setValue
    // is called.
    nsecs_t currentFrameTime = context.frameTimeMs();
    onPlayTimeChanged(currentFrameTime - mStartTime);
    nsecs_t currentPlayTime = context.frameTimeMs() - mStartTime;
    bool finished = updatePlayTime(currentPlayTime);
    if (finished && mPlayState != PlayState::Finished) {
        mPlayState = PlayState::Finished;
        callOnFinishedListener(context);
    }
    return finished;
}

bool BaseRenderNodeAnimator::updatePlayTime(nsecs_t playTime) {
    mPlayTime = mPlayState == PlayState::Reversing ? mDuration - playTime : playTime;
    onPlayTimeChanged(mPlayTime);
    // If BaseRenderNodeAnimator is handling the delay (not typical), then
    // because the staging properties reflect the final value, we always need
    // to call setValue even if the animation isn't yet running or is still
    // being delayed as we need to override the staging value
    if (mStartTime > context.frameTimeMs()) {
    if (playTime < 0) {
        setValue(mTarget, mFromValue);
        return false;
    }

    float fraction = 1.0f;

    if (mPlayState == PlayState::Running && mDuration > 0) {
        fraction = (float)(currentFrameTime - mStartTime) / mDuration;
    }
    if (fraction >= 1.0f) {
        fraction = 1.0f;
        mPlayState = PlayState::Finished;
    if ((mPlayState == PlayState::Running || mPlayState == PlayState::Reversing) && mDuration > 0) {
        fraction = mPlayTime / (float) mDuration;
    }
    fraction = MathUtils::clamp(fraction, 0.0f, 1.0f);

    fraction = mInterpolator->interpolate(fraction);
    setValue(mTarget, mFromValue + (mDeltaValue * fraction));

    if (mPlayState == PlayState::Finished) {
        callOnFinishedListener(context);
        return true;
    }

    return false;
    return playTime >= mDuration;
}

void BaseRenderNodeAnimator::forceEndNow(AnimationContext& context) {
Loading