1d05336248c5600cde35ad564840532f59b4c085cChiao Cheng/*
2d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * Copyright (C) 2011 The Android Open Source Project
3d05336248c5600cde35ad564840532f59b4c085cChiao Cheng *
4d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * Licensed under the Apache License, Version 2.0 (the "License");
5d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * you may not use this file except in compliance with the License.
6d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * You may obtain a copy of the License at
7d05336248c5600cde35ad564840532f59b4c085cChiao Cheng *
8d05336248c5600cde35ad564840532f59b4c085cChiao Cheng *      http://www.apache.org/licenses/LICENSE-2.0
9d05336248c5600cde35ad564840532f59b4c085cChiao Cheng *
10d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * Unless required by applicable law or agreed to in writing, software
11d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * distributed under the License is distributed on an "AS IS" BASIS,
12d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * See the License for the specific language governing permissions and
14d05336248c5600cde35ad564840532f59b4c085cChiao Cheng * limitations under the License.
15d05336248c5600cde35ad564840532f59b4c085cChiao Cheng */
16d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
17d05336248c5600cde35ad564840532f59b4c085cChiao Chengpackage com.android.incallui.widget.multiwaveview;
18d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
19d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.animation.Animator;
20d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.animation.Animator.AnimatorListener;
21d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.animation.AnimatorListenerAdapter;
22d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.animation.ObjectAnimator;
23d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.animation.PropertyValuesHolder;
24d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.animation.TimeInterpolator;
25d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.animation.ValueAnimator.AnimatorUpdateListener;
26d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport android.util.Log;
27d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
28d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport java.util.ArrayList;
29d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport java.util.HashMap;
30d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport java.util.Iterator;
31d05336248c5600cde35ad564840532f59b4c085cChiao Chengimport java.util.Map.Entry;
32d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
33d05336248c5600cde35ad564840532f59b4c085cChiao Chengclass Tweener {
34d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    private static final String TAG = "Tweener";
35d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    private static final boolean DEBUG = false;
36d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
37d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    ObjectAnimator animator;
38d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
39d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
40d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    public Tweener(ObjectAnimator anim) {
41d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        animator = anim;
42d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    }
43d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
44d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    private static void remove(Animator animator) {
45d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        Iterator<Entry<Object, Tweener>> iter = sTweens.entrySet().iterator();
46d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        while (iter.hasNext()) {
47d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            Entry<Object, Tweener> entry = iter.next();
48d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            if (entry.getValue().animator == animator) {
49d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                if (DEBUG) Log.v(TAG, "Removing tweener " + sTweens.get(entry.getKey())
50d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                        + " sTweens.size() = " + sTweens.size());
51d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                iter.remove();
52d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                break; // an animator can only be attached to one object
53d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            }
54d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
55d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    }
56d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
57d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    public static Tweener to(Object object, long duration, Object... vars) {
58d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        long delay = 0;
59d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        AnimatorUpdateListener updateListener = null;
60d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        AnimatorListener listener = null;
61d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        TimeInterpolator interpolator = null;
62d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
63d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        // Iterate through arguments and discover properties to animate
64d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2);
65d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        for (int i = 0; i < vars.length; i+=2) {
66d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            if (!(vars[i] instanceof String)) {
67d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                throw new IllegalArgumentException("Key must be a string: " + vars[i]);
68d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            }
69d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            String key = (String) vars[i];
70d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            Object value = vars[i+1];
71d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
72d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            if ("simultaneousTween".equals(key)) {
73d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                // TODO
74d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if ("ease".equals(key)) {
75d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
76d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
77d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                updateListener = (AnimatorUpdateListener) value;
78d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) {
79d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                listener = (AnimatorListener) value;
80d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if ("delay".equals(key)) {
81d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                delay = ((Number) value).longValue();
82d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if ("syncWith".equals(key)) {
83d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                // TODO
84d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if (value instanceof float[]) {
85d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                props.add(PropertyValuesHolder.ofFloat(key,
86d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                        ((float[])value)[0], ((float[])value)[1]));
87d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if (value instanceof int[]) {
88d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                props.add(PropertyValuesHolder.ofInt(key,
89d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                        ((int[])value)[0], ((int[])value)[1]));
90d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else if (value instanceof Number) {
91d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                float floatValue = ((Number)value).floatValue();
92d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                props.add(PropertyValuesHolder.ofFloat(key, floatValue));
93d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            } else {
94d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                throw new IllegalArgumentException(
95d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                        "Bad argument for key \"" + key + "\" with value " + value.getClass());
96d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            }
97d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
98d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
99d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        // Re-use existing tween, if present
100d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        Tweener tween = sTweens.get(object);
101d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        ObjectAnimator anim = null;
102d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        if (tween == null) {
103d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            anim = ObjectAnimator.ofPropertyValuesHolder(object,
104d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                    props.toArray(new PropertyValuesHolder[props.size()]));
105d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            tween = new Tweener(anim);
106d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            sTweens.put(object, tween);
107d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            if (DEBUG) Log.v(TAG, "Added new Tweener " + tween);
108d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        } else {
109d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            anim = sTweens.get(object).animator;
110d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            replace(props, object); // Cancel all animators for given object
111d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
112d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
113d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        if (interpolator != null) {
114d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            anim.setInterpolator(interpolator);
115d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
116d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
117d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        // Update animation with properties discovered in loop above
118d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        anim.setStartDelay(delay);
119d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        anim.setDuration(duration);
120d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        if (updateListener != null) {
121d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            anim.removeAllUpdateListeners(); // There should be only one
122d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            anim.addUpdateListener(updateListener);
123d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
124d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        if (listener != null) {
125d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            anim.removeAllListeners(); // There should be only one.
126d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            anim.addListener(listener);
127d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
128d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        anim.addListener(mCleanupListener);
129d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
130d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        return tween;
131d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    }
132d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
133d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    Tweener from(Object object, long duration, Object... vars) {
134d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        // TODO:  for v of vars
135d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        //            toVars[v] = object[v]
136d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        //            object[v] = vars[v]
137d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        return Tweener.to(object, duration, vars);
138d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    }
139d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
140d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    // Listener to watch for completed animations and remove them.
141d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    private static AnimatorListener mCleanupListener = new AnimatorListenerAdapter() {
142d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
143d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        @Override
144d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        public void onAnimationEnd(Animator animation) {
145d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            remove(animation);
146d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
147d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
148d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        @Override
149d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        public void onAnimationCancel(Animator animation) {
150d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            remove(animation);
151d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
152d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    };
153d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
154d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    public static void reset() {
155d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        if (DEBUG) {
156d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            Log.v(TAG, "Reset()");
157d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            if (sTweens.size() > 0) {
158d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                Log.v(TAG, "Cleaning up " + sTweens.size() + " animations");
159d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            }
160d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
161d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        sTweens.clear();
162d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    }
163d05336248c5600cde35ad564840532f59b4c085cChiao Cheng
164d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    private static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
165d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        for (final Object killobject : args) {
166d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            Tweener tween = sTweens.get(killobject);
167d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            if (tween != null) {
168d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                tween.animator.cancel();
169d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                if (props != null) {
170d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                    tween.animator.setValues(
171d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                            props.toArray(new PropertyValuesHolder[props.size()]));
172d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                } else {
173d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                    sTweens.remove(tween);
174d05336248c5600cde35ad564840532f59b4c085cChiao Cheng                }
175d05336248c5600cde35ad564840532f59b4c085cChiao Cheng            }
176d05336248c5600cde35ad564840532f59b4c085cChiao Cheng        }
177d05336248c5600cde35ad564840532f59b4c085cChiao Cheng    }
178d05336248c5600cde35ad564840532f59b4c085cChiao Cheng}
179