1150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung/*
2150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * Copyright (C) 2010 The Android Open Source Project
3150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung *
4150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * Licensed under the Apache License, Version 2.0 (the "License");
5150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * you may not use this file except in compliance with the License.
6150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * You may obtain a copy of the License at
7150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung *
8150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung *      http://www.apache.org/licenses/LICENSE-2.0
9150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung *
10150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * Unless required by applicable law or agreed to in writing, software
11150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * distributed under the License is distributed on an "AS IS" BASIS,
12150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * See the License for the specific language governing permissions and
14150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * limitations under the License.
15150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung */
16150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
17150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungpackage com.android.launcher2;
18150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.Animator;
204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onoratoimport android.animation.AnimatorListenerAdapter;
21150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chungimport android.animation.ValueAnimator;
22f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurkaimport android.view.View;
23150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
24150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung/**
25150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * A convenience class for two-way animations, e.g. a fadeIn/fadeOut animation.
26150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * With a regular ValueAnimator, if you call reverse to show the 'out' animation, you'll get
27150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * a frame-by-frame mirror of the 'in' animation -- i.e., the interpolated values will
28150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * be exactly reversed. Using this class, both the 'in' and the 'out' animation use the
29150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung * interpolator in the same direction.
30150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung */
31472b281d5cb4f5660df981a6c912266b9f5703feChet Haasepublic class InterruptibleInOutAnimator {
32150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    private long mOriginalDuration;
33472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    private float mOriginalFromValue;
34472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    private float mOriginalToValue;
35472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    private ValueAnimator mAnimator;
36150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
374be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private boolean mFirstRun = true;
384be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
394be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    private Object mTag = null;
404be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
41fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    private static final int STOPPED = 0;
42fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    private static final int IN = 1;
43fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    private static final int OUT = 2;
44fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy
4508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy    // TODO: This isn't really necessary, but is here to help diagnose a bug in the drag viz
46fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    private int mDirection = STOPPED;
47fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy
48f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka    public InterruptibleInOutAnimator(View view, long duration, float fromValue, float toValue) {
49f1ad608c28c79c8e9b83d83ce9154f1b7284f412Michael Jurka        mAnimator = LauncherAnimUtils.ofFloat(view, fromValue, toValue).setDuration(duration);
50150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung        mOriginalDuration = duration;
51150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung        mOriginalFromValue = fromValue;
52150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung        mOriginalToValue = toValue;
5308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
548edd75c8bb0729a10cb39f614183e3e9ae4288e8Michael Jurka        mAnimator.addListener(new AnimatorListenerAdapter() {
553c4c20fbe682cb4b3ef94f09afe0af09171583f3Michael Jurka            @Override
568edd75c8bb0729a10cb39f614183e3e9ae4288e8Michael Jurka            public void onAnimationEnd(Animator animation) {
5708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy                mDirection = STOPPED;
5808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy            }
5908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        });
60150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    }
61150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
62fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    private void animate(int direction) {
63472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final long currentPlayTime = mAnimator.getCurrentPlayTime();
64472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float toValue = (direction == IN) ? mOriginalToValue : mOriginalFromValue;
65472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        final float startValue = mFirstRun ? mOriginalFromValue :
66472b281d5cb4f5660df981a6c912266b9f5703feChet Haase                ((Float) mAnimator.getAnimatedValue()).floatValue();
67fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy
68fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy        // Make sure it's stopped before we modify any values
69150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung        cancel();
70fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy
7108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // TODO: We don't really need to do the animation if startValue == toValue, but
7208ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // somehow that doesn't seem to work, possibly a quirk of the animation framework
7308ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mDirection = direction;
7408ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
7508ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        // Ensure we don't calculate a non-sensical duration
7608ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        long duration = mOriginalDuration - currentPlayTime;
7708ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mAnimator.setDuration(Math.max(0, Math.min(duration, mOriginalDuration)));
7808ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy
7908ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mAnimator.setFloatValues(startValue, toValue);
8008ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mAnimator.start();
8108ae2ec4847a971ad1b19c163e3a0d6307a8ed72Patrick Dubroy        mFirstRun = false;
82150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    }
83150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
84fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    public void cancel() {
85472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        mAnimator.cancel();
86fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy        mDirection = STOPPED;
87fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    }
88fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy
89fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    public void end() {
90472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        mAnimator.end();
91fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy        mDirection = STOPPED;
92fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    }
93fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy
94fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    /**
95fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy     * Return true when the animation is not running and it hasn't even been started.
96fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy     */
97fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    public boolean isStopped() {
98fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy        return mDirection == STOPPED;
99fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy    }
100fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy
101150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    /**
102150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     * This is the equivalent of calling Animator.start(), except that it can be called when
103150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     * the animation is running in the opposite direction, in which case we reverse
104150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     * direction and animate for a correspondingly shorter duration.
105150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     */
106150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    public void animateIn() {
107fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy        animate(IN);
108150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    }
109150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung
110150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    /**
111150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     * This is the roughly the equivalent of calling Animator.reverse(), except that it uses the
112150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     * same interpolation curve as animateIn(), rather than mirroring it. Also, like animateIn(),
113150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     * if the animation is currently running in the opposite direction, we reverse
114150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     * direction and animate for a correspondingly shorter duration.
115150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung     */
116150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    public void animateOut() {
117fe6bd87881e47b9ff38f58bd083042ae0f6a39d7Patrick Dubroy        animate(OUT);
1184be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    }
1194be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
1204be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    public void setTag(Object tag) {
1214be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        mTag = tag;
1224be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    }
1234be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato
1244be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato    public Object getTag() {
1254be866d3a1665aa2098cb5d38d535b1ad1aab6d6Joe Onorato        return mTag;
126150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung    }
127472b281d5cb4f5660df981a6c912266b9f5703feChet Haase
128472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    public ValueAnimator getAnimator() {
129472b281d5cb4f5660df981a6c912266b9f5703feChet Haase        return mAnimator;
130472b281d5cb4f5660df981a6c912266b9f5703feChet Haase    }
131150fbab7de7df45ce0e2d08fb0f0be87ff091c2fWinson Chung}
132