Home | History | Annotate | Download | only in power
      1 /*
      2  * Copyright (C) 2012 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.power;
     18 
     19 import android.animation.ValueAnimator;
     20 import android.util.IntProperty;
     21 import android.view.Choreographer;
     22 
     23 /**
     24  * A custom animator that progressively updates a property value at
     25  * a given variable rate until it reaches a particular target value.
     26  */
     27 final class RampAnimator<T> {
     28     private final T mObject;
     29     private final IntProperty<T> mProperty;
     30     private final Choreographer mChoreographer;
     31 
     32     private int mCurrentValue;
     33     private int mTargetValue;
     34     private int mRate;
     35 
     36     private boolean mAnimating;
     37     private float mAnimatedValue; // higher precision copy of mCurrentValue
     38     private long mLastFrameTimeNanos;
     39 
     40     private boolean mFirstTime = true;
     41 
     42     public RampAnimator(T object, IntProperty<T> property) {
     43         mObject = object;
     44         mProperty = property;
     45         mChoreographer = Choreographer.getInstance();
     46     }
     47 
     48     /**
     49      * Starts animating towards the specified value.
     50      *
     51      * If this is the first time the property is being set, the value jumps
     52      * directly to the target.
     53      *
     54      * @param target The target value.
     55      * @param rate The convergence rate, in units per second.
     56      * @return True if the target differs from the previous target.
     57      */
     58     public boolean animateTo(int target, int rate) {
     59         // Immediately jump to the target the first time.
     60         if (mFirstTime) {
     61             mFirstTime = false;
     62             mProperty.setValue(mObject, target);
     63             mCurrentValue = target;
     64             return true;
     65         }
     66 
     67         // Adjust the rate based on the closest target.
     68         // If a faster rate is specified, then use the new rate so that we converge
     69         // more rapidly based on the new request.
     70         // If a slower rate is specified, then use the new rate only if the current
     71         // value is somewhere in between the new and the old target meaning that
     72         // we will be ramping in a different direction to get there.
     73         // Otherwise, continue at the previous rate.
     74         if (!mAnimating
     75                 || rate > mRate
     76                 || (target <= mCurrentValue && mCurrentValue <= mTargetValue)
     77                 || (mTargetValue <= mCurrentValue && mCurrentValue <= target)) {
     78             mRate = rate;
     79         }
     80 
     81         final boolean changed = (mTargetValue != target);
     82         mTargetValue = target;
     83 
     84         // Start animating.
     85         if (!mAnimating && target != mCurrentValue) {
     86             mAnimating = true;
     87             mAnimatedValue = mCurrentValue;
     88             mLastFrameTimeNanos = System.nanoTime();
     89             postCallback();
     90         }
     91 
     92         return changed;
     93     }
     94 
     95     private void postCallback() {
     96         mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mCallback, null);
     97     }
     98 
     99     private final Runnable mCallback = new Runnable() {
    100         @Override // Choreographer callback
    101         public void run() {
    102             final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
    103             final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
    104                     * 0.000000001f;
    105             mLastFrameTimeNanos = frameTimeNanos;
    106 
    107             // Advance the animated value towards the target at the specified rate
    108             // and clamp to the target. This gives us the new current value but
    109             // we keep the animated value around to allow for fractional increments
    110             // towards the target.
    111             final float scale = ValueAnimator.getDurationScale();
    112             if (scale == 0) {
    113                 // Animation off.
    114                 mAnimatedValue = mTargetValue;
    115             } else {
    116                 final float amount = timeDelta * mRate / scale;
    117                 if (mTargetValue > mCurrentValue) {
    118                     mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
    119                 } else {
    120                     mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
    121                 }
    122             }
    123             final int oldCurrentValue = mCurrentValue;
    124             mCurrentValue = Math.round(mAnimatedValue);
    125 
    126             if (oldCurrentValue != mCurrentValue) {
    127                 mProperty.setValue(mObject, mCurrentValue);
    128             }
    129 
    130             if (mTargetValue != mCurrentValue) {
    131                 postCallback();
    132             } else {
    133                 mAnimating = false;
    134             }
    135         }
    136     };
    137 }
    138