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

Commit 94f6878b authored by John Reck's avatar John Reck Committed by Android (Google) Code Review
Browse files

Merge "Run RevealAnimator on RT" into lmp-dev

parents 8c5c3736 291161ac
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -370,6 +370,7 @@ public abstract class Animator implements Cloneable {
     * @hide
     */
    public void reverse() {
        throw new IllegalStateException("Reverse is not supported");
    }

    /**
+5 −132
Original line number Diff line number Diff line
@@ -26,148 +26,21 @@ import android.view.View;
 *
 * @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));
    }

    @Override
    void animateValue(float fraction) {
        super.animateValue(fraction);
        fraction = getAnimatedFraction();
        float radius = mStartRadius + (mDelta * fraction);
        mClipView.setRevealClip(true, mX, mY, radius);
        setTarget(mClipView);
    }

    @Override
    protected void endAnimation(AnimationHandler handler) {
    protected void onFinished() {
        mClipView.setRevealClip(false, 0, 0, 0);
        super.endAnimation(handler);
    }

    @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;
        super.onFinished();
    }

    @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;
    }
}
+106 −2
Original line number Diff line number Diff line
@@ -93,6 +93,14 @@ public class RenderNodeAnimator extends Animator {

    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 class RenderNodeAnimator extends Animator {
    public RenderNodeAnimator(int property, float finalValue) {
        mRenderProperty = property;
        mFinalValue = finalValue;
        mUiThreadHandlesDelay = true;
        init(nCreateAnimator(new WeakReference<RenderNodeAnimator>(this),
                property, finalValue));
    }
@@ -109,6 +118,7 @@ public class RenderNodeAnimator extends Animator {
        init(nCreateCanvasPropertyFloatAnimator(
                new WeakReference<RenderNodeAnimator>(this),
                property.getNativeContainer(), finalValue));
        mUiThreadHandlesDelay = false;
    }

    /**
@@ -123,11 +133,13 @@ public class RenderNodeAnimator extends Animator {
        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 @@ public class RenderNodeAnimator extends Animator {

        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 @@ public class RenderNodeAnimator extends Animator {
    @Override
    public void cancel() {
        if (!mFinished) {
            getHelper().removeDelayedAnimation(this);
            nEnd(mNativePtr.get());

            final ArrayList<AnimatorListener> listeners = getListeners();
@@ -258,7 +281,7 @@ public class RenderNodeAnimator extends Animator {
            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 @@ public class RenderNodeAnimator extends Animator {
        return mInterpolator;
    }

    private void onFinished() {
    protected void onFinished() {
        mFinished = true;

        final ArrayList<AnimatorListener> listeners = getListeners();
@@ -317,6 +340,82 @@ public class RenderNodeAnimator extends Animator {
        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 @@ public class RenderNodeAnimator extends Animator {
        }
    }

    @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,
+0 −151
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;
    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();
            }
        }
    }
}
+3 −0
Original line number Diff line number Diff line
@@ -30,6 +30,9 @@ public final class ViewAnimationUtils {
     *
     * 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.
Loading