Removing Launcher activity dependency on various animations

(This cl reverts change-Id: I455edcd17bda83ab51c2c04fa40e66097a4d6975)

Various animations were marked for cancellation when launcher activity is
destroyed. This this does not work with multiple activities (Launcher,
fallback recents, shortcut confirmation). Also since launcher activity
handles configuration changes, the activity is not destroyed often.

Instead associating a target with various animations which automatically
cancels the animations when that target goes away.

Change-Id: I64cd095a28075561a9e20c9dcdeb9f90c18e1047
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 41626c6..28928a8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -34,7 +34,6 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseDraggingActivity;
 import com.android.launcher3.FastBitmapDrawable;
-import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.Interpolators;
@@ -241,7 +240,7 @@
         if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
             mOpenCloseAnimator.end();
         }
-        mOpenCloseAnimator = LauncherAnimUtils.createAnimatorSet();
+        mOpenCloseAnimator = new AnimatorSet();
 
         final Animator revealAnimator = createOpenCloseOutlineProvider()
                 .createRevealAnimator(this, closing);
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index 7648e30..b2d5a3f 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -433,22 +433,18 @@
             }
             requestLayout();
         } else {
-            PropertyValuesHolder width = PropertyValuesHolder.ofInt("width", lp.width, newWidth);
-            PropertyValuesHolder height = PropertyValuesHolder.ofInt("height", lp.height,
-                    newHeight);
-            PropertyValuesHolder x = PropertyValuesHolder.ofInt("x", lp.x, newX);
-            PropertyValuesHolder y = PropertyValuesHolder.ofInt("y", lp.y, newY);
-            ObjectAnimator oa =
-                    LauncherAnimUtils.ofPropertyValuesHolder(lp, this, width, height, x, y);
-            oa.addUpdateListener(new AnimatorUpdateListener() {
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    requestLayout();
-                }
-            });
-            AnimatorSet set = LauncherAnimUtils.createAnimatorSet();
+            ObjectAnimator oa = LauncherAnimUtils.ofPropertyValuesHolder(lp, this,
+                    PropertyValuesHolder.ofInt("width", lp.width, newWidth),
+                    PropertyValuesHolder.ofInt("height", lp.height, newHeight),
+                    PropertyValuesHolder.ofInt("x", lp.x, newX),
+                    PropertyValuesHolder.ofInt("y", lp.y, newY));
+            oa.addUpdateListener(a -> requestLayout());
+
+            AnimatorSet set = new AnimatorSet();
             set.play(oa);
             for (int i = 0; i < HANDLE_COUNT; i++) {
-                set.play(LauncherAnimUtils.ofFloat(mDragHandles[i], ALPHA, 1.0f));
+                set.play(LauncherAnimUtils.ofPropertyValuesHolder(mDragHandles[i],
+                        PropertyValuesHolder.ofFloat(ALPHA, 1f)));
             }
 
             set.setDuration(SNAP_DURATION);
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 6c2fd8e..260abd1 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
@@ -34,11 +35,13 @@
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Parcelable;
+import android.os.SystemClock;
 import android.support.annotation.IntDef;
 import android.support.v4.view.ViewCompat;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.Property;
 import android.util.SparseArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -243,7 +246,7 @@
 
         for (int i = 0; i < mDragOutlineAnims.length; i++) {
             final InterruptibleInOutAnimator anim =
-                new InterruptibleInOutAnimator(this, duration, fromAlphaValue, toAlphaValue);
+                new InterruptibleInOutAnimator(duration, fromAlphaValue, toAlphaValue);
             anim.getAnimator().setInterpolator(mEaseOutInterpolator);
             final int thisIndex = i;
             anim.getAnimator().addUpdateListener(new AnimatorUpdateListener() {
@@ -877,7 +880,7 @@
                 return true;
             }
 
-            ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+            ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
             va.setDuration(duration);
             mReorderAnimators.put(lp, va);
 
@@ -1884,6 +1887,19 @@
         }
     }
 
