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