1 /* 2 * Copyright (C) 2010 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.launcher2; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.animation.ValueAnimator; 22 23 /** 24 * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation. 25 * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get 26 * a frame-by-frame mirror of the 'in' animation -- i.e., the interpolated values will 27 * be exactly reversed. Using this class, both the 'in' and the 'out' animation use the 28 * interpolator in the same direction. 29 */ 30 public class InterruptibleInOutAnimator { 31 private long mOriginalDuration; 32 private float mOriginalFromValue; 33 private float mOriginalToValue; 34 private ValueAnimator mAnimator; 35 36 private boolean mFirstRun = true; 37 38 private Object mTag = null; 39 40 private static final int STOPPED = 0; 41 private static final int IN = 1; 42 private static final int OUT = 2; 43 44 // TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz 45 private int mDirection = STOPPED; 46 47 public InterruptibleInOutAnimator(long duration, float fromValue, float toValue) { 48 mAnimator = ValueAnimator.ofFloat(fromValue, toValue).setDuration(duration); 49 mOriginalDuration = duration; 50 mOriginalFromValue = fromValue; 51 mOriginalToValue = toValue; 52 53 mAnimator.addListener(new AnimatorListenerAdapter() { 54 @Override 55 public void onAnimationEnd(Animator animation) { 56 mDirection = STOPPED; 57 } 58 }); 59 } 60 61 private void animate(int direction) { 62 final long currentPlayTime = mAnimator.getCurrentPlayTime(); 63 final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue; 64 final float startValue = mFirstRun ? mOriginalFromValue : 65 ((Float) mAnimator.getAnimatedValue()).floatValue(); 66 67 // Make sure it's stopped before we modify any values 68 cancel(); 69 70 // TODO: We don't really need to do the animation if startValue == toValue, but 71 // somehow that doesn't seem to work, possibly a quirk of the animation framework 72 mDirection = direction; 73 74 // Ensure we don't calculate a non-sensical duration 75 long duration = mOriginalDuration - currentPlayTime; 76 mAnimator.setDuration(Math.max(0, Math.min(duration, mOriginalDuration))); 77 78 mAnimator.setFloatValues(startValue, toValue); 79 mAnimator.start(); 80 mFirstRun = false; 81 } 82 83 public void cancel() { 84 mAnimator.cancel(); 85 mDirection = STOPPED; 86 } 87 88 public void end() { 89 mAnimator.end(); 90 mDirection = STOPPED; 91 } 92 93 /** 94 * Return true when the animation is not running and it hasn't even been started. 95 */ 96 public boolean isStopped() { 97 return mDirection == STOPPED; 98 } 99 100 /** 101 * This is the equivalent of calling Animator.start(), except that it can be called when 102 * the animation is running in the opposite direction, in which case we reverse 103 * direction and animate for a correspondingly shorter duration. 104 */ 105 public void animateIn() { 106 animate(IN); 107 } 108 109 /** 110 * This is the roughly the equivalent of calling Animator.reverse(), except that it uses the 111 * same interpolation curve as animateIn(), rather than mirroring it. Also, like animateIn(), 112 * if the animation is currently running in the opposite direction, we reverse 113 * direction and animate for a correspondingly shorter duration. 114 */ 115 public void animateOut() { 116 animate(OUT); 117 } 118 119 public void setTag(Object tag) { 120 mTag = tag; 121 } 122 123 public Object getTag() { 124 return mTag; 125 } 126 127 public ValueAnimator getAnimator() { 128 return mAnimator; 129 } 130 } 131