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