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

Commit 33c04705 authored by Sunny Goyal's avatar Sunny Goyal
Browse files

Changing LauncherViewPropertyAnimator to use ValueAnimator

Using ValueAnimator allows better support for changes in Animator
APIs.

Bug: 35218222
Change-Id: I4efa470b4bb686328539d35d8e23e297a4ac885a
parent ee544c5d
Loading
Loading
Loading
Loading
+48 −217
Original line number Diff line number Diff line
@@ -17,259 +17,90 @@
package com.android.launcher3;

import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.TimeInterpolator;
import android.animation.AnimatorListenerAdapter;
import android.animation.PropertyValuesHolder;
import android.animation.ValueAnimator;
import android.view.View;
import android.view.ViewPropertyAnimator;

import java.util.ArrayList;
import java.util.EnumSet;

public class LauncherViewPropertyAnimator extends Animator implements AnimatorListener {

    enum Properties {
            TRANSLATION_X,
            TRANSLATION_Y,
            SCALE_X,
            SCALE_Y,
            ROTATION_Y,
            ALPHA,
            START_DELAY,
            DURATION,
            INTERPOLATOR,
            WITH_LAYER
    }
    EnumSet<Properties> mPropertiesToSet = EnumSet.noneOf(Properties.class);
    ViewPropertyAnimator mViewPropertyAnimator;
    View mTarget;

    float mTranslationX;
    float mTranslationY;
    float mScaleX;
    float mScaleY;
    float mRotationY;
    float mAlpha;
    long mStartDelay;
    long mDuration;
    TimeInterpolator mInterpolator;
    ArrayList<Animator.AnimatorListener> mListeners = new ArrayList<>();
    boolean mRunning = false;
    FirstFrameAnimatorHelper mFirstFrameHelper;

    public LauncherViewPropertyAnimator(View target) {
        mTarget = target;
    }

    @Override
    public void addListener(Animator.AnimatorListener listener) {
        mListeners.add(listener);
    }

    @Override
    public void cancel() {
        if (mViewPropertyAnimator != null) {
            mViewPropertyAnimator.cancel();
        }
    }

    @Override
    public Animator clone() {
        throw new RuntimeException("Not implemented");
    }

    @Override
    public void end() {
        throw new RuntimeException("Not implemented");
    }

    @Override
    public long getDuration() {
        return mDuration;
    }

    @Override
    public ArrayList<Animator.AnimatorListener> getListeners() {
        return mListeners;
    }

    @Override
    public long getStartDelay() {
        return mStartDelay;
    }

    @Override
    public void onAnimationCancel(Animator animation) {
        for (int i = 0; i < mListeners.size(); i++) {
            Animator.AnimatorListener listener = mListeners.get(i);
            listener.onAnimationCancel(this);
        }
        mRunning = false;
    }

    @Override
    public void onAnimationEnd(Animator animation) {
        for (int i = 0; i < mListeners.size(); i++) {
            Animator.AnimatorListener listener = mListeners.get(i);
            listener.onAnimationEnd(this);
        }
        mRunning = false;
    }

    @Override
    public void onAnimationRepeat(Animator animation) {
        for (int i = 0; i < mListeners.size(); i++) {
            Animator.AnimatorListener listener = mListeners.get(i);
            listener.onAnimationRepeat(this);
        }
    }

    @Override
    public void onAnimationStart(Animator animation) {
        // This is the first time we get a handle to the internal ValueAnimator
        // used by the ViewPropertyAnimator.
        mFirstFrameHelper.onAnimationStart(animation);

        for (int i = 0; i < mListeners.size(); i++) {
            Animator.AnimatorListener listener = mListeners.get(i);
            listener.onAnimationStart(this);
        }
        mRunning = true;
    }

    @Override
    public boolean isRunning() {
        return mRunning;
    }
import com.android.launcher3.anim.AnimationLayerSet;

    @Override
    public boolean isStarted() {
        return mViewPropertyAnimator != null;
    }

    @Override
    public void removeAllListeners() {
        mListeners.clear();
    }

    @Override
    public void removeListener(Animator.AnimatorListener listener) {
        mListeners.remove(listener);
    }

    @Override
    public Animator setDuration(long duration) {
        mPropertiesToSet.add(Properties.DURATION);
        mDuration = duration;
        return this;
    }

    @Override
    public void setInterpolator(TimeInterpolator value) {
        mPropertiesToSet.add(Properties.INTERPOLATOR);
        mInterpolator = value;
    }

    @Override
    public void setStartDelay(long startDelay) {
        mPropertiesToSet.add(Properties.START_DELAY);
        mStartDelay = startDelay;
    }
import java.util.ArrayList;

    @Override
    public void setTarget(Object target) {
        throw new RuntimeException("Not implemented");
    }
/**
 * Extension of {@link ValueAnimator} to provide an interface similar to
 * {@link android.view.ViewPropertyAnimator}.
 */
public class LauncherViewPropertyAnimator extends ValueAnimator {

    @Override
    public void setupEndValues() {
    private final View mTarget;
    private final ArrayList<PropertyValuesHolder> mProperties;

    }
    private boolean mPrepared = false;

