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

Commit 83ea8c88 authored by Riddle Hsu's avatar Riddle Hsu Committed by Android (Google) Code Review
Browse files

Merge "Add the ability to adjust the timing animation end listener" into main

parents 30517bdc e685cf0a
Loading
Loading
Loading
Loading
+52 −0
Original line number Diff line number Diff line
@@ -81,6 +81,25 @@ public class AnimationHandler {
     */
    private final ArrayList<WeakReference<Object>> mAnimatorRequestors = new ArrayList<>();

    /**
     * The callbacks which will invoke {@link Animator#notifyEndListeners(boolean)} on next frame.
     * It is only used if {@link Animator#setPostNotifyEndListenerEnabled(boolean)} sets true.
     */
    private ArrayList<Runnable> mPendingEndAnimationListeners;

    /**
     * The value of {@link Choreographer#getVsyncId()} at the last animation frame.
     * It is only used if {@link Animator#setPostNotifyEndListenerEnabled(boolean)} sets true.
     */
    private long mLastAnimationFrameVsyncId;

    /**
     * The value of {@link Choreographer#getVsyncId()} when calling
     * {@link Animator#notifyEndListeners(boolean)}.
     * It is only used if {@link Animator#setPostNotifyEndListenerEnabled(boolean)} sets true.
     */
    private long mEndAnimationFrameVsyncId;

    private final Choreographer.FrameCallback mFrameCallback = new Choreographer.FrameCallback() {
        @Override
        public void doFrame(long frameTimeNanos) {
@@ -332,6 +351,39 @@ public class AnimationHandler {
        }
    }

    /**
     * Returns the vsyncId of last animation frame if the given {@param currentVsyncId} matches
     * the vsyncId from the end callback of animation. Otherwise it returns the given vsyncId.
     * It only takes effect if {@link #postEndAnimationCallback(Runnable)} is called.
     */
    public long getLastAnimationFrameVsyncId(long currentVsyncId) {
        return currentVsyncId == mEndAnimationFrameVsyncId && mLastAnimationFrameVsyncId != 0
                ? mLastAnimationFrameVsyncId : currentVsyncId;
    }

    /** Runs the given callback on next frame to notify the end of the animation. */
    public void postEndAnimationCallback(Runnable notifyEndAnimation) {
        if (mPendingEndAnimationListeners == null) {
            mPendingEndAnimationListeners = new ArrayList<>();
        }
        mPendingEndAnimationListeners.add(notifyEndAnimation);
        if (mPendingEndAnimationListeners.size() > 1) {
            return;
        }
        final Choreographer choreographer = Choreographer.getInstance();
        mLastAnimationFrameVsyncId = choreographer.getVsyncId();
        getProvider().postFrameCallback(frame -> {
            mEndAnimationFrameVsyncId = choreographer.getVsyncId();
            // The animation listeners can only get vsyncId of last animation frame in this frame
            // by getLastAnimationFrameVsyncId(currentVsyncId).
            while (mPendingEndAnimationListeners.size() > 0) {
                mPendingEndAnimationListeners.remove(0).run();
            }
            mEndAnimationFrameVsyncId = 0;
            mLastAnimationFrameVsyncId = 0;
        });
    }

    private void doAnimationFrame(long frameTime) {
        long currentTime = SystemClock.uptimeMillis();
        final int size = mAnimationCallbacks.size();
+39 −0
Original line number Diff line number Diff line
@@ -16,6 +16,7 @@

package android.animation;

import android.annotation.CallSuper;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.TestApi;
@@ -23,6 +24,7 @@ import android.compat.annotation.UnsupportedAppUsage;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ConstantState;
import android.os.Build;
import android.os.Trace;
import android.util.LongArray;

import java.util.ArrayList;
@@ -72,6 +74,13 @@ public abstract class Animator implements Cloneable {
     */
    private static long sBackgroundPauseDelay = 1000;

    /**
     * If true, when the animation plays normally to the end, the callback
     * {@link AnimatorListener#onAnimationEnd(Animator)} will be scheduled on the next frame.
     * It is to avoid the last animation frame being delayed by the implementation of listeners.
     */
    static boolean sPostNotifyEndListenerEnabled;

    /**
     * A cache of the values in a list. Used so that when calling the list, we have a copy
     * of it in case the list is modified while iterating. The array can be reused to avoid
@@ -123,6 +132,14 @@ public abstract class Animator implements Cloneable {
        AnimationHandler.setOverrideAnimatorPausingSystemProperty(!enable);
    }

    /**
     * @see #sPostNotifyEndListenerEnabled
     * @hide
     */
    public static void setPostNotifyEndListenerEnabled(boolean enable) {
        sPostNotifyEndListenerEnabled = enable;
    }

    /**
     * Starts this animation. If the animation has a nonzero startDelay, the animation will start
     * running after that delay elapses. A non-delayed animation will have its initial
@@ -635,6 +652,28 @@ public abstract class Animator implements Cloneable {
        }
    }

    void notifyEndListenersFromEndAnimation(boolean isReversing, boolean postNotifyEndListener) {
        if (postNotifyEndListener) {
            AnimationHandler.getInstance().postEndAnimationCallback(
                    () -> completeEndAnimation(isReversing, "postNotifyAnimEnd"));
        } else {
            completeEndAnimation(isReversing, "notifyAnimEnd");
        }
    }

    @CallSuper
    void completeEndAnimation(boolean isReversing, String notifyListenerTraceName) {
        final boolean useTrace = mListeners != null && Trace.isTagEnabled(Trace.TRACE_TAG_VIEW);
        if (useTrace) {
            Trace.traceBegin(Trace.TRACE_TAG_VIEW, notifyListenerTraceName
                    + "-" + getClass().getSimpleName());
        }
        notifyEndListeners(isReversing);
        if (useTrace) {
            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
        }
    }

    /**
     * Calls <code>call</code> for every item in <code>list</code> with <code>animator</code> and
     * <code>isReverse</code> as parameters.
+8 −1
Original line number Diff line number Diff line
@@ -1442,6 +1442,8 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim
    }

    private void endAnimation() {
        final boolean postNotifyEndListener = sPostNotifyEndListenerEnabled && mListeners != null
                && mLastFrameTime > 0;
        mStarted = false;
        mLastFrameTime = -1;
        mFirstFrame = -1;
@@ -1453,7 +1455,12 @@ public final class AnimatorSet extends Animator implements AnimationHandler.Anim

        // No longer receive callbacks
        removeAnimationCallback();
        notifyEndListeners(mReversing);
        notifyEndListenersFromEndAnimation(mReversing, postNotifyEndListener);
    }

    @Override
    void completeEndAnimation(boolean isReversing, String notifyListenerTraceName) {
        super.completeEndAnimation(isReversing, notifyListenerTraceName);
        removeAnimationEndListener();
        mSelfPulse = true;
        mReversing = false;
+10 −3
Original line number Diff line number Diff line
@@ -1289,6 +1289,8 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
        if (mAnimationEndRequested) {
            return;
        }
        final boolean postNotifyEndListener = sPostNotifyEndListenerEnabled && mListeners != null
                && mLastFrameTime > 0;
        removeAnimationCallback();

        mAnimationEndRequested = true;
@@ -1303,15 +1305,20 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
        mStartTime = -1;
        mRunning = false;
        mStarted = false;
        notifyEndListeners(mReversing);
        // mReversing needs to be reset *after* notifying the listeners for the end callbacks.
        mReversing = false;
        notifyEndListenersFromEndAnimation(mReversing, postNotifyEndListener);
        if (Trace.isTagEnabled(Trace.TRACE_TAG_VIEW)) {
            Trace.asyncTraceEnd(Trace.TRACE_TAG_VIEW, getNameForTrace(),
                    System.identityHashCode(this));
        }
    }

    @Override
    void completeEndAnimation(boolean isReversing, String notifyListenerTraceName) {
        super.completeEndAnimation(isReversing, notifyListenerTraceName);
        // mReversing needs to be reset *after* notifying the listeners for the end callbacks.
        mReversing = false;
    }

    /**
     * Called internally to start an animation by adding it to the active animations list. Must be
     * called on the UI thread.
+3 −1
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_CA
import static com.android.internal.jank.InteractionJankMonitor.ACTION_SESSION_END;
import static com.android.internal.jank.InteractionJankMonitor.EXECUTOR_TASK_TIMEOUT;

import android.animation.AnimationHandler;
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
@@ -344,7 +345,8 @@ public class FrameTracker implements HardwareRendererObserver.OnFrameMetricsAvai
    @UiThread
    public boolean end(@Reasons int reason) {
        if (mCancelled || mEndVsyncId != INVALID_ID) return false;
        mEndVsyncId = mChoreographer.getVsyncId();
        mEndVsyncId = AnimationHandler.getInstance().getLastAnimationFrameVsyncId(
                mChoreographer.getVsyncId());
        // Cancel the session if:
        // 1. The session begins and ends at the same vsync id.
        // 2. The session never begun.
Loading