+    private static final Property<ReorderPreviewAnimation, Float> ANIMATION_PROGRESS =
+            new Property<ReorderPreviewAnimation, Float>(float.class, "animationProgress") {
+                @Override
+                public Float get(ReorderPreviewAnimation anim) {
+                    return anim.animationProgress;
+                }
+
+                @Override
+                public void set(ReorderPreviewAnimation anim, Float progress) {
+                    anim.setAnimationProgress(progress);
+                }
+            };
+
     // Class which represents the reorder preview animations. These animations show that an item is
     // in a temporary state, and hint at where the item will return to.
     class ReorderPreviewAnimation {
@@ -1904,6 +1920,7 @@
         public static final int MODE_HINT = 0;
         public static final int MODE_PREVIEW = 1;
 
+        float animationProgress = 0;
         Animator a;
 
         public ReorderPreviewAnimation(View child, int mode, int cellX0, int cellY0, int cellX1,
@@ -1974,7 +1991,7 @@
             if (noMovement) {
                 return;
             }
-            ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+            ValueAnimator va = ObjectAnimator.ofFloat(this, ANIMATION_PROGRESS, 0, 1);
             a = va;
 
             // Animations are disabled in power save mode, causing the repeated animation to jump
@@ -1987,20 +2004,6 @@
 
             va.setDuration(mode == MODE_HINT ? HINT_DURATION : PREVIEW_DURATION);
             va.setStartDelay((int) (Math.random() * 60));
-            va.addUpdateListener(new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    float r = (Float) animation.getAnimatedValue();
-                    float r1 = (mode == MODE_HINT && repeating) ? 1.0f : r;
-                    float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
-                    float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
-                    child.setTranslationX(x);
-                    child.setTranslationY(y);
-                    float s = r * finalScale + (1 - r) * initScale;
-                    child.setScaleX(s);
-                    child.setScaleY(s);
-                }
-            });
             va.addListener(new AnimatorListenerAdapter() {
                 public void onAnimationRepeat(Animator animation) {
                     // We make sure to end only after a full period
@@ -2012,6 +2015,18 @@
             va.start();
         }
 
+        private void setAnimationProgress(float progress) {
+            animationProgress = progress;
+            float r1 = (mode == MODE_HINT && repeating) ? 1.0f : animationProgress;
+            float x = r1 * finalDeltaX + (1 - r1) * initDeltaX;
+            float y = r1 * finalDeltaY + (1 - r1) * initDeltaY;
+            child.setTranslationX(x);
+            child.setTranslationY(y);
+            float s = animationProgress * finalScale + (1 - animationProgress) * initScale;
+            child.setScaleX(s);
+            child.setScaleY(s);
+        }
+
         private void cancel() {
             if (a != null) {
                 a.cancel();
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index e7ca121..48c1059 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -16,24 +16,21 @@
 
 package com.android.launcher3;
 
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+
 import android.animation.ValueAnimator;
 import android.util.Log;
 import android.view.View;
-import android.view.ViewPropertyAnimator;
 import android.view.ViewTreeObserver;
-import com.android.launcher3.util.Thunk;
 
-import static com.android.launcher3.Utilities.SINGLE_FRAME_MS;
+import com.android.launcher3.util.Thunk;
 
 /*
  *  This is a helper class that listens to updates from the corresponding animation.
  *  For the first two frames, it adjusts the current play time of the animation to
  *  prevent jank at the beginning of the animation
  */
-public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
-    implements ValueAnimator.AnimatorUpdateListener {
+public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateListener {
     private static final String TAG = "FirstFrameAnimatorHlpr";
     private static final boolean DEBUG = false;
     private static final int MAX_DELAY = 1000;
@@ -52,18 +49,6 @@
         animator.addUpdateListener(this);
     }
 
-    public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) {
-        mTarget = target;
-        vpa.setListener(this);
-    }
-
-    // only used for ViewPropertyAnimators
-    public void onAnimationStart(Animator animation) {
-        final ValueAnimator va = (ValueAnimator) animation;
-        va.addUpdateListener(FirstFrameAnimatorHelper.this);
-        onAnimationUpdate(va);
-    }
-
     public static void setIsVisible(boolean visible) {
         sVisible = visible;
     }
@@ -78,6 +63,7 @@
         sVisible = true;
     }
 
+    @Override
     public void onAnimationUpdate(final ValueAnimator animation) {
         final long currentTime = System.currentTimeMillis();
         if (mStartTime == -1) {
@@ -115,11 +101,7 @@
                 mAdjustedSecondFrameTime = true;
             } else {
                 if (frameNum > 1) {
-                    mTarget.post(new Runnable() {
-                            public void run() {
-                                animation.removeUpdateListener(FirstFrameAnimatorHelper.this);
-                            }
-                        });
+                    mTarget.post(() -> animation.removeUpdateListener(this));
                 }
                 if (DEBUG) print(animation);
             }
diff --git a/src/com/android/launcher3/InterruptibleInOutAnimator.java b/src/com/android/launcher3/InterruptibleInOutAnimator.java
index 8501e24..f4395ca 100644
--- a/src/com/android/launcher3/InterruptibleInOutAnimator.java
+++ b/src/com/android/launcher3/InterruptibleInOutAnimator.java
@@ -18,7 +18,9 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.util.Property;
 import android.view.View;
 
 import com.android.launcher3.util.Thunk;
@@ -31,11 +33,27 @@
  * interpolator in the same direction.
  */
 public class InterruptibleInOutAnimator {
+
+    private static final Property<InterruptibleInOutAnimator, Float> VALUE =
+            new Property<InterruptibleInOutAnimator, Float>(Float.TYPE, "value") {
+                @Override
+                public Float get(InterruptibleInOutAnimator anim) {
+                    return anim.mValue;
+                }
+
+                @Override
+                public void set(InterruptibleInOutAnimator anim, Float value) {
+                    anim.mValue = value;
+                }
+            };
+
     private long mOriginalDuration;
     private float mOriginalFromValue;
     private float mOriginalToValue;
     private ValueAnimator mAnimator;
 
+    private float mValue;
+
     private boolean mFirstRun = true;
 
     private Object mTag = null;
@@ -47,8 +65,8 @@
     // TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
     @Thunk int mDirection = STOPPED;
 
-    public InterruptibleInOutAnimator(View view, long duration, float fromValue, float toValue) {
-        mAnimator = LauncherAnimUtils.ofFloat(fromValue, toValue).setDuration(duration);
+    public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) {
+        mAnimator = ObjectAnimator.ofFloat(this, VALUE, fromValue, toValue).setDuration(duration);
         mOriginalDuration = duration;
         mOriginalFromValue = fromValue;
         mOriginalToValue = toValue;
@@ -64,8 +82,7 @@
     private void animate(int direction) {
         final long currentPlayTime = mAnimator.getCurrentPlayTime();
         final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
-        final float startValue = mFirstRun ? mOriginalFromValue :
-                ((Float) mAnimator.getAnimatedValue()).floatValue();
+        final float startValue = mFirstRun ? mOriginalFromValue : mValue;
 
         // Make sure it's stopped before we modify any values
         cancel();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index a545122..9650e4e 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -31,6 +31,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.annotation.TargetApi;
 import android.app.ActivityOptions;
@@ -1332,9 +1333,6 @@
         }
 
         TextKeyListener.getInstance().release();
-
-        LauncherAnimUtils.onDestroyActivity();
-
         clearPendingBinds();
 
         if (mLauncherCallbacks != null) {
@@ -1841,7 +1839,7 @@
     @Override
     public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
         // Get the list of added items and intersect them with the set of items here
-        final AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+        final AnimatorSet anim = new AnimatorSet();
         final Collection<Animator> bounceAnims = new ArrayList<>();
         final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
         Workspace workspace = mWorkspace;
@@ -2163,7 +2161,10 @@
     }
 
     private ValueAnimator createNewAppBounceAnimation(View v, int i) {
-        ValueAnimator bounceAnim = LauncherAnimUtils.ofViewAlphaAndScale(v, 1, 1, 1);
+        ValueAnimator bounceAnim = LauncherAnimUtils.ofPropertyValuesHolder(v,
+                PropertyValuesHolder.ofFloat(View.ALPHA, 1f),
+                PropertyValuesHolder.ofFloat(View.SCALE_X, 1f),
+                PropertyValuesHolder.ofFloat(View.SCALE_Y, 1f));
         bounceAnim.setDuration(InstallShortcutReceiver.NEW_SHORTCUT_BOUNCE_DURATION);
         bounceAnim.setStartDelay(i * InstallShortcutReceiver.NEW_SHORTCUT_STAGGER_DELAY);
         bounceAnim.setInterpolator(new OvershootInterpolator(BOUNCE_ANIMATION_TENSION));
diff --git a/src/com/android/launcher3/LauncherAnimUtils.java b/src/com/android/launcher3/LauncherAnimUtils.java
index 03ffded..7944ec5 100644
--- a/src/com/android/launcher3/LauncherAnimUtils.java
+++ b/src/com/android/launcher3/LauncherAnimUtils.java
@@ -16,18 +16,11 @@
 
 package com.android.launcher3;
 
-import android.animation.Animator;
-import android.animation.AnimatorSet;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
-import android.animation.ValueAnimator;
 import android.graphics.drawable.Drawable;
 import android.util.Property;
 import android.view.View;
-import android.view.ViewTreeObserver;
-
-import java.util.HashSet;
-import java.util.WeakHashMap;
 
 public class LauncherAnimUtils {
     /**
@@ -42,92 +35,6 @@
     // The progress of an animation to all apps must be at least this far along to snap to all apps.
     public static final float MIN_PROGRESS_TO_ALL_APPS = 0.5f;
 
-    static WeakHashMap<Animator, Object> sAnimators = new WeakHashMap<Animator, Object>();
-    static Animator.AnimatorListener sEndAnimListener = new Animator.AnimatorListener() {
-        public void onAnimationStart(Animator animation) {
-            sAnimators.put(animation, null);
-        }
-
-        public void onAnimationRepeat(Animator animation) {
-        }
-
-        public void onAnimationEnd(Animator animation) {
-            sAnimators.remove(animation);
-        }
-
-        public void onAnimationCancel(Animator animation) {
-            sAnimators.remove(animation);
-        }
-    };
-
-    public static void cancelOnDestroyActivity(Animator a) {
-        a.addListener(sEndAnimListener);
-    }
-
-    // Helper method. Assumes a draw is pending, and that if the animation's duration is 0
-    // it should be cancelled
-    public static void startAnimationAfterNextDraw(final Animator animator, final View view) {
-        view.getViewTreeObserver().addOnDrawListener(new ViewTreeObserver.OnDrawListener() {
-            private boolean mStarted = false;
-
-            public void onDraw() {
-                if (mStarted) return;
-                mStarted = true;
-                // Use this as a signal that the animation was cancelled
-                if (animator.getDuration() == 0) {
-                    return;
-                }
-                animator.start();
-
-                final ViewTreeObserver.OnDrawListener listener = this;
-                view.post(new Runnable() {
-                    public void run() {
-                        view.getViewTreeObserver().removeOnDrawListener(listener);
-                    }
-                });
-            }
-        });
-    }
-
-    public static void onDestroyActivity() {
-        HashSet<Animator> animators = new HashSet<Animator>(sAnimators.keySet());
-        for (Animator a : animators) {
-            if (a.isRunning()) {
-                a.cancel();
-            }
-            sAnimators.remove(a);
-        }
-    }
-
-    public static AnimatorSet createAnimatorSet() {
-        AnimatorSet anim = new AnimatorSet();
-        cancelOnDestroyActivity(anim);
-        return anim;
-    }
-
-    public static ValueAnimator ofFloat(float... values) {
-        ValueAnimator anim = new ValueAnimator();
-        anim.setFloatValues(values);
-        cancelOnDestroyActivity(anim);
-        return anim;
-    }
-
-    public static ObjectAnimator ofFloat(View target, Property<View, Float> property,
-            float... values) {
-        ObjectAnimator anim = ObjectAnimator.ofFloat(target, property, values);
-        cancelOnDestroyActivity(anim);
-        new FirstFrameAnimatorHelper(anim, target);
-        return anim;
-    }
-
-    public static ObjectAnimator ofViewAlphaAndScale(View target,
-            float alpha, float scaleX, float scaleY) {
-        return ofPropertyValuesHolder(target,
-                PropertyValuesHolder.ofFloat(View.ALPHA, alpha),
-                PropertyValuesHolder.ofFloat(View.SCALE_X, scaleX),
-                PropertyValuesHolder.ofFloat(View.SCALE_Y, scaleY));
-    }
-
     public static ObjectAnimator ofPropertyValuesHolder(View target,
             PropertyValuesHolder... values) {
         return ofPropertyValuesHolder(target, target, values);
@@ -136,7 +43,6 @@
     public static ObjectAnimator ofPropertyValuesHolder(Object target,
             View view, PropertyValuesHolder... values) {
         ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(target, values);
-        cancelOnDestroyActivity(anim);
         new FirstFrameAnimatorHelper(anim, view);
         return anim;
     }
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 307f258..fdac5c8 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -20,8 +20,6 @@
 import android.util.SparseArray;
 import android.view.animation.Interpolator;
 
-import com.android.launcher3.LauncherAnimUtils;
-
 import java.util.ArrayList;
 import java.util.List;
 
@@ -56,7 +54,7 @@
     }
 
     public AnimatorSet build() {
-        AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
+        AnimatorSet anim = new AnimatorSet();
         anim.playTogether(mAnims);
         if (!mOnFinishRunnables.isEmpty()) {
             anim.addListener(new AnimationSuccessListener() {
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index b3d9bdd..998de99 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -77,8 +77,6 @@
     public static final int COLOR_CHANGE_DURATION = 120;
     public static final int VIEW_ZOOM_DURATION = 150;
 
-    @Thunk static float sDragAlpha = 1f;
-
     private boolean mDrawBitmap = true;
     private Bitmap mBitmap;
     private Bitmap mCrossFadeBitmap;
@@ -143,22 +141,14 @@
         setScaleY(initialScale);
 
         // Animate the view into the correct position
-        mAnim = LauncherAnimUtils.ofFloat(0f, 1f);
+        mAnim = ValueAnimator.ofFloat(0f, 1f);
         mAnim.setDuration(VIEW_ZOOM_DURATION);
-        mAnim.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                final float value = (Float) animation.getAnimatedValue();
-
-                setScaleX(initialScale + (value * (scale - initialScale)));
-                setScaleY(initialScale + (value * (scale - initialScale)));
-                if (sDragAlpha != 1f) {
-                    setAlpha(sDragAlpha * value + (1f - value));
-                }
-
-                if (getParent() == null) {
-                    animation.cancel();
-                }
+        mAnim.addUpdateListener(animation -> {
+            final float value = (Float) animation.getAnimatedValue();
+            setScaleX(initialScale + (value * (scale - initialScale)));
+            setScaleY(initialScale + (value * (scale - initialScale)));
+            if (!isAttachedToWindow()) {
+                animation.cancel();
             }
         });
 
@@ -479,15 +469,12 @@
     }
 
     public void crossFade(int duration) {
-        ValueAnimator va = LauncherAnimUtils.ofFloat(0f, 1f);
+        ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
         va.setDuration(duration);
         va.setInterpolator(Interpolators.DEACCEL_1_5);
-        va.addUpdateListener(new AnimatorUpdateListener() {
-            @Override
-            public void onAnimationUpdate(ValueAnimator animation) {
-                mCrossFadeProgress = animation.getAnimatedFraction();
-                invalidate();
-            }
+        va.addUpdateListener(a -> {
+            mCrossFadeProgress = a.getAnimatedFraction();
+            invalidate();
         });
         va.start();
     }
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 9ae3775..0c77f9e 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -27,7 +27,6 @@
 import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Color;
 import android.graphics.Rect;
 import android.graphics.drawable.GradientDrawable;
 import android.support.v4.graphics.ColorUtils;
@@ -38,7 +37,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
 import com.android.launcher3.Utilities;
@@ -170,7 +168,7 @@
         float finalRadius = Utilities.pxFromDp(2, mContext.getResources().getDisplayMetrics());
 
         // Create the animators.
-        AnimatorSet a = LauncherAnimUtils.createAnimatorSet();
+        AnimatorSet a = new AnimatorSet();
 
         // Initialize the Folder items' text.
         PropertyResetListener colorResetListener =
diff --git a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
index be075bc..1e56f7d 100644
--- a/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
+++ b/src/com/android/launcher3/folder/FolderPreviewItemAnim.java
@@ -17,22 +17,41 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
+import android.animation.FloatArrayEvaluator;
+import android.animation.ObjectAnimator;
+import android.util.Property;
 
-import com.android.launcher3.LauncherAnimUtils;
+import java.util.Arrays;
 
 /**
  * Animates a Folder preview item.
  */
 class FolderPreviewItemAnim {
 
+    private static final Property<FolderPreviewItemAnim, float[]> PARAMS =
+            new Property<FolderPreviewItemAnim, float[]>(float[].class, "params") {
+                @Override
+                public float[] get(FolderPreviewItemAnim anim) {
+                    sTempParamsArray[0] = anim.mParams.scale;
+                    sTempParamsArray[1] = anim.mParams.transX;
+                    sTempParamsArray[2] = anim.mParams.transY;
+                    return sTempParamsArray;
+                }
+
+                @Override
+                public void set(FolderPreviewItemAnim anim, float[] value) {
+                    anim.setParams(value);
+                }
+            };
+
     private static PreviewItemDrawingParams sTmpParams = new PreviewItemDrawingParams(0, 0, 0, 0);
+    private static final float[] sTempParamsArray = new float[3];
 
-    private ValueAnimator mValueAnimator;
+    private final ObjectAnimator mAnimator;
+    private final PreviewItemManager mItemManager;
+    private final PreviewItemDrawingParams mParams;
 
-    float finalScale;
-    float finalTransX;
-    float finalTransY;
+    public final float[] finalState;
 
     /**
      * @param params layout params to animate
@@ -43,33 +62,21 @@
      * @param duration duration in ms of the animation
      * @param onCompleteRunnable runnable to execute upon animation completion
      */
-    FolderPreviewItemAnim(final PreviewItemManager previewItemManager,
-            final PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
+    FolderPreviewItemAnim(PreviewItemManager itemManager,
+            PreviewItemDrawingParams params, int index0, int items0, int index1, int items1,
             int duration, final Runnable onCompleteRunnable) {
-        previewItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
+        mItemManager = itemManager;
+        mParams = params;
 
-        finalScale = sTmpParams.scale;
-        finalTransX = sTmpParams.transX;
-        finalTransY = sTmpParams.transY;
+        mItemManager.computePreviewItemDrawingParams(index1, items1, sTmpParams);
+        finalState = new float[] {sTmpParams.scale, sTmpParams.transX, sTmpParams.transY};
 
-        previewItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
+        mItemManager.computePreviewItemDrawingParams(index0, items0, sTmpParams);
+        float[] startState = new float[] {sTmpParams.scale, sTmpParams.transX, sTmpParams.transY};
 
-        final float scale0 = sTmpParams.scale;
-        final float transX0 = sTmpParams.transX;
-        final float transY0 = sTmpParams.transY;
-
-        mValueAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
-        mValueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener(){
-            public void onAnimationUpdate(ValueAnimator animation) {
-                float progress = animation.getAnimatedFraction();
-
-                params.transX = transX0 + progress * (finalTransX - transX0);
-                params.transY = transY0 + progress * (finalTransY - transY0);
-                params.scale = scale0 + progress * (finalScale - scale0);
-                previewItemManager.onParamsChanged();
-            }
-        });
-        mValueAnimator.addListener(new AnimatorListenerAdapter() {
+        mAnimator = ObjectAnimator.ofObject(this, PARAMS, new FloatArrayEvaluator(),
+                startState, finalState);
+        mAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 if (onCompleteRunnable != null) {
@@ -78,20 +85,26 @@
                 params.anim = null;
             }
         });
-        mValueAnimator.setDuration(duration);
+        mAnimator.setDuration(duration);
+    }
+
+    private void setParams(float[] values) {
+        mParams.scale = values[0];
+        mParams.transX = values[1];
+        mParams.transY = values[2];
+        mItemManager.onParamsChanged();
     }
 
     public void start() {
-        mValueAnimator.start();
+        mAnimator.start();
     }
 
     public void cancel() {
-        mValueAnimator.cancel();
+        mAnimator.cancel();
     }
 
     public boolean hasEqualFinalState(FolderPreviewItemAnim anim) {
-        return finalTransY == anim.finalTransY && finalTransX == anim.finalTransX &&
-                finalScale == anim.finalScale;
+        return Arrays.equals(finalState, anim.finalState);
 
     }
 }
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index b162fcf..86266e6 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -37,7 +37,6 @@
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
 import com.android.launcher3.util.Themes;
 
@@ -368,7 +367,7 @@
             mScaleAnimator.cancel();
         }
 
-        mScaleAnimator = LauncherAnimUtils.ofFloat(0f, 1.0f);
+        mScaleAnimator = ValueAnimator.ofFloat(0f, 1.0f);
 
         mScaleAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
@@ -400,37 +399,19 @@
         mScaleAnimator.start();
     }
 
-    public void animateToAccept(final CellLayout cl, final int cellX, final int cellY) {
-        Runnable onStart = new Runnable() {
-            @Override
-            public void run() {
-                delegateDrawing(cl, cellX, cellY);
-            }
-        };
-        animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER, onStart, null);
+    public void animateToAccept(CellLayout cl, int cellX, int cellY) {
+        animateScale(ACCEPT_SCALE_FACTOR, ACCEPT_COLOR_MULTIPLIER,
+                () -> delegateDrawing(cl, cellX, cellY), null);
     }
 
     public void animateToRest() {
         // This can be called multiple times -- we need to make sure the drawing delegate
         // is saved and restored at the beginning of the animation, since cancelling the
         // existing animation can clear the delgate.
-        final CellLayout cl = mDrawingDelegate;
-        final int cellX = delegateCellX;
-        final int cellY = delegateCellY;
-
-        Runnable onStart = new Runnable() {
-            @Override
-            public void run() {
-                delegateDrawing(cl, cellX, cellY);
-            }
-        };
-        Runnable onEnd = new Runnable() {
-            @Override
-            public void run() {
-                clearDrawingDelegate();
-            }
-        };
-        animateScale(1f, 1f, onStart, onEnd);
+        CellLayout cl = mDrawingDelegate;
+        int cellX = delegateCellX;
+        int cellY = delegateCellY;
+        animateScale(1f, 1f, () -> delegateDrawing(cl, cellX, cellY), this::clearDrawingDelegate);
     }
 
     public int getBackgroundAlpha() {
diff --git a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
index 607b7ca..c818462 100644
--- a/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
+++ b/src/com/android/launcher3/folder/PreviewItemDrawingParams.java
@@ -40,8 +40,8 @@
         // We ensure the update will not interfere with an animation on the layout params
         // If the final values differ, we cancel the animation.
         if (anim != null) {
-            if (anim.finalTransX == transX || anim.finalTransY == transY
-                    || anim.finalScale == scale) {
+            if (anim.finalState[1] == transX || anim.finalState[2] == transY
+                    || anim.finalState[0] == scale) {
                 return;
             }
             anim.cancel();
diff --git a/src/com/android/launcher3/notification/NotificationFooterLayout.java b/src/com/android/launcher3/notification/NotificationFooterLayout.java
index 66f525c..3cc9365 100644
--- a/src/com/android/launcher3/notification/NotificationFooterLayout.java
+++ b/src/com/android/launcher3/notification/NotificationFooterLayout.java
@@ -29,7 +29,6 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
-import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PropertyListBuilder;
@@ -151,7 +150,7 @@
 
     public void animateFirstNotificationTo(Rect toBounds,
             final IconAnimationEndListener callback) {
-        AnimatorSet animation = LauncherAnimUtils.createAnimatorSet();
+        AnimatorSet animation = new AnimatorSet();
         final View firstNotification = mIconRow.getChildAt(mIconRow.getChildCount() - 1);
 
         Rect fromBounds = sTempRect;
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index e157482..3bf8bef 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -340,7 +340,7 @@
     private void animateOpen() {
         setVisibility(View.VISIBLE);
 
-        final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
+        final AnimatorSet openAnim = new AnimatorSet();
         final Resources res = getResources();
         final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
         final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
@@ -388,7 +388,7 @@
         }
         mIsOpen = false;
 
-        final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
+        final AnimatorSet closeAnim = new AnimatorSet();
         // Hide the arrow
         closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0));
         closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0));