• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 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.deskclock.widget.multiwaveview;
18 
19 import android.animation.Animator;
20 import android.animation.Animator.AnimatorListener;
21 import android.animation.AnimatorListenerAdapter;
22 import android.animation.ObjectAnimator;
23 import android.animation.PropertyValuesHolder;
24 import android.animation.TimeInterpolator;
25 import android.animation.ValueAnimator.AnimatorUpdateListener;
26 import android.util.Log;
27 
28 import java.util.ArrayList;
29 import java.util.HashMap;
30 import java.util.Iterator;
31 import java.util.Map.Entry;
32 
33 class Tweener {
34     private static final String TAG = "Tweener";
35     private static final boolean DEBUG = false;
36 
37     ObjectAnimator animator;
38     private static HashMap<Object, Tweener> sTweens = new HashMap<Object, Tweener>();
39 
Tweener(ObjectAnimator anim)40     public Tweener(ObjectAnimator anim) {
41         animator = anim;
42     }
43 
remove(Animator animator)44     private static void remove(Animator animator) {
45         Iterator<Entry<Object, Tweener>> iter = sTweens.entrySet().iterator();
46         while (iter.hasNext()) {
47             Entry<Object, Tweener> entry = iter.next();
48             if (entry.getValue().animator == animator) {
49                 if (DEBUG) Log.v(TAG, "Removing tweener " + sTweens.get(entry.getKey())
50                         + " sTweens.size() = " + sTweens.size());
51                 iter.remove();
52                 break; // an animator can only be attached to one object
53             }
54         }
55     }
56 
to(Object object, long duration, Object... vars)57     public static Tweener to(Object object, long duration, Object... vars) {
58         long delay = 0;
59         AnimatorUpdateListener updateListener = null;
60         AnimatorListener listener = null;
61         TimeInterpolator interpolator = null;
62 
63         // Iterate through arguments and discover properties to animate
64         ArrayList<PropertyValuesHolder> props = new ArrayList<PropertyValuesHolder>(vars.length/2);
65         for (int i = 0; i < vars.length; i+=2) {
66             if (!(vars[i] instanceof String)) {
67                 throw new IllegalArgumentException("Key must be a string: " + vars[i]);
68             }
69             String key = (String) vars[i];
70             Object value = vars[i+1];
71 
72             if ("simultaneousTween".equals(key)) {
73                 // TODO
74             } else if ("ease".equals(key)) {
75                 interpolator = (TimeInterpolator) value; // TODO: multiple interpolators?
76             } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) {
77                 updateListener = (AnimatorUpdateListener) value;
78             } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) {
79                 listener = (AnimatorListener) value;
80             } else if ("delay".equals(key)) {
81                 delay = ((Number) value).longValue();
82             } else if ("syncWith".equals(key)) {
83                 // TODO
84             } else if (value instanceof float[]) {
85                 props.add(PropertyValuesHolder.ofFloat(key,
86                         ((float[])value)[0], ((float[])value)[1]));
87             } else if (value instanceof int[]) {
88                 props.add(PropertyValuesHolder.ofInt(key,
89                         ((int[])value)[0], ((int[])value)[1]));
90             } else if (value instanceof Number) {
91                 float floatValue = ((Number)value).floatValue();
92                 props.add(PropertyValuesHolder.ofFloat(key, floatValue));
93             } else {
94                 throw new IllegalArgumentException(
95                         "Bad argument for key \"" + key + "\" with value " + value.getClass());
96             }
97         }
98 
99         // Re-use existing tween, if present
100         Tweener tween = sTweens.get(object);
101         ObjectAnimator anim = null;
102         if (tween == null) {
103             anim = ObjectAnimator.ofPropertyValuesHolder(object,
104                     props.toArray(new PropertyValuesHolder[props.size()]));
105             tween = new Tweener(anim);
106             sTweens.put(object, tween);
107             if (DEBUG) Log.v(TAG, "Added new Tweener " + tween);
108         } else {
109             anim = sTweens.get(object).animator;
110             replace(props, object); // Cancel all animators for given object
111         }
112 
113         if (interpolator != null) {
114             anim.setInterpolator(interpolator);
115         }
116 
117         // Update animation with properties discovered in loop above
118         anim.setStartDelay(delay);
119         anim.setDuration(duration);
120         if (updateListener != null) {
121             anim.removeAllUpdateListeners(); // There should be only one
122             anim.addUpdateListener(updateListener);
123         }
124         if (listener != null) {
125             anim.removeAllListeners(); // There should be only one.
126             anim.addListener(listener);
127         }
128         anim.addListener(mCleanupListener);
129 
130         return tween;
131     }
132 
from(Object object, long duration, Object... vars)133     Tweener from(Object object, long duration, Object... vars) {
134         // TODO:  for v of vars
135         //            toVars[v] = object[v]
136         //            object[v] = vars[v]
137         return Tweener.to(object, duration, vars);
138     }
139 
140     // Listener to watch for completed animations and remove them.
141     private static AnimatorListener mCleanupListener = new AnimatorListenerAdapter() {
142 
143         @Override
144         public void onAnimationEnd(Animator animation) {
145             remove(animation);
146         }
147 
148         @Override
149         public void onAnimationCancel(Animator animation) {
150             remove(animation);
151         }
152     };
153 
reset()154     public static void reset() {
155         if (DEBUG) {
156             Log.v(TAG, "Reset()");
157             if (sTweens.size() > 0) {
158                 Log.v(TAG, "Cleaning up " + sTweens.size() + " animations");
159             }
160         }
161         sTweens.clear();
162     }
163 
replace(ArrayList<PropertyValuesHolder> props, Object... args)164     private static void replace(ArrayList<PropertyValuesHolder> props, Object... args) {
165         for (final Object killobject : args) {
166             Tweener tween = sTweens.get(killobject);
167             if (tween != null) {
168                 tween.animator.cancel();
169                 if (props != null) {
170                     tween.animator.setValues(
171                             props.toArray(new PropertyValuesHolder[props.size()]));
172                 } else {
173                     sTweens.remove(tween);
174                 }
175             }
176         }
177     }
178 }
179