diff options
Diffstat (limited to 'services/java/com/android/server/power/RampAnimator.java')
-rw-r--r-- | services/java/com/android/server/power/RampAnimator.java | 131 |
1 files changed, 131 insertions, 0 deletions
diff --git a/services/java/com/android/server/power/RampAnimator.java b/services/java/com/android/server/power/RampAnimator.java new file mode 100644 index 0000000..6f063c3 --- /dev/null +++ b/services/java/com/android/server/power/RampAnimator.java @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2012 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.server.power; + +import android.animation.ValueAnimator; +import android.util.IntProperty; +import android.view.Choreographer; + +/** + * A custom animator that progressively updates a property value at + * a given variable rate until it reaches a particular target value. + */ +final class RampAnimator<T> { + private final T mObject; + private final IntProperty<T> mProperty; + private final Choreographer mChoreographer; + + private int mCurrentValue; + private int mTargetValue; + private int mRate; + + private boolean mAnimating; + private float mAnimatedValue; // higher precision copy of mCurrentValue + private long mLastFrameTimeNanos; + + private boolean mFirstTime = true; + + public RampAnimator(T object, IntProperty<T> property) { + mObject = object; + mProperty = property; + mChoreographer = Choreographer.getInstance(); + } + + /** + * Starts animating towards the specified value. + * + * If this is the first time the property is being set, the value jumps + * directly to the target. + * + * @param target The target value. + * @param rate The convergence rate, in units per second. + * @return True if the target differs from the previous target. + */ + public boolean animateTo(int target, int rate) { + // Immediately jump to the target the first time. + if (mFirstTime) { + mFirstTime = false; + mProperty.setValue(mObject, target); + mCurrentValue = target; + return true; + } + + // Adjust the rate based on the closest target. + // If a faster rate is specified, then use the new rate so that we converge + // more rapidly based on the new request. + // If a slower rate is specified, then use the new rate only if the current + // value is somewhere in between the new and the old target meaning that + // we will be ramping in a different direction to get there. + // Otherwise, continue at the previous rate. + if (!mAnimating + || rate > mRate + || (target <= mCurrentValue && mCurrentValue <= mTargetValue) + || (mTargetValue <= mCurrentValue && mCurrentValue <= target)) { + mRate = rate; + } + + final boolean changed = (mTargetValue != target); + mTargetValue = target; + + // Start animating. + if (!mAnimating && target != mCurrentValue) { + mAnimating = true; + mAnimatedValue = mCurrentValue; + mLastFrameTimeNanos = System.nanoTime(); + postCallback(); + } + + return changed; + } + + private void postCallback() { + mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null); + } + + private final Runnable mCallback = new Runnable() { + @Override // Choreographer callback + public void run() { + final long frameTimeNanos = mChoreographer.getFrameTimeNanos(); + final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos) + * 0.000000001f; + final float amount = timeDelta * mRate / ValueAnimator.getDurationScale(); + mLastFrameTimeNanos = frameTimeNanos; + + // Advance the animated value towards the target at the specified rate + // and clamp to the target. This gives us the new current value but + // we keep the animated value around to allow for fractional increments + // towards the target. + int oldCurrentValue = mCurrentValue; + if (mTargetValue > mCurrentValue) { + mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue); + } else { + mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue); + } + mCurrentValue = (int)Math.round(mAnimatedValue); + + if (oldCurrentValue != mCurrentValue) { + mProperty.setValue(mObject, mCurrentValue); + } + + if (mTargetValue != mCurrentValue) { + postCallback(); + } else { + mAnimating = false; + } + } + }; +} |