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

Commit 8d8af3c1 authored by John Reck's avatar John Reck
Browse files

Fixes to startDelay

 Bug: 15991758

 Don't update the UI thread with final value until after
 startDelay

Change-Id: Ie8bffb5a3ace353ec1d82943a4efcbd01c42c28f
parent d907e5b1
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -431,7 +431,7 @@ public final class Choreographer {
    /**
     * Gets the time when the current frame started.
     * <p>
     * This method provides the time in nanoseconds when the frame started being rendered.
     * This method provides the time in milliseconds when the frame started being rendered.
     * The frame time provides a stable time base for synchronizing animations
     * and drawing.  It should be used instead of {@link SystemClock#uptimeMillis()}
     * or {@link System#nanoTime()} for animations and drawing in the UI.  Using the frame
+31 −10
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package android.view;

import android.animation.Animator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Paint;
@@ -34,7 +35,7 @@ import java.util.ArrayList;
/**
 * @hide
 */
public final class RenderNodeAnimator extends Animator {
public class RenderNodeAnimator extends Animator {
    // Keep in sync with enum RenderProperty in Animator.h
    public static final int TRANSLATION_X = 0;
    public static final int TRANSLATION_Y = 1;
@@ -83,16 +84,23 @@ public final class RenderNodeAnimator extends Animator {

    private RenderNode mTarget;
    private View mViewTarget;
    private int mRenderProperty = -1;
    private float mFinalValue;
    private TimeInterpolator mInterpolator;

    private boolean mStarted = false;
    private boolean mFinished = false;

    private long mUnscaledDuration = 300;
    private long mUnscaledStartDelay = 0;

    public static int mapViewPropertyToRenderProperty(int viewProperty) {
        return sViewPropertyAnimatorMap.get(viewProperty);
    }

    public RenderNodeAnimator(int property, float finalValue) {
        mRenderProperty = property;
        mFinalValue = finalValue;
        init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
                property, finalValue));
    }
@@ -156,7 +164,16 @@ public final class RenderNodeAnimator extends Animator {

        mStarted = true;
        applyInterpolator();
        mTarget.addAnimator(this);
        nStart(mNativePtr.get());

        // Alpha is a special snowflake that has the canonical value stored
        // in mTransformationInfo instead of in RenderNode, so we need to update
        // it with the final value here.
        if (mRenderProperty == RenderNodeAnimator.ALPHA) {
            // Don't need null check because ViewPropertyAnimator's
            // ctor calls ensureTransformationInfo()
            mViewTarget.mTransformationInfo.mAlpha = mFinalValue;
        }

        final ArrayList<AnimatorListener> listeners = getListeners();
        final int numListeners = listeners == null ? 0 : listeners.size();
@@ -201,6 +218,7 @@ public final class RenderNodeAnimator extends Animator {
    public void setTarget(View view) {
        mViewTarget = view;
        mTarget = view.mRenderNode;
        mTarget.addAnimator(this);
    }

    public void setTarget(Canvas canvas) {
@@ -213,12 +231,12 @@ public final class RenderNodeAnimator extends Animator {
    }

    public void setTarget(RenderNode node) {
        if (mTarget != null) {
            throw new IllegalStateException("Target already set!");
        }
        mViewTarget = null;
        mTarget = node;
    }

    public RenderNode getTarget() {
        return mTarget;
        mTarget.addAnimator(this);
    }

    public void setStartValue(float startValue) {
@@ -232,12 +250,13 @@ public final class RenderNodeAnimator extends Animator {
        if (startDelay < 0) {
            throw new IllegalArgumentException("startDelay must be positive; " + startDelay);
        }
        nSetStartDelay(mNativePtr.get(), startDelay);
        mUnscaledStartDelay = startDelay;
        nSetStartDelay(mNativePtr.get(), (long) (startDelay * ValueAnimator.getDurationScale()));
    }

    @Override
    public long getStartDelay() {
        return nGetStartDelay(mNativePtr.get());
        return mUnscaledStartDelay;
    }

    @Override
@@ -246,13 +265,14 @@ public final class RenderNodeAnimator extends Animator {
        if (duration < 0) {
            throw new IllegalArgumentException("duration must be positive; " + duration);
        }
        nSetDuration(mNativePtr.get(), duration);
        mUnscaledDuration = duration;
        nSetDuration(mNativePtr.get(), (long) (duration * ValueAnimator.getDurationScale()));
        return this;
    }

    @Override
    public long getDuration() {
        return nGetDuration(mNativePtr.get());
        return mUnscaledDuration;
    }

    @Override
@@ -307,5 +327,6 @@ public final class RenderNodeAnimator extends Animator {
    private static native long nGetStartDelay(long nativePtr);
    private static native void nSetInterpolator(long animPtr, long interpolatorPtr);

    private static native void nStart(long animPtr);
    private static native void nCancel(long animPtr);
}
+144 −0
Original line number Diff line number Diff line
/*
 * 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;

    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() {
        if (mStartDelay <= 0) {
            doStart();
        } else {
            getHelper().addDelayedAnimation(this);
        }
    }

    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();
            }
        }
    }
}
+2 −9
Original line number Diff line number Diff line
@@ -73,21 +73,14 @@ class ViewPropertyAnimatorRT {
            int property = RenderNodeAnimator.mapViewPropertyToRenderProperty(holder.mNameConstant);

            final float finalValue = holder.mFromValue + holder.mDeltaValue;
            RenderNodeAnimator animator = new RenderNodeAnimator(property, finalValue);
            RenderNodeAnimator animator = new RenderNodeAnimatorCompat(property, finalValue);
            animator.setStartDelay(startDelay);
            animator.setDuration(duration);
            animator.setInterpolator(interpolator);
            animator.setTarget(mView);
            animator.start();

            // Alpha is a special snowflake that has the canonical value stored
            // in mTransformationInfo instead of in RenderNode, so we need to update
            // it with the final value here.
            if (property == RenderNodeAnimator.ALPHA) {
                // Don't need null check because ViewPropertyAnimator's
                // ctor calls ensureTransformationInfo()
                parent.mView.mTransformationInfo.mAlpha = finalValue;
            }
            mAnimators[property] = animator;
        }

        parent.mPendingAnimations.clear();
+0 −1
Original line number Diff line number Diff line
@@ -456,7 +456,6 @@ static void android_view_RenderNode_addAnimator(JNIEnv* env, jobject clazz,
    RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
    RenderPropertyAnimator* animator = reinterpret_cast<RenderPropertyAnimator*>(animatorPtr);
    renderNode->addAnimator(animator);
    animator->start();
}

#endif // USE_OPENGL_RENDERER
Loading