OSDN Git Service

Fix bug where folder open animation gets finished early
authorMichael Jurka <mikejurka@google.com>
Tue, 9 Apr 2013 01:28:15 +0000 (18:28 -0700)
committerThe Android Automerger <android-build@android.com>
Tue, 9 Apr 2013 23:02:00 +0000 (16:02 -0700)
Also, sync FirstFrameAnimatorHelper with changes
made in Recents

Bug: 8530231

Change-Id: Ibf1a43f67d91df89a2338f0f0c0fb52ee5496e57

src/com/android/launcher2/FirstFrameAnimatorHelper.java
src/com/android/launcher2/LauncherViewPropertyAnimator.java

index 2351dd0..8eac7cd 100644 (file)
 
 package com.android.launcher2;
 
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.animation.Animator.AnimatorListener;
 import android.util.Log;
 import android.view.ViewTreeObserver;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 
 /*
  *  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 implements ValueAnimator.AnimatorUpdateListener {
+public class FirstFrameAnimatorHelper extends AnimatorListenerAdapter
+    implements ValueAnimator.AnimatorUpdateListener {
     private static final boolean DEBUG = false;
-    private static final int MAX_FIRST_FRAME_DELAY = 200;
+    private static final int MAX_DELAY = 1000;
     private static final int IDEAL_FRAME_DURATION = 16;
     private View mTarget;
     private long mStartFrame;
@@ -45,43 +49,65 @@ public class FirstFrameAnimatorHelper implements ValueAnimator.AnimatorUpdateLis
         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 initializeDrawListener(View view) {
+        if (sGlobalDrawListener != null) {
+            view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener);
+        }
         sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() {
                 private long mTime = System.currentTimeMillis();
                 public void onDraw() {
                     sGlobalFrameCounter++;
-                    long newTime = System.currentTimeMillis();
                     if (DEBUG) {
+                        long newTime = System.currentTimeMillis();
                         Log.d("FirstFrameAnimatorHelper", "TICK " + (newTime - mTime));
+                        mTime = newTime;
                     }
-                    mTime = newTime;
                 }
             };
         view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener);
     }
 
     public void onAnimationUpdate(final ValueAnimator animation) {
+        final long currentTime = System.currentTimeMillis();
         if (mStartTime == -1) {
             mStartFrame = sGlobalFrameCounter;
-            mStartTime = System.currentTimeMillis();
+            mStartTime = currentTime;
         }
 
-        if (!mHandlingOnAnimationUpdate) {
+        if (!mHandlingOnAnimationUpdate &&
+            // If the current play time exceeds the duration, the animation
+            // will get finished, even if we call setCurrentPlayTime -- therefore
+            // don't adjust the animation in that case
+            animation.getCurrentPlayTime() < animation.getDuration()) {
             mHandlingOnAnimationUpdate = true;
             long frameNum = sGlobalFrameCounter - mStartFrame;
-
             // If we haven't drawn our first frame, reset the time to t = 0
-            // (give up after 200ms of waiting though - might happen, for example, if we are no
-            // longer in the foreground and no frames are being rendered ever)
-            if (frameNum == 0 && System.currentTimeMillis() < mStartTime + MAX_FIRST_FRAME_DELAY) {
-                mTarget.getRootView().invalidate(); // make sure we'll do a draw
+            // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
+            // are no longer in the foreground and no frames are being rendered ever)
+            if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY) {
+                // The first frame on animations doesn't always trigger an invalidate...
+                // force an invalidate here to make sure the animation continues to advance
+                mTarget.getRootView().invalidate();
                 animation.setCurrentPlayTime(0);
 
             // For the second frame, if the first frame took more than 16ms,
             // adjust the start time and pretend it took only 16ms anyway. This
             // prevents a large jump in the animation due to an expensive first frame
-            } else if (frameNum == 1 && !mAdjustedSecondFrameTime &&
-                       System.currentTimeMillis() > mStartTime + 16) {
+            } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY &&
+                       !mAdjustedSecondFrameTime &&
+                       currentTime > mStartTime + IDEAL_FRAME_DURATION) {
                 animation.setCurrentPlayTime(IDEAL_FRAME_DURATION);
                 mAdjustedSecondFrameTime = true;
             } else {
index 274ff80..83b745e 100644 (file)
@@ -53,6 +53,7 @@ public class LauncherViewPropertyAnimator extends Animator implements AnimatorLi
     TimeInterpolator mInterpolator;
     ArrayList<Animator.AnimatorListener> mListeners;
     boolean mRunning = false;
+    FirstFrameAnimatorHelper mFirstFrameHelper;
 
     public LauncherViewPropertyAnimator(View target) {
         mTarget = target;
@@ -124,12 +125,10 @@ public class LauncherViewPropertyAnimator extends Animator implements AnimatorLi
 
     @Override
     public void onAnimationStart(Animator animation) {
-       // This is the first time we get a handle to the internal ValueAnimator
-       // used by the ViewPropertyAnimator.
-       // FirstFrameAnimatorHelper hooks itself up to the updates on the animator,
-       // and then adjusts the play time to keep the first two frames jank-free
-        new FirstFrameAnimatorHelper((ValueAnimator) animation, mTarget)
-                .onAnimationUpdate((ValueAnimator) 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);
@@ -193,6 +192,11 @@ public class LauncherViewPropertyAnimator extends Animator implements AnimatorLi
     @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);
         }