From d51d368f2d512ab657b8ae45780c82c0dbea94c3 Mon Sep 17 00:00:00 2001 From: Chet Haase Date: Wed, 11 Aug 2010 19:46:48 -0700 Subject: [PATCH] Change animator xml importing to use new inflater class Change-Id: I97225ee9868f4dcce5e4c1ba55e16414eb6c0464 --- api/current.xml | 72 +++-- .../android/animation/AnimatableInflater.java | 269 ++++++++++++++++++ core/java/android/animation/Animator.java | 117 ++------ .../android/animation/PropertyAnimator.java | 30 +- core/java/android/app/FragmentManager.java | 6 +- .../view/animation/AnimationUtils.java | 103 ------- 6 files changed, 351 insertions(+), 246 deletions(-) create mode 100644 core/java/android/animation/AnimatableInflater.java diff --git a/api/current.xml b/api/current.xml index cbbf3d1fe8bfc..8ff263c94f615 100644 --- a/api/current.xml +++ b/api/current.xml @@ -19966,6 +19966,40 @@ + + + + + + + + + + + + - - - - + + + + - - - - - - - - - - - - + * For performance reasons, menu inflation relies heavily on pre-processing of + * XML files that is done at build time. Therefore, it is not currently possible + * to use MenuInflater with an XmlPullParser over a plain XML file at runtime; + * it only works with an XmlPullParser returned from a compiled resource (R. + * something file.) + */ +public class AnimatableInflater { + + /** + * These flags are used when parsing Sequencer objects + */ + private static final int TOGETHER = 0; + private static final int SEQUENTIALLY = 1; + + /** + * Enum values used in XML attributes to indicate the value for mValueType + */ + private static final int VALUE_TYPE_FLOAT = 0; + private static final int VALUE_TYPE_INT = 1; + private static final int VALUE_TYPE_DOUBLE = 2; + private static final int VALUE_TYPE_COLOR = 3; + private static final int VALUE_TYPE_CUSTOM = 4; + + /** + * Loads an {@link Animatable} object from a resource + * + * @param context Application context used to access resources + * @param id The resource id of the animation to load + * @return The animatable object reference by the specified id + * @throws android.content.res.Resources.NotFoundException when the animation cannot be loaded + */ + public static Animatable loadAnimatable(Context context, int id) + throws NotFoundException { + + XmlResourceParser parser = null; + try { + parser = context.getResources().getAnimation(id); + return createAnimatableFromXml(context, parser); + } catch (XmlPullParserException ex) { + Resources.NotFoundException rnf = + new Resources.NotFoundException("Can't load animation resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(ex); + throw rnf; + } catch (IOException ex) { + Resources.NotFoundException rnf = + new Resources.NotFoundException("Can't load animation resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(ex); + throw rnf; + } finally { + if (parser != null) parser.close(); + } + } + + private static Animatable createAnimatableFromXml(Context c, XmlPullParser parser) + throws XmlPullParserException, IOException { + + return createAnimatableFromXml(c, parser, Xml.asAttributeSet(parser), null, 0); + } + + private static Animatable createAnimatableFromXml(Context c, XmlPullParser parser, + AttributeSet attrs, Sequencer parent, int sequenceOrdering) + throws XmlPullParserException, IOException { + + Animatable anim = null; + ArrayList childAnims = null; + + // Make sure we are on a start tag. + int type; + int depth = parser.getDepth(); + + while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) + && type != XmlPullParser.END_DOCUMENT) { + + if (type != XmlPullParser.START_TAG) { + continue; + } + + String name = parser.getName(); + + if (name.equals("property")) { + anim = loadPropertyAnimator(c, attrs); + } else if (name.equals("animator")) { + anim = loadAnimator(c, attrs, null); + } else if (name.equals("sequencer")) { + anim = new Sequencer(); + TypedArray a = c.obtainStyledAttributes(attrs, + com.android.internal.R.styleable.Sequencer); + int ordering = a.getInt(com.android.internal.R.styleable.Sequencer_ordering, + TOGETHER); + createAnimatableFromXml(c, parser, attrs, (Sequencer) anim, ordering); + a.recycle(); + } else { + throw new RuntimeException("Unknown animator name: " + parser.getName()); + } + + if (parent != null) { + if (childAnims == null) { + childAnims = new ArrayList(); + } + childAnims.add(anim); + } + } + if (parent != null && childAnims != null) { + Animatable[] animsArray = new Animatable[childAnims.size()]; + int index = 0; + for (Animatable a : childAnims) { + animsArray[index++] = a; + } + if (sequenceOrdering == TOGETHER) { + parent.playTogether(animsArray); + } else { + parent.playSequentially(animsArray); + } + } + + return anim; + + } + + private static PropertyAnimator loadPropertyAnimator(Context context, AttributeSet attrs) + throws NotFoundException { + + PropertyAnimator anim = new PropertyAnimator(); + + loadAnimator(context, attrs, anim); + + TypedArray a = + context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.PropertyAnimator); + + String propertyName = a.getString(com.android.internal.R.styleable.PropertyAnimator_propertyName); + + anim.setPropertyName(propertyName); + + a.recycle(); + + return anim; + } + + /** + * Creates a new animation whose parameters come from the specified context and + * attributes set. + * + * @param context the application environment + * @param attrs the set of attributes holding the animation parameters + */ + private static Animator loadAnimator(Context context, AttributeSet attrs, Animator anim) + throws NotFoundException { + + TypedArray a = + context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator); + + long duration = a.getInt(com.android.internal.R.styleable.Animator_duration, 0); + + long startDelay = a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0); + + int valueType = a.getInt(com.android.internal.R.styleable.Animator_valueType, + VALUE_TYPE_FLOAT); + + Object valueFrom = null; + Object valueTo = null; + TypeEvaluator evaluator = null; + + switch (valueType) { + case VALUE_TYPE_FLOAT: + if (a.hasValue(com.android.internal.R.styleable.Animator_valueFrom)) { + valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f); + } + if (a.hasValue(com.android.internal.R.styleable.Animator_valueTo)) { + valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f); + } + break; + case VALUE_TYPE_COLOR: + evaluator = new RGBEvaluator(); + // fall through to pick up values + case VALUE_TYPE_INT: + if (a.hasValue(com.android.internal.R.styleable.Animator_valueFrom)) { + valueFrom = a.getInteger(com.android.internal.R.styleable.Animator_valueFrom, 0); + } + if (a.hasValue(com.android.internal.R.styleable.Animator_valueTo)) { + valueTo = a.getInteger(com.android.internal.R.styleable.Animator_valueTo, 0); + } + break; + case VALUE_TYPE_DOUBLE: + if (a.hasValue(com.android.internal.R.styleable.Animator_valueFrom)) { + valueFrom = (Double)((Float)(a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f))).doubleValue(); + } + if (a.hasValue(com.android.internal.R.styleable.Animator_valueTo)) { + valueTo = (Double)((Float)a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f)).doubleValue(); + } + break; + case VALUE_TYPE_CUSTOM: + // TODO: How to get an 'Object' value? + if (a.hasValue(com.android.internal.R.styleable.Animator_valueFrom)) { + valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f); + } + if (a.hasValue(com.android.internal.R.styleable.Animator_valueTo)) { + valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f); + } + break; + } + + if (anim == null) { + anim = new Animator(duration, valueFrom, valueTo); + } else { + anim.setDuration(duration); + anim.setValues(valueFrom, valueTo); + } + + anim.setStartDelay(startDelay); + + if (a.hasValue(com.android.internal.R.styleable.Animator_repeatCount)) { + anim.setRepeatCount( + a.getInt(com.android.internal.R.styleable.Animator_repeatCount, 0)); + } + if (a.hasValue(com.android.internal.R.styleable.Animator_repeatMode)) { + anim.setRepeatMode( + a.getInt(com.android.internal.R.styleable.Animator_repeatMode, + Animator.RESTART)); + } + if (evaluator != null) { + anim.setEvaluator(evaluator); + } + + final int resID = + a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0); + if (resID > 0) { + anim.setInterpolator(AnimationUtils.loadInterpolator(context, resID)); + } + a.recycle(); + + return anim; + } +} diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java index eca5f0d29601a..18017bae0dc32 100755 --- a/core/java/android/animation/Animator.java +++ b/core/java/android/animation/Animator.java @@ -17,11 +17,9 @@ package android.animation; import android.content.Context; -import android.content.res.TypedArray; import android.os.Handler; import android.os.Looper; import android.os.Message; -import android.util.AttributeSet; import android.view.animation.AccelerateDecelerateInterpolator; import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; @@ -69,15 +67,6 @@ public class Animator extends Animatable { private static final int ENDED = 3; // end() called - need to end it private static final int SEEKED = 4; // Seeked to some time value - /** - * Enum values used in XML attributes to indicate the value for mValueType - */ - private static final int VALUE_TYPE_FLOAT = 0; - private static final int VALUE_TYPE_INT = 1; - private static final int VALUE_TYPE_DOUBLE = 2; - private static final int VALUE_TYPE_COLOR = 3; - private static final int VALUE_TYPE_CUSTOM = 4; - /** * Internal variables * NOTE: This object implements the clone() method, making a deep copy of any referenced @@ -208,11 +197,6 @@ public class Animator extends Animatable { */ HashMap mValuesMap; - /** - * The type of the values, as determined by the valueFrom/valueTo properties. - */ - Class mValueType; - /** * Public constants */ @@ -234,76 +218,13 @@ public class Animator extends Animatable { public static final int INFINITE = -1; /** - * Creates a new animation whose parameters come from the specified context and - * attributes set. - * - * @param context the application environment - * @param attrs the set of attributes holding the animation parameters + * Creates a new Animator object. This default constructor is primarily for + * use internally; the other constructors which take parameters are more generally + * useful. */ - public Animator(Context context, AttributeSet attrs) { - TypedArray a = - context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animator); - - mDuration = (long) a.getInt(com.android.internal.R.styleable.Animator_duration, 0); - - mStartDelay = (long) a.getInt(com.android.internal.R.styleable.Animator_startOffset, 0); - - final int resID = - a.getResourceId(com.android.internal.R.styleable.Animator_interpolator, 0); - if (resID > 0) { - setInterpolator(AnimationUtils.loadInterpolator(context, resID)); - } - int valueType = a.getInt(com.android.internal.R.styleable.Animator_valueType, - VALUE_TYPE_FLOAT); - - Object valueFrom = null; - Object valueTo = null; - - switch (valueType) { - case VALUE_TYPE_FLOAT: - valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f); - valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f); - mValueType = float.class; - break; - case VALUE_TYPE_INT: - valueFrom = a.getInt(com.android.internal.R.styleable.Animator_valueFrom, 0); - valueTo = a.getInt(com.android.internal.R.styleable.Animator_valueTo, 0); - mValueType = int.class; - break; - case VALUE_TYPE_DOUBLE: - valueFrom = (double) - a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f); - valueTo = (double) - a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f); - mValueType = double.class; - break; - case VALUE_TYPE_COLOR: - valueFrom = a.getInt(com.android.internal.R.styleable.Animator_valueFrom, 0); - valueTo = a.getInt(com.android.internal.R.styleable.Animator_valueTo, 0); - setEvaluator(new RGBEvaluator()); - mValueType = int.class; - break; - case VALUE_TYPE_CUSTOM: - // TODO: How to get an 'Object' value? - valueFrom = a.getFloat(com.android.internal.R.styleable.Animator_valueFrom, 0f); - valueTo = a.getFloat(com.android.internal.R.styleable.Animator_valueTo, 0f); - mValueType = Object.class; - break; - } - - PropertyValuesHolder valuesHolder = new PropertyValuesHolder("", valueFrom, valueTo); - mValues = new PropertyValuesHolder[1]; - mValues[0] = valuesHolder; - mValuesMap = new HashMap(1); - mValuesMap.put("", valuesHolder); - - mRepeatCount = a.getInt(com.android.internal.R.styleable.Animator_repeatCount, mRepeatCount); - mRepeatMode = a.getInt(com.android.internal.R.styleable.Animator_repeatMode, RESTART); - - a.recycle(); + public Animator() { } - /** * Constructs an Animator object with the specified duration and set of * values. If the values are a set of PropertyValuesHolder objects, then these objects @@ -373,6 +294,25 @@ public class Animator extends Animatable { mInitialized = true; } + + /** + * Sets the length of the animation. + * + * @param duration The length of the animation, in milliseconds. + */ + public void setDuration(long duration) { + mDuration = duration; + } + + /** + * Gets the length of the animation. + * + * @return The length of the animation, in milliseconds. + */ + public long getDuration() { + return mDuration; + } + /** * Sets the position of the animation to the specified point in time. This time should * be between 0 and the total duration of the animation, including any repetition. If @@ -723,11 +663,11 @@ public class Animator extends Animatable { * @param playBackwards Whether the Animator should start playing in reverse. */ private void start(boolean playBackwards) { + mPlayingBackwards = playBackwards; if ((mStartDelay == 0) && (Thread.currentThread() == Looper.getMainLooper().getThread())) { // This sets the initial value of the animation, prior to actually starting it running setCurrentPlayTime(getCurrentPlayTime()); } - mPlayingBackwards = playBackwards; mPlayingState = STOPPED; sPendingAnimations.add(this); if (sAnimationHandler == null) { @@ -738,15 +678,6 @@ public class Animator extends Animatable { sAnimationHandler.sendEmptyMessage(ANIMATION_START); } - /** - * Returns the duration that this animation will run for. - * - * @return The length in time of the animation, in milliseconds. - */ - public long getDuration() { - return mDuration; - } - @Override public void start() { start(false); diff --git a/core/java/android/animation/PropertyAnimator.java b/core/java/android/animation/PropertyAnimator.java index 022ca7ddc999c..8a6edcc72f3e0 100644 --- a/core/java/android/animation/PropertyAnimator.java +++ b/core/java/android/animation/PropertyAnimator.java @@ -16,9 +16,6 @@ package android.animation; -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; import android.util.Log; import java.lang.reflect.Method; @@ -80,25 +77,6 @@ public final class PropertyAnimator extends Animator { return mPropertyName; } - /** - * Creates a new animation whose parameters come from the specified context and - * attributes set. - * - * @param context the application environment - * @param attrs the set of attributes holding the animation parameters - */ - public PropertyAnimator(Context context, AttributeSet attrs) { - super(context, attrs); - - TypedArray a = context.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.PropertyAnimator); - - setPropertyName(a.getString( - com.android.internal.R.styleable.PropertyAnimator_propertyName)); - - - a.recycle(); - } /** * Determine the setter or getter function using the JavaBeans convention of setFoo or * getFoo for a property named 'foo'. This function figures out what the name of the @@ -129,6 +107,14 @@ public final class PropertyAnimator extends Animator { return returnVal; } + /** + * Creates a new PropertyAnimator object. This default constructor is primarily for + * use internally; the other constructors which take parameters are more generally + * useful. + */ + public PropertyAnimator() { + } + /** * A constructor that takes a single property name and set of values. This constructor is * used in the simple case of animating a single property. diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java index f190d0d3dd9b7..c63233e4b6493 100644 --- a/core/java/android/app/FragmentManager.java +++ b/core/java/android/app/FragmentManager.java @@ -17,6 +17,7 @@ package android.app; import android.animation.Animatable; +import android.animation.AnimatableInflater; import android.animation.PropertyAnimator; import android.animation.Sequencer; import android.content.res.TypedArray; @@ -31,7 +32,6 @@ import android.view.MenuInflater; import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; -import android.view.animation.AnimationUtils; import java.util.ArrayList; @@ -257,7 +257,7 @@ final class FragmentManagerImpl implements FragmentManager { } if (fragment.mNextAnim != 0) { - Animatable anim = AnimationUtils.loadAnimator(mActivity, fragment.mNextAnim); + Animatable anim = AnimatableInflater.loadAnimatable(mActivity, fragment.mNextAnim); if (anim != null) { return anim; } @@ -288,7 +288,7 @@ final class FragmentManagerImpl implements FragmentManager { return null; } - return AnimationUtils.loadAnimator(mActivity, anim); + return AnimatableInflater.loadAnimatable(mActivity, anim); } void moveToState(Fragment f, int newState, int transit, int transitionStyle) { diff --git a/core/java/android/view/animation/AnimationUtils.java b/core/java/android/view/animation/AnimationUtils.java index 8e4cf67d1fea5..c090f8e5f083a 100644 --- a/core/java/android/view/animation/AnimationUtils.java +++ b/core/java/android/view/animation/AnimationUtils.java @@ -16,12 +16,6 @@ package android.view.animation; -import android.animation.Animatable; -import android.animation.Animator; -import android.animation.PropertyAnimator; -import android.animation.Sequencer; -import android.content.res.TypedArray; -import android.util.TypedValue; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -33,7 +27,6 @@ import android.util.Xml; import android.os.SystemClock; import java.io.IOException; -import java.util.ArrayList; /** * Defines common utilities for working with animations. @@ -92,42 +85,6 @@ public class AnimationUtils { } } - /** - * Loads an {@link Animation} object from a resource - * - * @param context Application context used to access resources - * @param id The resource id of the animation to load - * @return The animation object reference by the specified id - * @throws NotFoundException when the animation cannot be loaded - */ - public static Animatable loadAnimator(Context context, int id) - throws NotFoundException { - - XmlResourceParser parser = null; - try { - parser = context.getResources().getAnimation(id); - return createAnimatableFromXml(context, parser); - } catch (XmlPullParserException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } catch (IOException ex) { - NotFoundException rnf = new NotFoundException("Can't load animation resource ID #0x" + - Integer.toHexString(id)); - rnf.initCause(ex); - throw rnf; - } finally { - if (parser != null) parser.close(); - } - } - - private static Animatable createAnimatableFromXml(Context c, XmlPullParser parser) - throws XmlPullParserException, IOException { - - return createAnimatableFromXml(c, parser, Xml.asAttributeSet(parser), null, 0); - } - private static Animation createAnimationFromXml(Context c, XmlPullParser parser) throws XmlPullParserException, IOException { @@ -176,66 +133,6 @@ public class AnimationUtils { } - private static Animatable createAnimatableFromXml(Context c, XmlPullParser parser, - AttributeSet attrs, Sequencer parent, int sequenceOrdering) - throws XmlPullParserException, IOException { - - Animatable anim = null; - ArrayList childAnims = null; - - // Make sure we are on a start tag. - int type; - int depth = parser.getDepth(); - - while (((type=parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) - && type != XmlPullParser.END_DOCUMENT) { - - if (type != XmlPullParser.START_TAG) { - continue; - } - - String name = parser.getName(); - - if (name.equals("property")) { - anim = new PropertyAnimator(c, attrs); - } else if (name.equals("animator")) { - anim = new Animator(c, attrs); - } else if (name.equals("sequencer")) { - anim = new Sequencer(); - TypedArray a = c.obtainStyledAttributes(attrs, - com.android.internal.R.styleable.Sequencer); - int ordering = a.getInt(com.android.internal.R.styleable.Sequencer_ordering, - TOGETHER); - createAnimatableFromXml(c, parser, attrs, (Sequencer) anim, ordering); - a.recycle(); - } else { - throw new RuntimeException("Unknown animator name: " + parser.getName()); - } - - if (parent != null) { - if (childAnims == null) { - childAnims = new ArrayList(); - } - childAnims.add(anim); - } - } - if (parent != null && childAnims != null) { - Animatable[] animsArray = new Animatable[childAnims.size()]; - int index = 0; - for (Animatable a : childAnims) { - animsArray[index++] = a; - } - if (sequenceOrdering == TOGETHER) { - parent.playTogether(animsArray); - } else { - parent.playSequentially(animsArray); - } - } - - return anim; - - } - public static LayoutAnimationController loadLayoutAnimation(Context context, int id) throws NotFoundException {