Home | History | Annotate | Download | only in multiwaveview
      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.incallui.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 
     40     public Tweener(ObjectAnimator anim) {
     41         animator = anim;
     42     }
     43 
     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 
     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 
    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 
    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 
    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