    @Override
    public void setupStartValues() {
    public LauncherViewPropertyAnimator(View view) {
        mTarget = view;
        mProperties = new ArrayList<>();
        setTarget(mTarget);
        addListener(new TransientStateUpdater(mTarget));
    }

    @Override
    public void start() {
        mViewPropertyAnimator = mTarget.animate();

        // FirstFrameAnimatorHelper hooks itself up to the updates on the animator,
        // and then adjusts the play time to keep the first two frames jank-free
        mFirstFrameHelper = new FirstFrameAnimatorHelper(mViewPropertyAnimator, mTarget);

        if (mPropertiesToSet.contains(Properties.TRANSLATION_X)) {
            mViewPropertyAnimator.translationX(mTranslationX);
        }
        if (mPropertiesToSet.contains(Properties.TRANSLATION_Y)) {
            mViewPropertyAnimator.translationY(mTranslationY);
        }
        if (mPropertiesToSet.contains(Properties.SCALE_X)) {
            mViewPropertyAnimator.scaleX(mScaleX);
        }
        if (mPropertiesToSet.contains(Properties.ROTATION_Y)) {
            mViewPropertyAnimator.rotationY(mRotationY);
        }
        if (mPropertiesToSet.contains(Properties.SCALE_Y)) {
            mViewPropertyAnimator.scaleY(mScaleY);
        }
        if (mPropertiesToSet.contains(Properties.ALPHA)) {
            mViewPropertyAnimator.alpha(mAlpha);
        }
        if (mPropertiesToSet.contains(Properties.START_DELAY)) {
            mViewPropertyAnimator.setStartDelay(mStartDelay);
        if (!mPrepared) {
            mPrepared = true;
            setValues(mProperties.toArray(new PropertyValuesHolder[mProperties.size()]));
        }
        if (mPropertiesToSet.contains(Properties.DURATION)) {
            mViewPropertyAnimator.setDuration(mDuration);
        }
        if (mPropertiesToSet.contains(Properties.INTERPOLATOR)) {
            mViewPropertyAnimator.setInterpolator(mInterpolator);
        }
        if (mPropertiesToSet.contains(Properties.WITH_LAYER)) {
            mViewPropertyAnimator.withLayer();
        }
        mViewPropertyAnimator.setListener(this);
        mViewPropertyAnimator.start();
        LauncherAnimUtils.cancelOnDestroyActivity(this);
        super.start();
    }

    public LauncherViewPropertyAnimator translationX(float value) {
        mPropertiesToSet.add(Properties.TRANSLATION_X);
        mTranslationX = value;
        mProperties.add(PropertyValuesHolder.ofFloat(View.TRANSLATION_X, value));
        return this;
    }

    public LauncherViewPropertyAnimator translationY(float value) {
        mPropertiesToSet.add(Properties.TRANSLATION_Y);
        mTranslationY = value;
        mProperties.add(PropertyValuesHolder.ofFloat(View.TRANSLATION_Y, value));
        return this;
    }

    public LauncherViewPropertyAnimator scaleX(float value) {
        mPropertiesToSet.add(Properties.SCALE_X);
        mScaleX = value;
        mProperties.add(PropertyValuesHolder.ofFloat(View.SCALE_X, value));
        return this;
    }

    public LauncherViewPropertyAnimator scaleY(float value) {
        mPropertiesToSet.add(Properties.SCALE_Y);
        mScaleY = value;
        return this;
    }

    public LauncherViewPropertyAnimator rotationY(float value) {
        mPropertiesToSet.add(Properties.ROTATION_Y);
        mRotationY = value;
        mProperties.add(PropertyValuesHolder.ofFloat(View.SCALE_Y, value));
        return this;
    }

    public LauncherViewPropertyAnimator alpha(float value) {
        mPropertiesToSet.add(Properties.ALPHA);
        mAlpha = value;
        mProperties.add(PropertyValuesHolder.ofFloat(View.ALPHA, value));
        return this;
    }

    public LauncherViewPropertyAnimator withLayer() {
        mPropertiesToSet.add(Properties.WITH_LAYER);
        AnimationLayerSet listener = new AnimationLayerSet();
        listener.addView(mTarget);
        addListener(listener);
        return this;
    }

    private static class TransientStateUpdater extends AnimatorListenerAdapter {
        private final View mView;

        TransientStateUpdater(View v) {
            mView = v;
        }

        @Override
        public void onAnimationStart(Animator animation) {
            mView.setHasTransientState(true);
        }

        @Override
        public void onAnimationEnd(Animator animation) {
            mView.setHasTransientState(false);
        }
    }
}
+14 −6
Original line number Diff line number Diff line
@@ -20,23 +20,29 @@ import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.view.View;

import java.util.HashSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * Helper class to automatically build view hardware layers for the duration of an animation.
 */
public class AnimationLayerSet extends AnimatorListenerAdapter {

    private final HashSet<View> mViews = new HashSet<>();
    private final HashMap<View, Integer> mViewsToLayerTypeMap = new HashMap<>();

    public void addView(View v) {
        mViews.add(v);
        mViewsToLayerTypeMap.put(v, v.getLayerType());
    }

    @Override
    public void onAnimationStart(Animator animation) {
        // Enable all necessary layers
        for (View v : mViews) {
        Iterator<Map.Entry<View, Integer>> itr = mViewsToLayerTypeMap.entrySet().iterator();
        while (itr.hasNext()) {
            Map.Entry<View, Integer> entry = itr.next();
            View v = entry.getKey();
            entry.setValue(v.getLayerType());
            v.setLayerType(View.LAYER_TYPE_HARDWARE, null);
            if (v.isAttachedToWindow() && v.getVisibility() == View.VISIBLE) {
                v.buildLayer();
@@ -46,8 +52,10 @@ public class AnimationLayerSet extends AnimatorListenerAdapter {

    @Override
    public void onAnimationEnd(Animator animation) {
        for (View v : mViews) {
            v.setLayerType(View.LAYER_TYPE_NONE, null);
        Iterator<Map.Entry<View, Integer>> itr = mViewsToLayerTypeMap.entrySet().iterator();
        while (itr.hasNext()) {
            Map.Entry<View, Integer> entry = itr.next();
            entry.getKey().setLayerType(entry.getValue(), null);
        }
    }
}