1f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka/* 2f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * Copyright (C) 2013 The Android Open Source Project 3f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * 4f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * Licensed under the Apache License, Version 2.0 (the "License"); 5f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * you may not use this file except in compliance with the License. 6f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * You may obtain a copy of the License at 7f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * 8f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * http://www.apache.org/licenses/LICENSE-2.0 9f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * 10f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * Unless required by applicable law or agreed to in writing, software 11f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * distributed under the License is distributed on an "AS IS" BASIS, 12f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * See the License for the specific language governing permissions and 14f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * limitations under the License. 15f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka */ 16f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 17f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurkapackage com.android.launcher2; 18f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 1939b599e0641047e5583cf717d35a4cb080049665Michael Jurkaimport android.animation.Animator; 2039b599e0641047e5583cf717d35a4cb080049665Michael Jurkaimport android.animation.AnimatorListenerAdapter; 21f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurkaimport android.animation.ValueAnimator; 22f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurkaimport android.util.Log; 23f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurkaimport android.view.View; 2439b599e0641047e5583cf717d35a4cb080049665Michael Jurkaimport android.view.ViewPropertyAnimator; 25032e6bad1ba588ed8a884fb8f28fb8596efac480Michael Jurkaimport android.view.ViewTreeObserver; 26f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 27f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka/* 28f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * This is a helper class that listens to updates from the corresponding animation. 29f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * For the first two frames, it adjusts the current play time of the animation to 30f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka * prevent jank at the beginning of the animation 31f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka */ 3239b599e0641047e5583cf717d35a4cb080049665Michael Jurkapublic class FirstFrameAnimatorHelper extends AnimatorListenerAdapter 3339b599e0641047e5583cf717d35a4cb080049665Michael Jurka implements ValueAnimator.AnimatorUpdateListener { 34f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private static final boolean DEBUG = false; 3539b599e0641047e5583cf717d35a4cb080049665Michael Jurka private static final int MAX_DELAY = 1000; 36f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private static final int IDEAL_FRAME_DURATION = 16; 37f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private View mTarget; 38f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private long mStartFrame; 39f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private long mStartTime = -1; 40f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private boolean mHandlingOnAnimationUpdate; 41f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private boolean mAdjustedSecondFrameTime; 42f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 43f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private static ViewTreeObserver.OnDrawListener sGlobalDrawListener; 44f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private static long sGlobalFrameCounter; 45cd496d723ca6b4b100771ae66f09007e7acf0d17Michael Jurka private static boolean sVisible; 46f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 47f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka public FirstFrameAnimatorHelper(ValueAnimator animator, View target) { 48f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka mTarget = target; 49f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka animator.addUpdateListener(this); 50f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 51f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 5239b599e0641047e5583cf717d35a4cb080049665Michael Jurka public FirstFrameAnimatorHelper(ViewPropertyAnimator vpa, View target) { 5339b599e0641047e5583cf717d35a4cb080049665Michael Jurka mTarget = target; 5439b599e0641047e5583cf717d35a4cb080049665Michael Jurka vpa.setListener(this); 5539b599e0641047e5583cf717d35a4cb080049665Michael Jurka } 5639b599e0641047e5583cf717d35a4cb080049665Michael Jurka 5739b599e0641047e5583cf717d35a4cb080049665Michael Jurka // only used for ViewPropertyAnimators 5839b599e0641047e5583cf717d35a4cb080049665Michael Jurka public void onAnimationStart(Animator animation) { 5939b599e0641047e5583cf717d35a4cb080049665Michael Jurka final ValueAnimator va = (ValueAnimator) animation; 6039b599e0641047e5583cf717d35a4cb080049665Michael Jurka va.addUpdateListener(FirstFrameAnimatorHelper.this); 6139b599e0641047e5583cf717d35a4cb080049665Michael Jurka onAnimationUpdate(va); 6239b599e0641047e5583cf717d35a4cb080049665Michael Jurka } 6339b599e0641047e5583cf717d35a4cb080049665Michael Jurka 64cd496d723ca6b4b100771ae66f09007e7acf0d17Michael Jurka public static void setIsVisible(boolean visible) { 65cd496d723ca6b4b100771ae66f09007e7acf0d17Michael Jurka sVisible = visible; 66cd496d723ca6b4b100771ae66f09007e7acf0d17Michael Jurka } 67cd496d723ca6b4b100771ae66f09007e7acf0d17Michael Jurka 68f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka public static void initializeDrawListener(View view) { 6939b599e0641047e5583cf717d35a4cb080049665Michael Jurka if (sGlobalDrawListener != null) { 7039b599e0641047e5583cf717d35a4cb080049665Michael Jurka view.getViewTreeObserver().removeOnDrawListener(sGlobalDrawListener); 7139b599e0641047e5583cf717d35a4cb080049665Michael Jurka } 72f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka sGlobalDrawListener = new ViewTreeObserver.OnDrawListener() { 73f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka private long mTime = System.currentTimeMillis(); 74f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka public void onDraw() { 75f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka sGlobalFrameCounter++; 76f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka if (DEBUG) { 7739b599e0641047e5583cf717d35a4cb080049665Michael Jurka long newTime = System.currentTimeMillis(); 78f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka Log.d("FirstFrameAnimatorHelper", "TICK " + (newTime - mTime)); 7939b599e0641047e5583cf717d35a4cb080049665Michael Jurka mTime = newTime; 80f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 81f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 82f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka }; 83f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka view.getViewTreeObserver().addOnDrawListener(sGlobalDrawListener); 84cd496d723ca6b4b100771ae66f09007e7acf0d17Michael Jurka sVisible = true; 85f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 86f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 8798720c96ee8c1eab026903dd83507a3cc50de900Michael Jurka public void onAnimationUpdate(final ValueAnimator animation) { 8839b599e0641047e5583cf717d35a4cb080049665Michael Jurka final long currentTime = System.currentTimeMillis(); 89f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka if (mStartTime == -1) { 90f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka mStartFrame = sGlobalFrameCounter; 9139b599e0641047e5583cf717d35a4cb080049665Michael Jurka mStartTime = currentTime; 92f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 93f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 9439b599e0641047e5583cf717d35a4cb080049665Michael Jurka if (!mHandlingOnAnimationUpdate && 95cd496d723ca6b4b100771ae66f09007e7acf0d17Michael Jurka sVisible && 9639b599e0641047e5583cf717d35a4cb080049665Michael Jurka // If the current play time exceeds the duration, the animation 9739b599e0641047e5583cf717d35a4cb080049665Michael Jurka // will get finished, even if we call setCurrentPlayTime -- therefore 9839b599e0641047e5583cf717d35a4cb080049665Michael Jurka // don't adjust the animation in that case 9939b599e0641047e5583cf717d35a4cb080049665Michael Jurka animation.getCurrentPlayTime() < animation.getDuration()) { 100f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka mHandlingOnAnimationUpdate = true; 101f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka long frameNum = sGlobalFrameCounter - mStartFrame; 102f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka // If we haven't drawn our first frame, reset the time to t = 0 10339b599e0641047e5583cf717d35a4cb080049665Michael Jurka // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we 10439b599e0641047e5583cf717d35a4cb080049665Michael Jurka // are no longer in the foreground and no frames are being rendered ever) 10539b599e0641047e5583cf717d35a4cb080049665Michael Jurka if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY) { 10639b599e0641047e5583cf717d35a4cb080049665Michael Jurka // The first frame on animations doesn't always trigger an invalidate... 10739b599e0641047e5583cf717d35a4cb080049665Michael Jurka // force an invalidate here to make sure the animation continues to advance 10839b599e0641047e5583cf717d35a4cb080049665Michael Jurka mTarget.getRootView().invalidate(); 109f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka animation.setCurrentPlayTime(0); 110f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 111f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka // For the second frame, if the first frame took more than 16ms, 112f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka // adjust the start time and pretend it took only 16ms anyway. This 113f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka // prevents a large jump in the animation due to an expensive first frame 11439b599e0641047e5583cf717d35a4cb080049665Michael Jurka } else if (frameNum == 1 && currentTime < mStartTime + MAX_DELAY && 11539b599e0641047e5583cf717d35a4cb080049665Michael Jurka !mAdjustedSecondFrameTime && 11639b599e0641047e5583cf717d35a4cb080049665Michael Jurka currentTime > mStartTime + IDEAL_FRAME_DURATION) { 117f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka animation.setCurrentPlayTime(IDEAL_FRAME_DURATION); 118f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka mAdjustedSecondFrameTime = true; 119f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } else { 120f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka if (frameNum > 1) { 12198720c96ee8c1eab026903dd83507a3cc50de900Michael Jurka mTarget.post(new Runnable() { 12298720c96ee8c1eab026903dd83507a3cc50de900Michael Jurka public void run() { 12398720c96ee8c1eab026903dd83507a3cc50de900Michael Jurka animation.removeUpdateListener(FirstFrameAnimatorHelper.this); 12498720c96ee8c1eab026903dd83507a3cc50de900Michael Jurka } 12598720c96ee8c1eab026903dd83507a3cc50de900Michael Jurka }); 126f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 127f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka if (DEBUG) print(animation); 128f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 129f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka mHandlingOnAnimationUpdate = false; 130f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } else { 131f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka if (DEBUG) print(animation); 132f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 133f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 134f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka 135f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka public void print(ValueAnimator animation) { 136f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration(); 137f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka Log.d("FirstFrameAnimatorHelper", sGlobalFrameCounter + 138f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka "(" + (sGlobalFrameCounter - mStartFrame) + ") " + mTarget + " dirty? " + 139f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka mTarget.isDirty() + " " + flatFraction + " " + this + " " + animation); 140f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka } 141f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka} 142