/* * Copyright (C) 2011 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.internal.widget.multiwaveview; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.Map.Entry; import android.animation.Animator.AnimatorListener; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.animation.PropertyValuesHolder; import android.animation.TimeInterpolator; import android.animation.ValueAnimator.AnimatorUpdateListener; import android.util.Log; class Tweener { private static final String TAG = "Tweener"; private static final boolean DEBUG = false; ObjectAnimator animator; private static HashMap sTweens = new HashMap(); public Tweener(ObjectAnimator anim) { animator = anim; } private static void remove(Animator animator) { Iterator> iter = sTweens.entrySet().iterator(); while (iter.hasNext()) { Entry entry = iter.next(); if (entry.getValue().animator == animator) { if (DEBUG) Log.v(TAG, "Removing tweener " + sTweens.get(entry.getKey()) + " sTweens.size() = " + sTweens.size()); iter.remove(); break; // an animator can only be attached to one object } } } public static Tweener to(Object object, long duration, Object... vars) { long delay = 0; AnimatorUpdateListener updateListener = null; AnimatorListener listener = null; TimeInterpolator interpolator = null; // Iterate through arguments and discover properties to animate ArrayList props = new ArrayList(vars.length/2); for (int i = 0; i < vars.length; i+=2) { if (!(vars[i] instanceof String)) { throw new IllegalArgumentException("Key must be a string: " + vars[i]); } String key = (String) vars[i]; Object value = vars[i+1]; if ("simultaneousTween".equals(key)) { // TODO } else if ("ease".equals(key)) { interpolator = (TimeInterpolator) value; // TODO: multiple interpolators? } else if ("onUpdate".equals(key) || "onUpdateListener".equals(key)) { updateListener = (AnimatorUpdateListener) value; } else if ("onComplete".equals(key) || "onCompleteListener".equals(key)) { listener = (AnimatorListener) value; } else if ("delay".equals(key)) { delay = ((Number) value).longValue(); } else if ("syncWith".equals(key)) { // TODO } else if (value instanceof float[]) { props.add(PropertyValuesHolder.ofFloat(key, ((float[])value)[0], ((float[])value)[1])); } else if (value instanceof int[]) { props.add(PropertyValuesHolder.ofInt(key, ((int[])value)[0], ((int[])value)[1])); } else if (value instanceof Number) { float floatValue = ((Number)value).floatValue(); props.add(PropertyValuesHolder.ofFloat(key, floatValue)); } else { throw new IllegalArgumentException( "Bad argument for key \"" + key + "\" with value " + value.getClass()); } } // Re-use existing tween, if present Tweener tween = sTweens.get(object); ObjectAnimator anim = null; if (tween == null) { anim = ObjectAnimator.ofPropertyValuesHolder(object, props.toArray(new PropertyValuesHolder[props.size()])); tween = new Tweener(anim); sTweens.put(object, tween); if (DEBUG) Log.v(TAG, "Added new Tweener " + tween); } else { anim = sTweens.get(object).animator; replace(props, object); // Cancel all animators for given object } if (interpolator != null) { anim.setInterpolator(interpolator); } // Update animation with properties discovered in loop above anim.setStartDelay(delay); anim.setDuration(duration); if (updateListener != null) { anim.removeAllUpdateListeners(); // There should be only one anim.addUpdateListener(updateListener); } if (listener != null) { anim.removeAllListeners(); // There should be only one. anim.addListener(listener); } anim.addListener(mCleanupListener); return tween; } Tweener from(Object object, long duration, Object... vars) { // TODO: for v of vars // toVars[v] = object[v] // object[v] = vars[v] return Tweener.to(object, duration, vars); } // Listener to watch for completed animations and remove them. private static AnimatorListener mCleanupListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { remove(animation); } @Override public void onAnimationCancel(Animator animation) { remove(animation); } }; public static void reset() { if (DEBUG) { Log.v(TAG, "Reset()"); if (sTweens.size() > 0) { Log.v(TAG, "Cleaning up " + sTweens.size() + " animations"); } } sTweens.clear(); } private static void replace(ArrayList props, Object... args) { for (final Object killobject : args) { Tweener tween = sTweens.get(killobject); if (tween != null) { tween.animator.cancel(); if (props != null) { tween.animator.setValues( props.toArray(new PropertyValuesHolder[props.size()])); } else { sTweens.remove(tween); } } } } }