change package name to uiuios
This commit is contained in:
136
src/com/android/uiuios/FirstFrameAnimatorHelper.java
Normal file
136
src/com/android/uiuios/FirstFrameAnimatorHelper.java
Normal file
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright (C) 2013 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 com.android.uiuios;
|
||||
|
||||
import static com.android.uiuios.Utilities.SINGLE_FRAME_MS;
|
||||
|
||||
import android.animation.ValueAnimator;
|
||||
import android.animation.ValueAnimator.AnimatorUpdateListener;
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.View.OnAttachStateChangeListener;
|
||||
import android.view.ViewTreeObserver.OnDrawListener;
|
||||
|
||||
/*
|
||||
* 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 OnDrawListener, OnAttachStateChangeListener {
|
||||
|
||||
private static final String TAG = "FirstFrameAnimatorHlpr";
|
||||
private static final boolean DEBUG = false;
|
||||
private static final int MAX_DELAY = 1000;
|
||||
|
||||
private View mRootView;
|
||||
private long mGlobalFrameCount;
|
||||
|
||||
public FirstFrameAnimatorHelper(View target) {
|
||||
target.addOnAttachStateChangeListener(this);
|
||||
if (target.isAttachedToWindow()) {
|
||||
onViewAttachedToWindow(target);
|
||||
}
|
||||
}
|
||||
|
||||
public <T extends ValueAnimator> T addTo(T anim) {
|
||||
anim.addUpdateListener(new MyListener());
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw() {
|
||||
mGlobalFrameCount ++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View view) {
|
||||
mRootView = view.getRootView();
|
||||
mRootView.getViewTreeObserver().addOnDrawListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View view) {
|
||||
if (mRootView != null) {
|
||||
mRootView.getViewTreeObserver().removeOnDrawListener(this);
|
||||
mRootView = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class MyListener implements AnimatorUpdateListener {
|
||||
|
||||
private long mStartFrame;
|
||||
private long mStartTime = -1;
|
||||
private boolean mHandlingOnAnimationUpdate;
|
||||
private boolean mAdjustedSecondFrameTime;
|
||||
|
||||
@Override
|
||||
public void onAnimationUpdate(final ValueAnimator animation) {
|
||||
final long currentTime = System.currentTimeMillis();
|
||||
if (mStartTime == -1) {
|
||||
mStartFrame = mGlobalFrameCount;
|
||||
mStartTime = currentTime;
|
||||
}
|
||||
|
||||
final long currentPlayTime = animation.getCurrentPlayTime();
|
||||
boolean isFinalFrame = Float.compare(1f, animation.getAnimatedFraction()) == 0;
|
||||
|
||||
if (!mHandlingOnAnimationUpdate &&
|
||||
mRootView != null &&
|
||||
mRootView.getWindowVisibility() == View.VISIBLE &&
|
||||
// If the current play time exceeds the duration, or the animated fraction is 1,
|
||||
// the animation will get finished, even if we call setCurrentPlayTime --
|
||||
// therefore don't adjust the animation in that case
|
||||
currentPlayTime < animation.getDuration() && !isFinalFrame) {
|
||||
mHandlingOnAnimationUpdate = true;
|
||||
long frameNum = mGlobalFrameCount - mStartFrame;
|
||||
|
||||
// If we haven't drawn our first frame, reset the time to t = 0
|
||||
// (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 && currentPlayTime > 0) {
|
||||
// The first frame on animations doesn't always trigger an invalidate...
|
||||
// force an invalidate here to make sure the animation continues to advance
|
||||
mRootView.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 && currentTime < mStartTime + MAX_DELAY &&
|
||||
!mAdjustedSecondFrameTime &&
|
||||
currentTime > mStartTime + SINGLE_FRAME_MS &&
|
||||
currentPlayTime > SINGLE_FRAME_MS) {
|
||||
animation.setCurrentPlayTime(SINGLE_FRAME_MS);
|
||||
mAdjustedSecondFrameTime = true;
|
||||
} else {
|
||||
if (frameNum > 1) {
|
||||
mRootView.post(() -> animation.removeUpdateListener(this));
|
||||
}
|
||||
if (DEBUG) print(animation);
|
||||
}
|
||||
mHandlingOnAnimationUpdate = false;
|
||||
} else {
|
||||
if (DEBUG) print(animation);
|
||||
}
|
||||
}
|
||||
|
||||
public void print(ValueAnimator animation) {
|
||||
float flatFraction = animation.getCurrentPlayTime() / (float) animation.getDuration();
|
||||
Log.d(TAG, mGlobalFrameCount +
|
||||
"(" + (mGlobalFrameCount - mStartFrame) + ") " + mRootView + " dirty? " +
|
||||
mRootView.isDirty() + " " + flatFraction + " " + this + " " + animation);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user