19630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown/* 29630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Copyright (C) 2012 The Android Open Source Project 39630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * 49630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License"); 59630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * you may not use this file except in compliance with the License. 69630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * You may obtain a copy of the License at 79630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * 89630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * http://www.apache.org/licenses/LICENSE-2.0 99630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * 109630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Unless required by applicable law or agreed to in writing, software 119630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS, 129630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 139630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * See the License for the specific language governing permissions and 149630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * limitations under the License. 159630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown */ 169630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 17ad9ef191f50767d8d5b6f0fbd4b59bb1400dcd25Jeff Brownpackage com.android.server.display; 189630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 199630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.animation.ValueAnimator; 209630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.util.IntProperty; 219630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownimport android.view.Choreographer; 229630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 239630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown/** 249630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * A custom animator that progressively updates a property value at 259630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * a given variable rate until it reaches a particular target value. 269630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown */ 279630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brownfinal class RampAnimator<T> { 289630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private final T mObject; 299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private final IntProperty<T> mProperty; 309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private final Choreographer mChoreographer; 319630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private int mCurrentValue; 339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private int mTargetValue; 349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private int mRate; 359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private boolean mAnimating; 379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private float mAnimatedValue; // higher precision copy of mCurrentValue 389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private long mLastFrameTimeNanos; 399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown private boolean mFirstTime = true; 419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 424255869ac00e700395832ee73b2294603d4b6eceJeff Brown private Listener mListener; 434255869ac00e700395832ee73b2294603d4b6eceJeff Brown 449630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown public RampAnimator(T object, IntProperty<T> property) { 459630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mObject = object; 469630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mProperty = property; 479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mChoreographer = Choreographer.getInstance(); 489630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 499630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 509630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown /** 519630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * Starts animating towards the specified value. 529630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * 530a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown * If this is the first time the property is being set or if the rate is 0, 540a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown * the value jumps directly to the target. 559630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * 569630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * @param target The target value. 570a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown * @param rate The convergence rate in units per second, or 0 to set the value immediately. 589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * @return True if the target differs from the previous target. 599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown */ 609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown public boolean animateTo(int target, int rate) { 619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // Immediately jump to the target the first time. 620a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown if (mFirstTime || rate <= 0) { 630a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown if (mFirstTime || target != mCurrentValue) { 640a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mFirstTime = false; 650a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mRate = 0; 660a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mTargetValue = target; 670a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mCurrentValue = target; 680a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mProperty.setValue(mObject, target); 690a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown if (mAnimating) { 700a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mAnimating = false; 710a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown cancelAnimationCallback(); 720a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown } 730a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown if (mListener != null) { 740a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mListener.onAnimationEnd(); 750a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown } 760a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown return true; 770a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown } 780a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown return false; 799630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 809630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 819630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // Adjust the rate based on the closest target. 829630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // If a faster rate is specified, then use the new rate so that we converge 839630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // more rapidly based on the new request. 849630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // If a slower rate is specified, then use the new rate only if the current 859630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // value is somewhere in between the new and the old target meaning that 869630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // we will be ramping in a different direction to get there. 879630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // Otherwise, continue at the previous rate. 889630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown if (!mAnimating 899630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown || rate > mRate 909630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown || (target <= mCurrentValue && mCurrentValue <= mTargetValue) 919630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown || (mTargetValue <= mCurrentValue && mCurrentValue <= target)) { 929630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mRate = rate; 939630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 949630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 959630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown final boolean changed = (mTargetValue != target); 969630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mTargetValue = target; 979630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 989630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // Start animating. 999630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown if (!mAnimating && target != mCurrentValue) { 1009630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mAnimating = true; 1019630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mAnimatedValue = mCurrentValue; 1029630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mLastFrameTimeNanos = System.nanoTime(); 1030a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown postAnimationCallback(); 1049630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 1059630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 1069630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown return changed; 1079630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 1089630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 1094255869ac00e700395832ee73b2294603d4b6eceJeff Brown /** 1104255869ac00e700395832ee73b2294603d4b6eceJeff Brown * Returns true if the animation is running. 1114255869ac00e700395832ee73b2294603d4b6eceJeff Brown */ 1124255869ac00e700395832ee73b2294603d4b6eceJeff Brown public boolean isAnimating() { 1134255869ac00e700395832ee73b2294603d4b6eceJeff Brown return mAnimating; 1144255869ac00e700395832ee73b2294603d4b6eceJeff Brown } 1154255869ac00e700395832ee73b2294603d4b6eceJeff Brown 1164255869ac00e700395832ee73b2294603d4b6eceJeff Brown /** 1174255869ac00e700395832ee73b2294603d4b6eceJeff Brown * Sets a listener to watch for animation events. 1184255869ac00e700395832ee73b2294603d4b6eceJeff Brown */ 1194255869ac00e700395832ee73b2294603d4b6eceJeff Brown public void setListener(Listener listener) { 1204255869ac00e700395832ee73b2294603d4b6eceJeff Brown mListener = listener; 1214255869ac00e700395832ee73b2294603d4b6eceJeff Brown } 1224255869ac00e700395832ee73b2294603d4b6eceJeff Brown 1230a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown private void postAnimationCallback() { 1240a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mChoreographer.postCallback(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null); 1250a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown } 1260a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown 1270a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown private void cancelAnimationCallback() { 1280a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown mChoreographer.removeCallbacks(Choreographer.CALLBACK_ANIMATION, mAnimationCallback, null); 1299630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 1309630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 1310a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown private final Runnable mAnimationCallback = new Runnable() { 1329630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown @Override // Choreographer callback 1339630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown public void run() { 1349630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown final long frameTimeNanos = mChoreographer.getFrameTimeNanos(); 1359630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos) 1369630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown * 0.000000001f; 1379630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mLastFrameTimeNanos = frameTimeNanos; 1389630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 1399630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // Advance the animated value towards the target at the specified rate 1409630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // and clamp to the target. This gives us the new current value but 1419630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // we keep the animated value around to allow for fractional increments 1429630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown // towards the target. 143a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner final float scale = ValueAnimator.getDurationScale(); 144a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner if (scale == 0) { 145a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner // Animation off. 146a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner mAnimatedValue = mTargetValue; 1479630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } else { 148a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner final float amount = timeDelta * mRate / scale; 149a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner if (mTargetValue > mCurrentValue) { 150a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue); 151a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner } else { 152a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue); 153a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner } 1549630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 155a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner final int oldCurrentValue = mCurrentValue; 156a7233fe31a8144f54eb041d12e631afdce25af4eCraig Mautner mCurrentValue = Math.round(mAnimatedValue); 1579630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 1589630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown if (oldCurrentValue != mCurrentValue) { 1599630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mProperty.setValue(mObject, mCurrentValue); 1609630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 1619630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown 1629630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown if (mTargetValue != mCurrentValue) { 1630a434776b836f8fbea1f84b7bfe158b4ddafc876Jeff Brown postAnimationCallback(); 1649630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } else { 1659630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown mAnimating = false; 1664255869ac00e700395832ee73b2294603d4b6eceJeff Brown if (mListener != null) { 1674255869ac00e700395832ee73b2294603d4b6eceJeff Brown mListener.onAnimationEnd(); 1684255869ac00e700395832ee73b2294603d4b6eceJeff Brown } 1699630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 1709630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown } 1719630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown }; 1724255869ac00e700395832ee73b2294603d4b6eceJeff Brown 1734255869ac00e700395832ee73b2294603d4b6eceJeff Brown public interface Listener { 1744255869ac00e700395832ee73b2294603d4b6eceJeff Brown void onAnimationEnd(); 1754255869ac00e700395832ee73b2294603d4b6eceJeff Brown } 1769630704ed3b265f008a8f64ec60a33cf9dcd3345Jeff Brown} 177