Automatic sources dropoff on 2020-06-10 18:32:38.095721

The change is generated with prebuilt drop tool.

Change-Id: I24cbf6ba6db262a1ae1445db1427a08fee35b3b4
diff --git a/android/view/animation/AccelerateDecelerateInterpolator.java b/android/view/animation/AccelerateDecelerateInterpolator.java
new file mode 100644
index 0000000..a2bbc5c
--- /dev/null
+++ b/android/view/animation/AccelerateDecelerateInterpolator.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 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 android.view.animation;
+
+import android.content.Context;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+/**
+ * An interpolator where the rate of change starts and ends slowly but
+ * accelerates through the middle.
+ */
+@HasNativeInterpolator
+public class AccelerateDecelerateInterpolator extends BaseInterpolator
+        implements NativeInterpolator {
+    public AccelerateDecelerateInterpolator() {
+    }
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
+    }
+
+    public float getInterpolation(float input) {
+        return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
+    }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createAccelerateDecelerateInterpolator();
+    }
+}
diff --git a/android/view/animation/AccelerateInterpolator.java b/android/view/animation/AccelerateInterpolator.java
new file mode 100644
index 0000000..9d4cd32
--- /dev/null
+++ b/android/view/animation/AccelerateInterpolator.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+/**
+ * An interpolator where the rate of change starts out slowly and
+ * and then accelerates.
+ *
+ */
+@HasNativeInterpolator
+public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolator {
+    private final float mFactor;
+    private final double mDoubleFactor;
+
+    public AccelerateInterpolator() {
+        mFactor = 1.0f;
+        mDoubleFactor = 2.0;
+    }
+
+    /**
+     * Constructor
+     *
+     * @param factor Degree to which the animation should be eased. Seting
+     *        factor to 1.0f produces a y=x^2 parabola. Increasing factor above
+     *        1.0f  exaggerates the ease-in effect (i.e., it starts even
+     *        slower and ends evens faster)
+     */
+    public AccelerateInterpolator(float factor) {
+        mFactor = factor;
+        mDoubleFactor = 2 * mFactor;
+    }
+
+    public AccelerateInterpolator(Context context, AttributeSet attrs) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public AccelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.AccelerateInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.AccelerateInterpolator);
+        }
+
+        mFactor = a.getFloat(R.styleable.AccelerateInterpolator_factor, 1.0f);
+        mDoubleFactor = 2 * mFactor;
+        setChangingConfiguration(a.getChangingConfigurations());
+        a.recycle();
+    }
+
+    public float getInterpolation(float input) {
+        if (mFactor == 1.0f) {
+            return input * input;
+        } else {
+            return (float)Math.pow(input, mDoubleFactor);
+        }
+    }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createAccelerateInterpolator(mFactor);
+    }
+}
diff --git a/android/view/animation/AlphaAnimation.java b/android/view/animation/AlphaAnimation.java
new file mode 100644
index 0000000..c4d9afc
--- /dev/null
+++ b/android/view/animation/AlphaAnimation.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+/**
+ * An animation that controls the alpha level of an object.
+ * Useful for fading things in and out. This animation ends up
+ * changing the alpha property of a {@link Transformation}
+ *
+ */
+public class AlphaAnimation extends Animation {
+    private float mFromAlpha;
+    private float mToAlpha;
+
+    /**
+     * Constructor used when an AlphaAnimation is loaded from a resource. 
+     * 
+     * @param context Application context to use
+     * @param attrs Attribute set from which to read values
+     */
+    public AlphaAnimation(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        
+        TypedArray a =
+            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AlphaAnimation);
+        
+        mFromAlpha = a.getFloat(com.android.internal.R.styleable.AlphaAnimation_fromAlpha, 1.0f);
+        mToAlpha = a.getFloat(com.android.internal.R.styleable.AlphaAnimation_toAlpha, 1.0f);
+        
+        a.recycle();
+    }
+    
+    /**
+     * Constructor to use when building an AlphaAnimation from code
+     * 
+     * @param fromAlpha Starting alpha value for the animation, where 1.0 means
+     *        fully opaque and 0.0 means fully transparent.
+     * @param toAlpha Ending alpha value for the animation.
+     */
+    public AlphaAnimation(float fromAlpha, float toAlpha) {
+        mFromAlpha = fromAlpha;
+        mToAlpha = toAlpha;
+    }
+    
+    /**
+     * Changes the alpha property of the supplied {@link Transformation}
+     */
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        final float alpha = mFromAlpha;
+        t.setAlpha(alpha + ((mToAlpha - alpha) * interpolatedTime));
+    }
+
+    @Override
+    public boolean willChangeTransformationMatrix() {
+        return false;
+    }
+
+    @Override
+    public boolean willChangeBounds() {
+        return false;
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean hasAlpha() {
+        return true;
+    }
+}
diff --git a/android/view/animation/Animation.java b/android/view/animation/Animation.java
new file mode 100644
index 0000000..b1d618e
--- /dev/null
+++ b/android/view/animation/Animation.java
@@ -0,0 +1,1256 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.annotation.AnimRes;
+import android.annotation.ColorInt;
+import android.annotation.InterpolatorRes;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.RectF;
+import android.os.Build;
+import android.os.Handler;
+import android.os.SystemProperties;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+
+import dalvik.system.CloseGuard;
+
+/**
+ * Abstraction for an Animation that can be applied to Views, Surfaces, or
+ * other objects. See the {@link android.view.animation animation package
+ * description file}.
+ */
+public abstract class Animation implements Cloneable {
+    /**
+     * Repeat the animation indefinitely.
+     */
+    public static final int INFINITE = -1;
+
+    /**
+     * When the animation reaches the end and the repeat count is INFINTE_REPEAT
+     * or a positive value, the animation restarts from the beginning.
+     */
+    public static final int RESTART = 1;
+
+    /**
+     * When the animation reaches the end and the repeat count is INFINTE_REPEAT
+     * or a positive value, the animation plays backward (and then forward again).
+     */
+    public static final int REVERSE = 2;
+
+    /**
+     * Can be used as the start time to indicate the start time should be the current
+     * time when {@link #getTransformation(long, Transformation)} is invoked for the
+     * first animation frame. This can is useful for short animations.
+     */
+    public static final int START_ON_FIRST_FRAME = -1;
+
+    /**
+     * The specified dimension is an absolute number of pixels.
+     */
+    public static final int ABSOLUTE = 0;
+
+    /**
+     * The specified dimension holds a float and should be multiplied by the
+     * height or width of the object being animated.
+     */
+    public static final int RELATIVE_TO_SELF = 1;
+
+    /**
+     * The specified dimension holds a float and should be multiplied by the
+     * height or width of the parent of the object being animated.
+     */
+    public static final int RELATIVE_TO_PARENT = 2;
+
+    /**
+     * Requests that the content being animated be kept in its current Z
+     * order.
+     */
+    public static final int ZORDER_NORMAL = 0;
+
+    /**
+     * Requests that the content being animated be forced on top of all other
+     * content for the duration of the animation.
+     */
+    public static final int ZORDER_TOP = 1;
+
+    /**
+     * Requests that the content being animated be forced under all other
+     * content for the duration of the animation.
+     */
+    public static final int ZORDER_BOTTOM = -1;
+
+    // Use a preload holder to isolate static initialization into inner class, which allows
+    // Animation and its subclasses to be compile-time initialized.
+    private static class NoImagePreloadHolder {
+        public static final boolean USE_CLOSEGUARD
+                = SystemProperties.getBoolean("log.closeguard.Animation", false);
+    }
+
+    /**
+     * Set by {@link #getTransformation(long, Transformation)} when the animation ends.
+     */
+    boolean mEnded = false;
+
+    /**
+     * Set by {@link #getTransformation(long, Transformation)} when the animation starts.
+     */
+    boolean mStarted = false;
+
+    /**
+     * Set by {@link #getTransformation(long, Transformation)} when the animation repeats
+     * in REVERSE mode.
+     */
+    boolean mCycleFlip = false;
+
+    /**
+     * This value must be set to true by {@link #initialize(int, int, int, int)}. It
+     * indicates the animation was successfully initialized and can be played.
+     */
+    boolean mInitialized = false;
+
+    /**
+     * Indicates whether the animation transformation should be applied before the
+     * animation starts. The value of this variable is only relevant if mFillEnabled is true;
+     * otherwise it is assumed to be true.
+     */
+    boolean mFillBefore = true;
+
+    /**
+     * Indicates whether the animation transformation should be applied after the
+     * animation ends.
+     */
+    boolean mFillAfter = false;
+
+    /**
+     * Indicates whether fillBefore should be taken into account.
+     */
+    boolean mFillEnabled = false;
+
+    /**
+     * The time in milliseconds at which the animation must start;
+     */
+    long mStartTime = -1;
+
+    /**
+     * The delay in milliseconds after which the animation must start. When the
+     * start offset is > 0, the start time of the animation is startTime + startOffset.
+     */
+    long mStartOffset;
+
+    /**
+     * The duration of one animation cycle in milliseconds.
+     */
+    long mDuration;
+
+    /**
+     * The number of times the animation must repeat. By default, an animation repeats
+     * indefinitely.
+     */
+    int mRepeatCount = 0;
+
+    /**
+     * Indicates how many times the animation was repeated.
+     */
+    int mRepeated = 0;
+
+    /**
+     * The behavior of the animation when it repeats. The repeat mode is either
+     * {@link #RESTART} or {@link #REVERSE}.
+     *
+     */
+    int mRepeatMode = RESTART;
+
+    /**
+     * The interpolator used by the animation to smooth the movement.
+     */
+    Interpolator mInterpolator;
+
+    /**
+     * An animation listener to be notified when the animation starts, ends or repeats.
+     */
+    // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet
+    // and add your new listener to that set
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981)
+    private AnimationListener mListener;
+
+    /**
+     * Desired Z order mode during animation.
+     */
+    private int mZAdjustment;
+
+    /**
+     * Desired background color behind animation.
+     */
+    private int mBackgroundColor;
+
+    /**
+     * scalefactor to apply to pivot points, etc. during animation. Subclasses retrieve the
+     * value via getScaleFactor().
+     */
+    private float mScaleFactor = 1f;
+
+    private boolean mShowWallpaper;
+    private boolean mHasRoundedCorners;
+
+    private boolean mMore = true;
+    private boolean mOneMoreTime = true;
+
+    @UnsupportedAppUsage
+    RectF mPreviousRegion = new RectF();
+    @UnsupportedAppUsage
+    RectF mRegion = new RectF();
+    @UnsupportedAppUsage
+    Transformation mTransformation = new Transformation();
+    @UnsupportedAppUsage
+    Transformation mPreviousTransformation = new Transformation();
+
+    private final CloseGuard guard = CloseGuard.get();
+
+    private Handler mListenerHandler;
+    private Runnable mOnStart;
+    private Runnable mOnRepeat;
+    private Runnable mOnEnd;
+
+    /**
+     * Creates a new animation with a duration of 0ms, the default interpolator, with
+     * fillBefore set to true and fillAfter set to false
+     */
+    public Animation() {
+        ensureInterpolator();
+    }
+
+    /**
+     * 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 Animation(Context context, AttributeSet attrs) {
+        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.Animation);
+
+        setDuration((long) a.getInt(com.android.internal.R.styleable.Animation_duration, 0));
+        setStartOffset((long) a.getInt(com.android.internal.R.styleable.Animation_startOffset, 0));
+
+        setFillEnabled(a.getBoolean(com.android.internal.R.styleable.Animation_fillEnabled, mFillEnabled));
+        setFillBefore(a.getBoolean(com.android.internal.R.styleable.Animation_fillBefore, mFillBefore));
+        setFillAfter(a.getBoolean(com.android.internal.R.styleable.Animation_fillAfter, mFillAfter));
+
+        setRepeatCount(a.getInt(com.android.internal.R.styleable.Animation_repeatCount, mRepeatCount));
+        setRepeatMode(a.getInt(com.android.internal.R.styleable.Animation_repeatMode, RESTART));
+
+        setZAdjustment(a.getInt(com.android.internal.R.styleable.Animation_zAdjustment, ZORDER_NORMAL));
+
+        setBackgroundColor(a.getInt(com.android.internal.R.styleable.Animation_background, 0));
+
+        setDetachWallpaper(
+                a.getBoolean(com.android.internal.R.styleable.Animation_detachWallpaper, false));
+        setShowWallpaper(
+                a.getBoolean(com.android.internal.R.styleable.Animation_showWallpaper, false));
+        setHasRoundedCorners(
+                a.getBoolean(com.android.internal.R.styleable.Animation_hasRoundedCorners, false));
+
+        final int resID = a.getResourceId(com.android.internal.R.styleable.Animation_interpolator, 0);
+
+        a.recycle();
+
+        if (resID > 0) {
+            setInterpolator(context, resID);
+        }
+
+        ensureInterpolator();
+    }
+
+    @Override
+    protected Animation clone() throws CloneNotSupportedException {
+        final Animation animation = (Animation) super.clone();
+        animation.mPreviousRegion = new RectF();
+        animation.mRegion = new RectF();
+        animation.mTransformation = new Transformation();
+        animation.mPreviousTransformation = new Transformation();
+        return animation;
+    }
+
+    /**
+     * Reset the initialization state of this animation.
+     *
+     * @see #initialize(int, int, int, int)
+     */
+    public void reset() {
+        mPreviousRegion.setEmpty();
+        mPreviousTransformation.clear();
+        mInitialized = false;
+        mCycleFlip = false;
+        mRepeated = 0;
+        mMore = true;
+        mOneMoreTime = true;
+        mListenerHandler = null;
+    }
+
+    /**
+     * Cancel the animation. Cancelling an animation invokes the animation
+     * listener, if set, to notify the end of the animation.
+     *
+     * If you cancel an animation manually, you must call {@link #reset()}
+     * before starting the animation again.
+     *
+     * @see #reset()
+     * @see #start()
+     * @see #startNow()
+     */
+    public void cancel() {
+        if (mStarted && !mEnded) {
+            fireAnimationEnd();
+            mEnded = true;
+            guard.close();
+        }
+        // Make sure we move the animation to the end
+        mStartTime = Long.MIN_VALUE;
+        mMore = mOneMoreTime = false;
+    }
+
+    /**
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public void detach() {
+        if (mStarted && !mEnded) {
+            mEnded = true;
+            guard.close();
+            fireAnimationEnd();
+        }
+    }
+
+    /**
+     * Whether or not the animation has been initialized.
+     *
+     * @return Has this animation been initialized.
+     * @see #initialize(int, int, int, int)
+     */
+    public boolean isInitialized() {
+        return mInitialized;
+    }
+
+    /**
+     * Initialize this animation with the dimensions of the object being
+     * animated as well as the objects parents. (This is to support animation
+     * sizes being specified relative to these dimensions.)
+     *
+     * <p>Objects that interpret Animations should call this method when
+     * the sizes of the object being animated and its parent are known, and
+     * before calling {@link #getTransformation}.
+     *
+     *
+     * @param width Width of the object being animated
+     * @param height Height of the object being animated
+     * @param parentWidth Width of the animated object's parent
+     * @param parentHeight Height of the animated object's parent
+     */
+    public void initialize(int width, int height, int parentWidth, int parentHeight) {
+        reset();
+        mInitialized = true;
+    }
+
+    /**
+     * Sets the handler used to invoke listeners.
+     *
+     * @hide
+     */
+    public void setListenerHandler(Handler handler) {
+        if (mListenerHandler == null) {
+            mOnStart = new Runnable() {
+                public void run() {
+                    dispatchAnimationStart();
+                }
+            };
+            mOnRepeat = new Runnable() {
+                public void run() {
+                    dispatchAnimationRepeat();
+                }
+            };
+            mOnEnd = new Runnable() {
+                public void run() {
+                    dispatchAnimationEnd();
+                }
+            };
+        }
+        mListenerHandler = handler;
+    }
+
+    /**
+     * Sets the acceleration curve for this animation. The interpolator is loaded as
+     * a resource from the specified context.
+     *
+     * @param context The application environment
+     * @param resID The resource identifier of the interpolator to load
+     * @attr ref android.R.styleable#Animation_interpolator
+     */
+    public void setInterpolator(Context context, @AnimRes @InterpolatorRes int resID) {
+        setInterpolator(AnimationUtils.loadInterpolator(context, resID));
+    }
+
+    /**
+     * Sets the acceleration curve for this animation. Defaults to a linear
+     * interpolation.
+     *
+     * @param i The interpolator which defines the acceleration curve
+     * @attr ref android.R.styleable#Animation_interpolator
+     */
+    public void setInterpolator(Interpolator i) {
+        mInterpolator = i;
+    }
+
+    /**
+     * When this animation should start relative to the start time. This is most
+     * useful when composing complex animations using an {@link AnimationSet }
+     * where some of the animations components start at different times.
+     *
+     * @param startOffset When this Animation should start, in milliseconds from
+     *                    the start time of the root AnimationSet.
+     * @attr ref android.R.styleable#Animation_startOffset
+     */
+    public void setStartOffset(long startOffset) {
+        mStartOffset = startOffset;
+    }
+
+    /**
+     * How long this animation should last. The duration cannot be negative.
+     *
+     * @param durationMillis Duration in milliseconds
+     *
+     * @throws java.lang.IllegalArgumentException if the duration is < 0
+     *
+     * @attr ref android.R.styleable#Animation_duration
+     */
+    public void setDuration(long durationMillis) {
+        if (durationMillis < 0) {
+            throw new IllegalArgumentException("Animation duration cannot be negative");
+        }
+        mDuration = durationMillis;
+    }
+
+    /**
+     * Ensure that the duration that this animation will run is not longer
+     * than <var>durationMillis</var>.  In addition to adjusting the duration
+     * itself, this ensures that the repeat count also will not make it run
+     * longer than the given time.
+     *
+     * @param durationMillis The maximum duration the animation is allowed
+     * to run.
+     */
+    public void restrictDuration(long durationMillis) {
+        // If we start after the duration, then we just won't run.
+        if (mStartOffset > durationMillis) {
+            mStartOffset = durationMillis;
+            mDuration = 0;
+            mRepeatCount = 0;
+            return;
+        }
+
+        long dur = mDuration + mStartOffset;
+        if (dur > durationMillis) {
+            mDuration = durationMillis-mStartOffset;
+            dur = durationMillis;
+        }
+        // If the duration is 0 or less, then we won't run.
+        if (mDuration <= 0) {
+            mDuration = 0;
+            mRepeatCount = 0;
+            return;
+        }
+        // Reduce the number of repeats to keep below the maximum duration.
+        // The comparison between mRepeatCount and duration is to catch
+        // overflows after multiplying them.
+        if (mRepeatCount < 0 || mRepeatCount > durationMillis
+                || (dur*mRepeatCount) > durationMillis) {
+            // Figure out how many times to do the animation.  Subtract 1 since
+            // repeat count is the number of times to repeat so 0 runs once.
+            mRepeatCount = (int)(durationMillis/dur) - 1;
+            if (mRepeatCount < 0) {
+                mRepeatCount = 0;
+            }
+        }
+    }
+
+    /**
+     * How much to scale the duration by.
+     *
+     * @param scale The amount to scale the duration.
+     */
+    public void scaleCurrentDuration(float scale) {
+        mDuration = (long) (mDuration * scale);
+        mStartOffset = (long) (mStartOffset * scale);
+    }
+
+    /**
+     * When this animation should start. When the start time is set to
+     * {@link #START_ON_FIRST_FRAME}, the animation will start the first time
+     * {@link #getTransformation(long, Transformation)} is invoked. The time passed
+     * to this method should be obtained by calling
+     * {@link AnimationUtils#currentAnimationTimeMillis()} instead of
+     * {@link System#currentTimeMillis()}.
+     *
+     * @param startTimeMillis the start time in milliseconds
+     */
+    public void setStartTime(long startTimeMillis) {
+        mStartTime = startTimeMillis;
+        mStarted = mEnded = false;
+        mCycleFlip = false;
+        mRepeated = 0;
+        mMore = true;
+    }
+
+    /**
+     * Convenience method to start the animation the first time
+     * {@link #getTransformation(long, Transformation)} is invoked.
+     */
+    public void start() {
+        setStartTime(-1);
+    }
+
+    /**
+     * Convenience method to start the animation at the current time in
+     * milliseconds.
+     */
+    public void startNow() {
+        setStartTime(AnimationUtils.currentAnimationTimeMillis());
+    }
+
+    /**
+     * Defines what this animation should do when it reaches the end. This
+     * setting is applied only when the repeat count is either greater than
+     * 0 or {@link #INFINITE}. Defaults to {@link #RESTART}.
+     *
+     * @param repeatMode {@link #RESTART} or {@link #REVERSE}
+     * @attr ref android.R.styleable#Animation_repeatMode
+     */
+    public void setRepeatMode(int repeatMode) {
+        mRepeatMode = repeatMode;
+    }
+
+    /**
+     * Sets how many times the animation should be repeated. If the repeat
+     * count is 0, the animation is never repeated. If the repeat count is
+     * greater than 0 or {@link #INFINITE}, the repeat mode will be taken
+     * into account. The repeat count is 0 by default.
+     *
+     * @param repeatCount the number of times the animation should be repeated
+     * @attr ref android.R.styleable#Animation_repeatCount
+     */
+    public void setRepeatCount(int repeatCount) {
+        if (repeatCount < 0) {
+            repeatCount = INFINITE;
+        }
+        mRepeatCount = repeatCount;
+    }
+
+    /**
+     * If fillEnabled is true, this animation will apply the value of fillBefore.
+     *
+     * @return true if the animation will take fillBefore into account
+     * @attr ref android.R.styleable#Animation_fillEnabled
+     */
+    public boolean isFillEnabled() {
+        return mFillEnabled;
+    }
+
+    /**
+     * If fillEnabled is true, the animation will apply the value of fillBefore.
+     * Otherwise, fillBefore is ignored and the animation
+     * transformation is always applied until the animation ends.
+     *
+     * @param fillEnabled true if the animation should take the value of fillBefore into account
+     * @attr ref android.R.styleable#Animation_fillEnabled
+     *
+     * @see #setFillBefore(boolean)
+     * @see #setFillAfter(boolean)
+     */
+    public void setFillEnabled(boolean fillEnabled) {
+        mFillEnabled = fillEnabled;
+    }
+
+    /**
+     * If fillBefore is true, this animation will apply its transformation
+     * before the start time of the animation. Defaults to true if
+     * {@link #setFillEnabled(boolean)} is not set to true.
+     * Note that this applies when using an {@link
+     * android.view.animation.AnimationSet AnimationSet} to chain
+     * animations. The transformation is not applied before the AnimationSet
+     * itself starts.
+     *
+     * @param fillBefore true if the animation should apply its transformation before it starts
+     * @attr ref android.R.styleable#Animation_fillBefore
+     *
+     * @see #setFillEnabled(boolean)
+     */
+    public void setFillBefore(boolean fillBefore) {
+        mFillBefore = fillBefore;
+    }
+
+    /**
+     * If fillAfter is true, the transformation that this animation performed
+     * will persist when it is finished. Defaults to false if not set.
+     * Note that this applies to individual animations and when using an {@link
+     * android.view.animation.AnimationSet AnimationSet} to chain
+     * animations.
+     *
+     * @param fillAfter true if the animation should apply its transformation after it ends
+     * @attr ref android.R.styleable#Animation_fillAfter
+     *
+     * @see #setFillEnabled(boolean)
+     */
+    public void setFillAfter(boolean fillAfter) {
+        mFillAfter = fillAfter;
+    }
+
+    /**
+     * Set the Z ordering mode to use while running the animation.
+     *
+     * @param zAdjustment The desired mode, one of {@link #ZORDER_NORMAL},
+     * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}.
+     * @attr ref android.R.styleable#Animation_zAdjustment
+     */
+    public void setZAdjustment(int zAdjustment) {
+        mZAdjustment = zAdjustment;
+    }
+
+    /**
+     * Set background behind animation.
+     *
+     * @param bg The background color.  If 0, no background.  Currently must
+     * be black, with any desired alpha level.
+     *
+     * @deprecated None of window animations are running with background color.
+     */
+    @Deprecated
+    public void setBackgroundColor(@ColorInt int bg) {
+        // The background color is not needed any more, do nothing.
+    }
+
+    /**
+     * The scale factor is set by the call to <code>getTransformation</code>. Overrides of
+     * {@link #getTransformation(long, Transformation, float)} will get this value
+     * directly. Overrides of {@link #applyTransformation(float, Transformation)} can
+     * call this method to get the value.
+     *
+     * @return float The scale factor that should be applied to pre-scaled values in
+     * an Animation such as the pivot points in {@link ScaleAnimation} and {@link RotateAnimation}.
+     */
+    protected float getScaleFactor() {
+        return mScaleFactor;
+    }
+
+    /**
+     * If detachWallpaper is true, and this is a window animation of a window
+     * that has a wallpaper background, then the window will be detached from
+     * the wallpaper while it runs.  That is, the animation will only be applied
+     * to the window, and the wallpaper behind it will remain static.
+     *
+     * @param detachWallpaper true if the wallpaper should be detached from the animation
+     * @attr ref android.R.styleable#Animation_detachWallpaper
+     *
+     * @deprecated All window animations are running with detached wallpaper.
+     */
+    @Deprecated
+    public void setDetachWallpaper(boolean detachWallpaper) {
+    }
+
+    /**
+     * If this animation is run as a window animation, this will make the wallpaper visible behind
+     * the animation.
+     *
+     * @param showWallpaper Whether the wallpaper should be shown during the animation.
+     * @attr ref android.R.styleable#Animation_detachWallpaper
+     * @hide
+     */
+    public void setShowWallpaper(boolean showWallpaper) {
+        mShowWallpaper = showWallpaper;
+    }
+
+    /**
+     * If this is a window animation, the window will have rounded corners matching the display
+     * corner radius.
+     *
+     * @param hasRoundedCorners Whether the window should have rounded corners or not.
+     * @attr ref android.R.styleable#Animation_hasRoundedCorners
+     * @see com.android.internal.policy.ScreenDecorationsUtils#getWindowCornerRadius(Resources)
+     * @hide
+     */
+    public void setHasRoundedCorners(boolean hasRoundedCorners) {
+        mHasRoundedCorners = hasRoundedCorners;
+    }
+
+    /**
+     * Gets the acceleration curve type for this animation.
+     *
+     * @return the {@link Interpolator} associated to this animation
+     * @attr ref android.R.styleable#Animation_interpolator
+     */
+    public Interpolator getInterpolator() {
+        return mInterpolator;
+    }
+
+    /**
+     * When this animation should start. If the animation has not startet yet,
+     * this method might return {@link #START_ON_FIRST_FRAME}.
+     *
+     * @return the time in milliseconds when the animation should start or
+     *         {@link #START_ON_FIRST_FRAME}
+     */
+    public long getStartTime() {
+        return mStartTime;
+    }
+
+    /**
+     * How long this animation should last
+     *
+     * @return the duration in milliseconds of the animation
+     * @attr ref android.R.styleable#Animation_duration
+     */
+    public long getDuration() {
+        return mDuration;
+    }
+
+    /**
+     * When this animation should start, relative to StartTime
+     *
+     * @return the start offset in milliseconds
+     * @attr ref android.R.styleable#Animation_startOffset
+     */
+    public long getStartOffset() {
+        return mStartOffset;
+    }
+
+    /**
+     * Defines what this animation should do when it reaches the end.
+     *
+     * @return either one of {@link #REVERSE} or {@link #RESTART}
+     * @attr ref android.R.styleable#Animation_repeatMode
+     */
+    public int getRepeatMode() {
+        return mRepeatMode;
+    }
+
+    /**
+     * Defines how many times the animation should repeat. The default value
+     * is 0.
+     *
+     * @return the number of times the animation should repeat, or {@link #INFINITE}
+     * @attr ref android.R.styleable#Animation_repeatCount
+     */
+    public int getRepeatCount() {
+        return mRepeatCount;
+    }
+
+    /**
+     * If fillBefore is true, this animation will apply its transformation
+     * before the start time of the animation. If fillBefore is false and
+     * {@link #isFillEnabled() fillEnabled} is true, the transformation will not be applied until
+     * the start time of the animation.
+     *
+     * @return true if the animation applies its transformation before it starts
+     * @attr ref android.R.styleable#Animation_fillBefore
+     */
+    public boolean getFillBefore() {
+        return mFillBefore;
+    }
+
+    /**
+     * If fillAfter is true, this animation will apply its transformation
+     * after the end time of the animation.
+     *
+     * @return true if the animation applies its transformation after it ends
+     * @attr ref android.R.styleable#Animation_fillAfter
+     */
+    public boolean getFillAfter() {
+        return mFillAfter;
+    }
+
+    /**
+     * Returns the Z ordering mode to use while running the animation as
+     * previously set by {@link #setZAdjustment}.
+     *
+     * @return Returns one of {@link #ZORDER_NORMAL},
+     * {@link #ZORDER_TOP}, or {@link #ZORDER_BOTTOM}.
+     * @attr ref android.R.styleable#Animation_zAdjustment
+     */
+    public int getZAdjustment() {
+        return mZAdjustment;
+    }
+
+    /**
+     * Returns the background color behind the animation.
+     *
+     * @deprecated None of window animations are running with background color.
+     */
+    @Deprecated
+    @ColorInt
+    public int getBackgroundColor() {
+        return 0;
+    }
+
+    /**
+     * Return value of {@link #setDetachWallpaper(boolean)}.
+     * @attr ref android.R.styleable#Animation_detachWallpaper
+     *
+     * @deprecated All window animations are running with detached wallpaper.
+     */
+    @Deprecated
+    public boolean getDetachWallpaper() {
+        return true;
+    }
+
+    /**
+     * @return If run as a window animation, returns whether the wallpaper will be shown behind
+     *         during the animation.
+     * @attr ref android.R.styleable#Animation_showWallpaper
+     * @hide
+     */
+    public boolean getShowWallpaper() {
+        return mShowWallpaper;
+    }
+
+    /**
+     * @return if a window animation should have rounded corners or not.
+     *
+     * @attr ref android.R.styleable#Animation_hasRoundedCorners
+     * @hide
+     */
+    public boolean hasRoundedCorners() {
+        return mHasRoundedCorners;
+    }
+
+    /**
+     * <p>Indicates whether or not this animation will affect the transformation
+     * matrix. For instance, a fade animation will not affect the matrix whereas
+     * a scale animation will.</p>
+     *
+     * @return true if this animation will change the transformation matrix
+     */
+    public boolean willChangeTransformationMatrix() {
+        // assume we will change the matrix
+        return true;
+    }
+
+    /**
+     * <p>Indicates whether or not this animation will affect the bounds of the
+     * animated view. For instance, a fade animation will not affect the bounds
+     * whereas a 200% scale animation will.</p>
+     *
+     * @return true if this animation will change the view's bounds
+     */
+    public boolean willChangeBounds() {
+        // assume we will change the bounds
+        return true;
+    }
+
+    private boolean hasAnimationListener() {
+        return mListener != null;
+    }
+
+    /**
+     * <p>Binds an animation listener to this animation. The animation listener
+     * is notified of animation events such as the end of the animation or the
+     * repetition of the animation.</p>
+     *
+     * @param listener the animation listener to be notified
+     */
+    public void setAnimationListener(AnimationListener listener) {
+        mListener = listener;
+    }
+
+    /**
+     * Gurantees that this animation has an interpolator. Will use
+     * a AccelerateDecelerateInterpolator is nothing else was specified.
+     */
+    protected void ensureInterpolator() {
+        if (mInterpolator == null) {
+            mInterpolator = new AccelerateDecelerateInterpolator();
+        }
+    }
+
+    /**
+     * Compute a hint at how long the entire animation may last, in milliseconds.
+     * Animations can be written to cause themselves to run for a different
+     * duration than what is computed here, but generally this should be
+     * accurate.
+     */
+    public long computeDurationHint() {
+        return (getStartOffset() + getDuration()) * (getRepeatCount() + 1);
+    }
+
+    /**
+     * Gets the transformation to apply at a specified point in time. Implementations of this
+     * method should always replace the specified Transformation or document they are doing
+     * otherwise.
+     *
+     * @param currentTime Where we are in the animation. This is wall clock time.
+     * @param outTransformation A transformation object that is provided by the
+     *        caller and will be filled in by the animation.
+     * @return True if the animation is still running
+     */
+    public boolean getTransformation(long currentTime, Transformation outTransformation) {
+        if (mStartTime == -1) {
+            mStartTime = currentTime;
+        }
+
+        final long startOffset = getStartOffset();
+        final long duration = mDuration;
+        float normalizedTime;
+        if (duration != 0) {
+            normalizedTime = ((float) (currentTime - (mStartTime + startOffset))) /
+                    (float) duration;
+        } else {
+            // time is a step-change with a zero duration
+            normalizedTime = currentTime < mStartTime ? 0.0f : 1.0f;
+        }
+
+        final boolean expired = normalizedTime >= 1.0f || isCanceled();
+        mMore = !expired;
+
+        if (!mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
+
+        if ((normalizedTime >= 0.0f || mFillBefore) && (normalizedTime <= 1.0f || mFillAfter)) {
+            if (!mStarted) {
+                fireAnimationStart();
+                mStarted = true;
+                if (NoImagePreloadHolder.USE_CLOSEGUARD) {
+                    guard.open("cancel or detach or getTransformation");
+                }
+            }
+
+            if (mFillEnabled) normalizedTime = Math.max(Math.min(normalizedTime, 1.0f), 0.0f);
+
+            if (mCycleFlip) {
+                normalizedTime = 1.0f - normalizedTime;
+            }
+
+            final float interpolatedTime = mInterpolator.getInterpolation(normalizedTime);
+            applyTransformation(interpolatedTime, outTransformation);
+        }
+
+        if (expired) {
+            if (mRepeatCount == mRepeated || isCanceled()) {
+                if (!mEnded) {
+                    mEnded = true;
+                    guard.close();
+                    fireAnimationEnd();
+                }
+            } else {
+                if (mRepeatCount > 0) {
+                    mRepeated++;
+                }
+
+                if (mRepeatMode == REVERSE) {
+                    mCycleFlip = !mCycleFlip;
+                }
+
+                mStartTime = -1;
+                mMore = true;
+
+                fireAnimationRepeat();
+            }
+        }
+
+        if (!mMore && mOneMoreTime) {
+            mOneMoreTime = false;
+            return true;
+        }
+
+        return mMore;
+    }
+
+    private boolean isCanceled() {
+        return mStartTime == Long.MIN_VALUE;
+    }
+
+    private void fireAnimationStart() {
+        if (hasAnimationListener()) {
+            if (mListenerHandler == null) dispatchAnimationStart();
+            else mListenerHandler.postAtFrontOfQueue(mOnStart);
+        }
+    }
+
+    private void fireAnimationRepeat() {
+        if (hasAnimationListener()) {
+            if (mListenerHandler == null) dispatchAnimationRepeat();
+            else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
+        }
+    }
+
+    private void fireAnimationEnd() {
+        if (hasAnimationListener()) {
+            if (mListenerHandler == null) dispatchAnimationEnd();
+            else mListenerHandler.postAtFrontOfQueue(mOnEnd);
+        }
+    }
+
+    void dispatchAnimationStart() {
+        if (mListener != null) {
+            mListener.onAnimationStart(this);
+        }
+    }
+
+    void dispatchAnimationRepeat() {
+        if (mListener != null) {
+            mListener.onAnimationRepeat(this);
+        }
+    }
+
+    void dispatchAnimationEnd() {
+        if (mListener != null) {
+            mListener.onAnimationEnd(this);
+        }
+    }
+
+    /**
+     * Gets the transformation to apply at a specified point in time. Implementations of this
+     * method should always replace the specified Transformation or document they are doing
+     * otherwise.
+     *
+     * @param currentTime Where we are in the animation. This is wall clock time.
+     * @param outTransformation A transformation object that is provided by the
+     *        caller and will be filled in by the animation.
+     * @param scale Scaling factor to apply to any inputs to the transform operation, such
+     *        pivot points being rotated or scaled around.
+     * @return True if the animation is still running
+     */
+    public boolean getTransformation(long currentTime, Transformation outTransformation,
+            float scale) {
+        mScaleFactor = scale;
+        return getTransformation(currentTime, outTransformation);
+    }
+
+    /**
+     * <p>Indicates whether this animation has started or not.</p>
+     *
+     * @return true if the animation has started, false otherwise
+     */
+    public boolean hasStarted() {
+        return mStarted;
+    }
+
+    /**
+     * <p>Indicates whether this animation has ended or not.</p>
+     *
+     * @return true if the animation has ended, false otherwise
+     */
+    public boolean hasEnded() {
+        return mEnded;
+    }
+
+    /**
+     * Helper for getTransformation. Subclasses should implement this to apply
+     * their transforms given an interpolation value.  Implementations of this
+     * method should always replace the specified Transformation or document
+     * they are doing otherwise.
+     *
+     * @param interpolatedTime The value of the normalized time (0.0 to 1.0)
+     *        after it has been run through the interpolation function.
+     * @param t The Transformation object to fill in with the current
+     *        transforms.
+     */
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+    }
+
+    /**
+     * Convert the information in the description of a size to an actual
+     * dimension
+     *
+     * @param type One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *             Animation.RELATIVE_TO_PARENT.
+     * @param value The dimension associated with the type parameter
+     * @param size The size of the object being animated
+     * @param parentSize The size of the parent of the object being animated
+     * @return The dimension to use for the animation
+     */
+    protected float resolveSize(int type, float value, int size, int parentSize) {
+        switch (type) {
+            case ABSOLUTE:
+                return value;
+            case RELATIVE_TO_SELF:
+                return size * value;
+            case RELATIVE_TO_PARENT:
+                return parentSize * value;
+            default:
+                return value;
+        }
+    }
+
+    /**
+     * @param left
+     * @param top
+     * @param right
+     * @param bottom
+     * @param invalidate
+     * @param transformation
+     *
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public void getInvalidateRegion(int left, int top, int right, int bottom,
+            RectF invalidate, Transformation transformation) {
+
+        final RectF tempRegion = mRegion;
+        final RectF previousRegion = mPreviousRegion;
+
+        invalidate.set(left, top, right, bottom);
+        transformation.getMatrix().mapRect(invalidate);
+        // Enlarge the invalidate region to account for rounding errors
+        invalidate.inset(-1.0f, -1.0f);
+        tempRegion.set(invalidate);
+        invalidate.union(previousRegion);
+
+        previousRegion.set(tempRegion);
+
+        final Transformation tempTransformation = mTransformation;
+        final Transformation previousTransformation = mPreviousTransformation;
+
+        tempTransformation.set(transformation);
+        transformation.set(previousTransformation);
+        previousTransformation.set(tempTransformation);
+    }
+
+    /**
+     * @param left
+     * @param top
+     * @param right
+     * @param bottom
+     *
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public void initializeInvalidateRegion(int left, int top, int right, int bottom) {
+        final RectF region = mPreviousRegion;
+        region.set(left, top, right, bottom);
+        // Enlarge the invalidate region to account for rounding errors
+        region.inset(-1.0f, -1.0f);
+        if (mFillBefore) {
+            final Transformation previousTransformation = mPreviousTransformation;
+            applyTransformation(mInterpolator.getInterpolation(0.0f), previousTransformation);
+        }
+    }
+
+    protected void finalize() throws Throwable {
+        try {
+            if (guard != null) {
+                guard.warnIfOpen();
+            }
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Return true if this animation changes the view's alpha property.
+     *
+     * @hide
+     */
+    public boolean hasAlpha() {
+        return false;
+    }
+
+    /**
+     * Utility class to parse a string description of a size.
+     */
+    protected static class Description {
+        /**
+         * One of Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+         * Animation.RELATIVE_TO_PARENT.
+         */
+        public int type;
+
+        /**
+         * The absolute or relative dimension for this Description.
+         */
+        public float value;
+
+        /**
+         * Size descriptions can appear inthree forms:
+         * <ol>
+         * <li>An absolute size. This is represented by a number.</li>
+         * <li>A size relative to the size of the object being animated. This
+         * is represented by a number followed by "%".</li> *
+         * <li>A size relative to the size of the parent of object being
+         * animated. This is represented by a number followed by "%p".</li>
+         * </ol>
+         * @param value The typed value to parse
+         * @return The parsed version of the description
+         */
+        static Description parseValue(TypedValue value) {
+            Description d = new Description();
+            if (value == null) {
+                d.type = ABSOLUTE;
+                d.value = 0;
+            } else {
+                if (value.type == TypedValue.TYPE_FRACTION) {
+                    d.type = (value.data & TypedValue.COMPLEX_UNIT_MASK) ==
+                            TypedValue.COMPLEX_UNIT_FRACTION_PARENT ?
+                                    RELATIVE_TO_PARENT : RELATIVE_TO_SELF;
+                    d.value = TypedValue.complexToFloat(value.data);
+                    return d;
+                } else if (value.type == TypedValue.TYPE_FLOAT) {
+                    d.type = ABSOLUTE;
+                    d.value = value.getFloat();
+                    return d;
+                } else if (value.type >= TypedValue.TYPE_FIRST_INT &&
+                        value.type <= TypedValue.TYPE_LAST_INT) {
+                    d.type = ABSOLUTE;
+                    d.value = value.data;
+                    return d;
+                }
+            }
+
+            d.type = ABSOLUTE;
+            d.value = 0.0f;
+
+            return d;
+        }
+    }
+
+    /**
+     * <p>An animation listener receives notifications from an animation.
+     * Notifications indicate animation related events, such as the end or the
+     * repetition of the animation.</p>
+     */
+    public static interface AnimationListener {
+        /**
+         * <p>Notifies the start of the animation.</p>
+         *
+         * @param animation The started animation.
+         */
+        void onAnimationStart(Animation animation);
+
+        /**
+         * <p>Notifies the end of the animation. This callback is not invoked
+         * for animations with repeat count set to INFINITE.</p>
+         *
+         * @param animation The animation which reached its end.
+         */
+        void onAnimationEnd(Animation animation);
+
+        /**
+         * <p>Notifies the repetition of the animation.</p>
+         *
+         * @param animation The animation which was repeated.
+         */
+        void onAnimationRepeat(Animation animation);
+    }
+}
diff --git a/android/view/animation/AnimationSet.java b/android/view/animation/AnimationSet.java
new file mode 100644
index 0000000..03c6ca6
--- /dev/null
+++ b/android/view/animation/AnimationSet.java
@@ -0,0 +1,520 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.RectF;
+import android.os.Build;
+import android.util.AttributeSet;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Represents a group of Animations that should be played together.
+ * The transformation of each individual animation are composed
+ * together into a single transform.
+ * If AnimationSet sets any properties that its children also set
+ * (for example, duration or fillBefore), the values of AnimationSet
+ * override the child values.
+ *
+ * <p>The way that AnimationSet inherits behavior from Animation is important to
+ * understand. Some of the Animation attributes applied to AnimationSet affect the
+ * AnimationSet itself, some are pushed down to the children, and some are ignored,
+ * as follows:
+ * <ul>
+ *     <li>duration, repeatMode, fillBefore, fillAfter: These properties, when set
+ *     on an AnimationSet object, will be pushed down to all child animations.</li>
+ *     <li>repeatCount, fillEnabled: These properties are ignored for AnimationSet.</li>
+ *     <li>startOffset, shareInterpolator: These properties apply to the AnimationSet itself.</li>
+ * </ul>
+ * Starting with {@link android.os.Build.VERSION_CODES#ICE_CREAM_SANDWICH},
+ * the behavior of these properties is the same in XML resources and at runtime (prior to that
+ * release, the values set in XML were ignored for AnimationSet). That is, calling
+ * <code>setDuration(500)</code> on an AnimationSet has the same effect as declaring
+ * <code>android:duration="500"</code> in an XML resource for an AnimationSet object.</p>
+ */
+public class AnimationSet extends Animation {
+    private static final int PROPERTY_FILL_AFTER_MASK         = 0x1;
+    private static final int PROPERTY_FILL_BEFORE_MASK        = 0x2;
+    private static final int PROPERTY_REPEAT_MODE_MASK        = 0x4;
+    private static final int PROPERTY_START_OFFSET_MASK       = 0x8;
+    private static final int PROPERTY_SHARE_INTERPOLATOR_MASK = 0x10;
+    private static final int PROPERTY_DURATION_MASK           = 0x20;
+    private static final int PROPERTY_MORPH_MATRIX_MASK       = 0x40;
+    private static final int PROPERTY_CHANGE_BOUNDS_MASK      = 0x80;
+
+    private int mFlags = 0;
+    private boolean mDirty;
+    private boolean mHasAlpha;
+
+    private ArrayList<Animation> mAnimations = new ArrayList<Animation>();
+
+    private Transformation mTempTransformation = new Transformation();
+
+    private long mLastEnd;
+
+    private long[] mStoredOffsets;
+
+    /**
+     * Constructor used when an AnimationSet is loaded from a resource.
+     *
+     * @param context Application context to use
+     * @param attrs Attribute set from which to read values
+     */
+    public AnimationSet(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a =
+            context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.AnimationSet);
+
+        setFlag(PROPERTY_SHARE_INTERPOLATOR_MASK,
+                a.getBoolean(com.android.internal.R.styleable.AnimationSet_shareInterpolator, true));
+        init();
+
+        if (context.getApplicationInfo().targetSdkVersion >=
+                Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
+            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_duration)) {
+                mFlags |= PROPERTY_DURATION_MASK;
+            }
+            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_fillBefore)) {
+                mFlags |= PROPERTY_FILL_BEFORE_MASK;
+            }
+            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_fillAfter)) {
+                mFlags |= PROPERTY_FILL_AFTER_MASK;
+            }
+            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_repeatMode)) {
+                mFlags |= PROPERTY_REPEAT_MODE_MASK;
+            }
+            if (a.hasValue(com.android.internal.R.styleable.AnimationSet_startOffset)) {
+                mFlags |= PROPERTY_START_OFFSET_MASK;
+            }
+        }
+
+        a.recycle();
+    }
+
+
+    /**
+     * Constructor to use when building an AnimationSet from code
+     *
+     * @param shareInterpolator Pass true if all of the animations in this set
+     *        should use the interpolator associated with this AnimationSet.
+     *        Pass false if each animation should use its own interpolator.
+     */
+    public AnimationSet(boolean shareInterpolator) {
+        setFlag(PROPERTY_SHARE_INTERPOLATOR_MASK, shareInterpolator);
+        init();
+    }
+
+    @Override
+    protected AnimationSet clone() throws CloneNotSupportedException {
+        final AnimationSet animation = (AnimationSet) super.clone();
+        animation.mTempTransformation = new Transformation();
+        animation.mAnimations = new ArrayList<Animation>();
+
+        final int count = mAnimations.size();
+        final ArrayList<Animation> animations = mAnimations;
+
+        for (int i = 0; i < count; i++) {
+            animation.mAnimations.add(animations.get(i).clone());
+        }
+
+        return animation;
+    }
+
+    private void setFlag(int mask, boolean value) {
+        if (value) {
+            mFlags |= mask;
+        } else {
+            mFlags &= ~mask;
+        }
+    }
+
+    private void init() {
+        mStartTime = 0;
+    }
+
+    @Override
+    public void setFillAfter(boolean fillAfter) {
+        mFlags |= PROPERTY_FILL_AFTER_MASK;
+        super.setFillAfter(fillAfter);
+    }
+
+    @Override
+    public void setFillBefore(boolean fillBefore) {
+        mFlags |= PROPERTY_FILL_BEFORE_MASK;
+        super.setFillBefore(fillBefore);
+    }
+
+    @Override
+    public void setRepeatMode(int repeatMode) {
+        mFlags |= PROPERTY_REPEAT_MODE_MASK;
+        super.setRepeatMode(repeatMode);
+    }
+
+    @Override
+    public void setStartOffset(long startOffset) {
+        mFlags |= PROPERTY_START_OFFSET_MASK;
+        super.setStartOffset(startOffset);
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public boolean hasAlpha() {
+        if (mDirty) {
+            mDirty = mHasAlpha = false;
+
+            final int count = mAnimations.size();
+            final ArrayList<Animation> animations = mAnimations;
+
+            for (int i = 0; i < count; i++) {
+                if (animations.get(i).hasAlpha()) {
+                    mHasAlpha = true;
+                    break;
+                }
+            }
+        }
+
+        return mHasAlpha;
+    }
+
+    /**
+     * <p>Sets the duration of every child animation.</p>
+     *
+     * @param durationMillis the duration of the animation, in milliseconds, for
+     *        every child in this set
+     */
+    @Override
+    public void setDuration(long durationMillis) {
+        mFlags |= PROPERTY_DURATION_MASK;
+        super.setDuration(durationMillis);
+        mLastEnd = mStartOffset + mDuration;
+    }
+
+    /**
+     * Add a child animation to this animation set.
+     * The transforms of the child animations are applied in the order
+     * that they were added
+     * @param a Animation to add.
+     */
+    public void addAnimation(Animation a) {
+        mAnimations.add(a);
+
+        boolean noMatrix = (mFlags & PROPERTY_MORPH_MATRIX_MASK) == 0;
+        if (noMatrix && a.willChangeTransformationMatrix()) {
+            mFlags |= PROPERTY_MORPH_MATRIX_MASK;
+        }
+
+        boolean changeBounds = (mFlags & PROPERTY_CHANGE_BOUNDS_MASK) == 0;
+
+
+        if (changeBounds && a.willChangeBounds()) {
+            mFlags |= PROPERTY_CHANGE_BOUNDS_MASK;
+        }
+
+        if ((mFlags & PROPERTY_DURATION_MASK) == PROPERTY_DURATION_MASK) {
+            mLastEnd = mStartOffset + mDuration;
+        } else {
+            if (mAnimations.size() == 1) {
+                mDuration = a.getStartOffset() + a.getDuration();
+                mLastEnd = mStartOffset + mDuration;
+            } else {
+                mLastEnd = Math.max(mLastEnd, mStartOffset + a.getStartOffset() + a.getDuration());
+                mDuration = mLastEnd - mStartOffset;
+            }
+        }
+
+        mDirty = true;
+    }
+
+    /**
+     * Sets the start time of this animation and all child animations
+     *
+     * @see android.view.animation.Animation#setStartTime(long)
+     */
+    @Override
+    public void setStartTime(long startTimeMillis) {
+        super.setStartTime(startTimeMillis);
+
+        final int count = mAnimations.size();
+        final ArrayList<Animation> animations = mAnimations;
+
+        for (int i = 0; i < count; i++) {
+            Animation a = animations.get(i);
+            a.setStartTime(startTimeMillis);
+        }
+    }
+
+    @Override
+    public long getStartTime() {
+        long startTime = Long.MAX_VALUE;
+
+        final int count = mAnimations.size();
+        final ArrayList<Animation> animations = mAnimations;
+
+        for (int i = 0; i < count; i++) {
+            Animation a = animations.get(i);
+            startTime = Math.min(startTime, a.getStartTime());
+        }
+
+        return startTime;
+    }
+
+    @Override
+    public void restrictDuration(long durationMillis) {
+        super.restrictDuration(durationMillis);
+
+        final ArrayList<Animation> animations = mAnimations;
+        int count = animations.size();
+
+        for (int i = 0; i < count; i++) {
+            animations.get(i).restrictDuration(durationMillis);
+        }
+    }
+
+    /**
+     * The duration of an AnimationSet is defined to be the
+     * duration of the longest child animation.
+     *
+     * @see android.view.animation.Animation#getDuration()
+     */
+    @Override
+    public long getDuration() {
+        final ArrayList<Animation> animations = mAnimations;
+        final int count = animations.size();
+        long duration = 0;
+
+        boolean durationSet = (mFlags & PROPERTY_DURATION_MASK) == PROPERTY_DURATION_MASK;
+        if (durationSet) {
+            duration = mDuration;
+        } else {
+            for (int i = 0; i < count; i++) {
+                duration = Math.max(duration, animations.get(i).getDuration());
+            }
+        }
+
+        return duration;
+    }
+
+    /**
+     * The duration hint of an animation set is the maximum of the duration
+     * hints of all of its component animations.
+     *
+     * @see android.view.animation.Animation#computeDurationHint
+     */
+    public long computeDurationHint() {
+        long duration = 0;
+        final int count = mAnimations.size();
+        final ArrayList<Animation> animations = mAnimations;
+        for (int i = count - 1; i >= 0; --i) {
+            final long d = animations.get(i).computeDurationHint();
+            if (d > duration) duration = d;
+        }
+        return duration;
+    }
+
+    /**
+     * @hide
+     */
+    public void initializeInvalidateRegion(int left, int top, int right, int bottom) {
+        final RectF region = mPreviousRegion;
+        region.set(left, top, right, bottom);
+        region.inset(-1.0f, -1.0f);
+
+        if (mFillBefore) {
+            final int count = mAnimations.size();
+            final ArrayList<Animation> animations = mAnimations;
+            final Transformation temp = mTempTransformation;
+
+            final Transformation previousTransformation = mPreviousTransformation;
+
+            for (int i = count - 1; i >= 0; --i) {
+                final Animation a = animations.get(i);
+                if (!a.isFillEnabled() || a.getFillBefore() || a.getStartOffset() == 0) {
+                    temp.clear();
+                    final Interpolator interpolator = a.mInterpolator;
+                    a.applyTransformation(interpolator != null ? interpolator.getInterpolation(0.0f)
+                            : 0.0f, temp);
+                    previousTransformation.compose(temp);
+                }
+            }
+        }
+    }
+
+    /**
+     * The transformation of an animation set is the concatenation of all of its
+     * component animations.
+     *
+     * @see android.view.animation.Animation#getTransformation
+     */
+    @Override
+    public boolean getTransformation(long currentTime, Transformation t) {
+        final int count = mAnimations.size();
+        final ArrayList<Animation> animations = mAnimations;
+        final Transformation temp = mTempTransformation;
+
+        boolean more = false;
+        boolean started = false;
+        boolean ended = true;
+
+        t.clear();
+
+        for (int i = count - 1; i >= 0; --i) {
+            final Animation a = animations.get(i);
+
+            temp.clear();
+            more = a.getTransformation(currentTime, temp, getScaleFactor()) || more;
+            t.compose(temp);
+
+            started = started || a.hasStarted();
+            ended = a.hasEnded() && ended;
+        }
+
+        if (started && !mStarted) {
+            dispatchAnimationStart();
+            mStarted = true;
+        }
+
+        if (ended != mEnded) {
+            dispatchAnimationEnd();
+            mEnded = ended;
+        }
+
+        return more;
+    }
+
+    /**
+     * @see android.view.animation.Animation#scaleCurrentDuration(float)
+     */
+    @Override
+    public void scaleCurrentDuration(float scale) {
+        final ArrayList<Animation> animations = mAnimations;
+        int count = animations.size();
+        for (int i = 0; i < count; i++) {
+            animations.get(i).scaleCurrentDuration(scale);
+        }
+    }
+
+    /**
+     * @see android.view.animation.Animation#initialize(int, int, int, int)
+     */
+    @Override
+    public void initialize(int width, int height, int parentWidth, int parentHeight) {
+        super.initialize(width, height, parentWidth, parentHeight);
+
+        boolean durationSet = (mFlags & PROPERTY_DURATION_MASK) == PROPERTY_DURATION_MASK;
+        boolean fillAfterSet = (mFlags & PROPERTY_FILL_AFTER_MASK) == PROPERTY_FILL_AFTER_MASK;
+        boolean fillBeforeSet = (mFlags & PROPERTY_FILL_BEFORE_MASK) == PROPERTY_FILL_BEFORE_MASK;
+        boolean repeatModeSet = (mFlags & PROPERTY_REPEAT_MODE_MASK) == PROPERTY_REPEAT_MODE_MASK;
+        boolean shareInterpolator = (mFlags & PROPERTY_SHARE_INTERPOLATOR_MASK)
+                == PROPERTY_SHARE_INTERPOLATOR_MASK;
+        boolean startOffsetSet = (mFlags & PROPERTY_START_OFFSET_MASK)
+                == PROPERTY_START_OFFSET_MASK;
+
+        if (shareInterpolator) {
+            ensureInterpolator();
+        }
+
+        final ArrayList<Animation> children = mAnimations;
+        final int count = children.size();
+
+        final long duration = mDuration;
+        final boolean fillAfter = mFillAfter;
+        final boolean fillBefore = mFillBefore;
+        final int repeatMode = mRepeatMode;
+        final Interpolator interpolator = mInterpolator;
+        final long startOffset = mStartOffset;
+
+
+        long[] storedOffsets = mStoredOffsets;
+        if (startOffsetSet) {
+            if (storedOffsets == null || storedOffsets.length != count) {
+                storedOffsets = mStoredOffsets = new long[count];
+            }
+        } else if (storedOffsets != null) {
+            storedOffsets = mStoredOffsets = null;
+        }
+
+        for (int i = 0; i < count; i++) {
+            Animation a = children.get(i);
+            if (durationSet) {
+                a.setDuration(duration);
+            }
+            if (fillAfterSet) {
+                a.setFillAfter(fillAfter);
+            }
+            if (fillBeforeSet) {
+                a.setFillBefore(fillBefore);
+            }
+            if (repeatModeSet) {
+                a.setRepeatMode(repeatMode);
+            }
+            if (shareInterpolator) {
+                a.setInterpolator(interpolator);
+            }
+            if (startOffsetSet) {
+                long offset = a.getStartOffset();
+                a.setStartOffset(offset + startOffset);
+                storedOffsets[i] = offset;
+            }
+            a.initialize(width, height, parentWidth, parentHeight);
+        }
+    }
+
+    @Override
+    public void reset() {
+        super.reset();
+        restoreChildrenStartOffset();
+    }
+
+    /**
+     * @hide
+     */
+    void restoreChildrenStartOffset() {
+        final long[] offsets = mStoredOffsets;
+        if (offsets == null) return;
+
+        final ArrayList<Animation> children = mAnimations;
+        final int count = children.size();
+
+        for (int i = 0; i < count; i++) {
+            children.get(i).setStartOffset(offsets[i]);
+        }
+    }
+
+    /**
+     * @return All the child animations in this AnimationSet. Note that
+     * this may include other AnimationSets, which are not expanded.
+     */
+    public List<Animation> getAnimations() {
+        return mAnimations;
+    }
+
+    @Override
+    public boolean willChangeTransformationMatrix() {
+        return (mFlags & PROPERTY_MORPH_MATRIX_MASK) == PROPERTY_MORPH_MATRIX_MASK;
+    }
+
+    @Override
+    public boolean willChangeBounds() {
+        return (mFlags & PROPERTY_CHANGE_BOUNDS_MASK) == PROPERTY_CHANGE_BOUNDS_MASK;
+    }
+}
diff --git a/android/view/animation/AnimationUtils.java b/android/view/animation/AnimationUtils.java
new file mode 100644
index 0000000..7ce0f45
--- /dev/null
+++ b/android/view/animation/AnimationUtils.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2007 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 android.view.animation;
+
+import android.annotation.AnimRes;
+import android.annotation.InterpolatorRes;
+import android.annotation.TestApi;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Defines common utilities for working with animations.
+ *
+ */
+public class AnimationUtils {
+
+    /**
+     * These flags are used when parsing AnimatorSet objects
+     */
+    private static final int TOGETHER = 0;
+    private static final int SEQUENTIALLY = 1;
+
+    private static class AnimationState {
+        boolean animationClockLocked;
+        long currentVsyncTimeMillis;
+        long lastReportedTimeMillis;
+    };
+
+    private static ThreadLocal<AnimationState> sAnimationState
+            = new ThreadLocal<AnimationState>() {
+        @Override
+        protected AnimationState initialValue() {
+            return new AnimationState();
+        }
+    };
+
+    /**
+     * Locks AnimationUtils{@link #currentAnimationTimeMillis()} to a fixed value for the current
+     * thread. This is used by {@link android.view.Choreographer} to ensure that all accesses
+     * during a vsync update are synchronized to the timestamp of the vsync.
+     *
+     * It is also exposed to tests to allow for rapid, flake-free headless testing.
+     *
+     * Must be followed by a call to {@link #unlockAnimationClock()} to allow time to
+     * progress. Failing to do this will result in stuck animations, scrolls, and flings.
+     *
+     * Note that time is not allowed to "rewind" and must perpetually flow forward. So the
+     * lock may fail if the time is in the past from a previously returned value, however
+     * time will be frozen for the duration of the lock. The clock is a thread-local, so
+     * ensure that {@link #lockAnimationClock(long)}, {@link #unlockAnimationClock()}, and
+     * {@link #currentAnimationTimeMillis()} are all called on the same thread.
+     *
+     * This is also not reference counted in any way. Any call to {@link #unlockAnimationClock()}
+     * will unlock the clock for everyone on the same thread. It is therefore recommended
+     * for tests to use their own thread to ensure that there is no collision with any existing
+     * {@link android.view.Choreographer} instance.
+     *
+     * @hide
+     * */
+    @TestApi
+    public static void lockAnimationClock(long vsyncMillis) {
+        AnimationState state = sAnimationState.get();
+        state.animationClockLocked = true;
+        state.currentVsyncTimeMillis = vsyncMillis;
+    }
+
+    /**
+     * Frees the time lock set in place by {@link #lockAnimationClock(long)}. Must be called
+     * to allow the animation clock to self-update.
+     *
+     * @hide
+     */
+    @TestApi
+    public static void unlockAnimationClock() {
+        sAnimationState.get().animationClockLocked = false;
+    }
+
+    /**
+     * Returns the current animation time in milliseconds. This time should be used when invoking
+     * {@link Animation#setStartTime(long)}. Refer to {@link android.os.SystemClock} for more
+     * information about the different available clocks. The clock used by this method is
+     * <em>not</em> the "wall" clock (it is not {@link System#currentTimeMillis}).
+     *
+     * @return the current animation time in milliseconds
+     *
+     * @see android.os.SystemClock
+     */
+    public static long currentAnimationTimeMillis() {
+        AnimationState state = sAnimationState.get();
+        if (state.animationClockLocked) {
+            // It's important that time never rewinds
+            return Math.max(state.currentVsyncTimeMillis,
+                    state.lastReportedTimeMillis);
+        }
+        state.lastReportedTimeMillis = SystemClock.uptimeMillis();
+        return state.lastReportedTimeMillis;
+    }
+
+    /**
+     * 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 referenced by the specified id
+     * @throws NotFoundException when the animation cannot be loaded
+     */
+    public static Animation loadAnimation(Context context, @AnimRes int id)
+            throws NotFoundException {
+
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getAnimation(id);
+            return createAnimationFromXml(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 Animation createAnimationFromXml(Context c, XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+
+        return createAnimationFromXml(c, parser, null, Xml.asAttributeSet(parser));
+    }
+
+    @UnsupportedAppUsage
+    private static Animation createAnimationFromXml(Context c, XmlPullParser parser,
+            AnimationSet parent, AttributeSet attrs) throws XmlPullParserException, IOException {
+
+        Animation anim = 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("set")) {
+                anim = new AnimationSet(c, attrs);
+                createAnimationFromXml(c, parser, (AnimationSet)anim, attrs);
+            } else if (name.equals("alpha")) {
+                anim = new AlphaAnimation(c, attrs);
+            } else if (name.equals("scale")) {
+                anim = new ScaleAnimation(c, attrs);
+            }  else if (name.equals("rotate")) {
+                anim = new RotateAnimation(c, attrs);
+            }  else if (name.equals("translate")) {
+                anim = new TranslateAnimation(c, attrs);
+            } else if (name.equals("cliprect")) {
+                anim = new ClipRectAnimation(c, attrs);
+            } else {
+                throw new RuntimeException("Unknown animation name: " + parser.getName());
+            }
+
+            if (parent != null) {
+                parent.addAnimation(anim);
+            }
+        }
+
+        return anim;
+
+    }
+
+    /**
+     * Loads a {@link LayoutAnimationController} 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 controller object referenced by the specified id
+     * @throws NotFoundException when the layout animation controller cannot be loaded
+     */
+    public static LayoutAnimationController loadLayoutAnimation(Context context, @AnimRes int id)
+            throws NotFoundException {
+
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getAnimation(id);
+            return createLayoutAnimationFromXml(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 LayoutAnimationController createLayoutAnimationFromXml(Context c,
+            XmlPullParser parser) throws XmlPullParserException, IOException {
+
+        return createLayoutAnimationFromXml(c, parser, Xml.asAttributeSet(parser));
+    }
+
+    private static LayoutAnimationController createLayoutAnimationFromXml(Context c,
+            XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException {
+
+        LayoutAnimationController controller = null;
+
+        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 ("layoutAnimation".equals(name)) {
+                controller = new LayoutAnimationController(c, attrs);
+            } else if ("gridLayoutAnimation".equals(name)) {
+                controller = new GridLayoutAnimationController(c, attrs);
+            } else {
+                throw new RuntimeException("Unknown layout animation name: " + name);
+            }
+        }
+
+        return controller;
+    }
+
+    /**
+     * Make an animation for objects becoming visible. Uses a slide and fade
+     * effect.
+     *
+     * @param c Context for loading resources
+     * @param fromLeft is the object to be animated coming from the left
+     * @return The new animation
+     */
+    public static Animation makeInAnimation(Context c, boolean fromLeft) {
+        Animation a;
+        if (fromLeft) {
+            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_left);
+        } else {
+            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_right);
+        }
+
+        a.setInterpolator(new DecelerateInterpolator());
+        a.setStartTime(currentAnimationTimeMillis());
+        return a;
+    }
+
+    /**
+     * Make an animation for objects becoming invisible. Uses a slide and fade
+     * effect.
+     *
+     * @param c Context for loading resources
+     * @param toRight is the object to be animated exiting to the right
+     * @return The new animation
+     */
+    public static Animation makeOutAnimation(Context c, boolean toRight) {
+        Animation a;
+        if (toRight) {
+            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_right);
+        } else {
+            a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_out_left);
+        }
+
+        a.setInterpolator(new AccelerateInterpolator());
+        a.setStartTime(currentAnimationTimeMillis());
+        return a;
+    }
+
+
+    /**
+     * Make an animation for objects becoming visible. Uses a slide up and fade
+     * effect.
+     *
+     * @param c Context for loading resources
+     * @return The new animation
+     */
+    public static Animation makeInChildBottomAnimation(Context c) {
+        Animation a;
+        a = AnimationUtils.loadAnimation(c, com.android.internal.R.anim.slide_in_child_bottom);
+        a.setInterpolator(new AccelerateInterpolator());
+        a.setStartTime(currentAnimationTimeMillis());
+        return a;
+    }
+
+    /**
+     * Loads an {@link Interpolator} object from a resource
+     *
+     * @param context Application context used to access resources
+     * @param id The resource id of the animation to load
+     * @return The interpolator object referenced by the specified id
+     * @throws NotFoundException
+     */
+    public static Interpolator loadInterpolator(Context context, @AnimRes @InterpolatorRes int id)
+            throws NotFoundException {
+        XmlResourceParser parser = null;
+        try {
+            parser = context.getResources().getAnimation(id);
+            return createInterpolatorFromXml(context.getResources(), context.getTheme(), 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();
+        }
+
+    }
+
+    /**
+     * Loads an {@link Interpolator} object from a resource
+     *
+     * @param res The resources
+     * @param id The resource id of the animation to load
+     * @return The interpolator object referenced by the specified id
+     * @throws NotFoundException
+     * @hide
+     */
+    public static Interpolator loadInterpolator(Resources res, Theme theme, int id) throws NotFoundException {
+        XmlResourceParser parser = null;
+        try {
+            parser = res.getAnimation(id);
+            return createInterpolatorFromXml(res, theme, 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 Interpolator createInterpolatorFromXml(Resources res, Theme theme, XmlPullParser parser)
+            throws XmlPullParserException, IOException {
+
+        BaseInterpolator interpolator = 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;
+            }
+
+            AttributeSet attrs = Xml.asAttributeSet(parser);
+
+            String name = parser.getName();
+
+            if (name.equals("linearInterpolator")) {
+                interpolator = new LinearInterpolator();
+            } else if (name.equals("accelerateInterpolator")) {
+                interpolator = new AccelerateInterpolator(res, theme, attrs);
+            } else if (name.equals("decelerateInterpolator")) {
+                interpolator = new DecelerateInterpolator(res, theme, attrs);
+            } else if (name.equals("accelerateDecelerateInterpolator")) {
+                interpolator = new AccelerateDecelerateInterpolator();
+            } else if (name.equals("cycleInterpolator")) {
+                interpolator = new CycleInterpolator(res, theme, attrs);
+            } else if (name.equals("anticipateInterpolator")) {
+                interpolator = new AnticipateInterpolator(res, theme, attrs);
+            } else if (name.equals("overshootInterpolator")) {
+                interpolator = new OvershootInterpolator(res, theme, attrs);
+            } else if (name.equals("anticipateOvershootInterpolator")) {
+                interpolator = new AnticipateOvershootInterpolator(res, theme, attrs);
+            } else if (name.equals("bounceInterpolator")) {
+                interpolator = new BounceInterpolator();
+            } else if (name.equals("pathInterpolator")) {
+                interpolator = new PathInterpolator(res, theme, attrs);
+            } else {
+                throw new RuntimeException("Unknown interpolator name: " + parser.getName());
+            }
+        }
+        return interpolator;
+    }
+}
diff --git a/android/view/animation/AnticipateInterpolator.java b/android/view/animation/AnticipateInterpolator.java
new file mode 100644
index 0000000..d146394
--- /dev/null
+++ b/android/view/animation/AnticipateInterpolator.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2009 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+/**
+ * An interpolator where the change starts backward then flings forward.
+ */
+@HasNativeInterpolator
+public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolator {
+    private final float mTension;
+
+    public AnticipateInterpolator() {
+        mTension = 2.0f;
+    }
+
+    /**
+     * @param tension Amount of anticipation. When tension equals 0.0f, there is
+     *                no anticipation and the interpolator becomes a simple
+     *                acceleration interpolator.
+     */
+    public AnticipateInterpolator(float tension) {
+        mTension = tension;
+    }
+
+    public AnticipateInterpolator(Context context, AttributeSet attrs) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public AnticipateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.AnticipateInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.AnticipateInterpolator);
+        }
+
+        mTension = a.getFloat(R.styleable.AnticipateInterpolator_tension, 2.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
+        a.recycle();
+    }
+
+    public float getInterpolation(float t) {
+        // a(t) = t * t * ((tension + 1) * t - tension)
+        return t * t * ((mTension + 1) * t - mTension);
+    }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createAnticipateInterpolator(mTension);
+    }
+}
diff --git a/android/view/animation/AnticipateOvershootInterpolator.java b/android/view/animation/AnticipateOvershootInterpolator.java
new file mode 100644
index 0000000..4d6a390
--- /dev/null
+++ b/android/view/animation/AnticipateOvershootInterpolator.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2009 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 android.view.animation;
+
+import static com.android.internal.R.styleable.AnticipateOvershootInterpolator;
+import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_extraTension;
+import static com.android.internal.R.styleable.AnticipateOvershootInterpolator_tension;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+
+/**
+ * An interpolator where the change starts backward then flings forward and overshoots
+ * the target value and finally goes back to the final value.
+ */
+@HasNativeInterpolator
+public class AnticipateOvershootInterpolator extends BaseInterpolator
+        implements NativeInterpolator {
+    private final float mTension;
+
+    public AnticipateOvershootInterpolator() {
+        mTension = 2.0f * 1.5f;
+    }
+
+    /**
+     * @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
+     *                there is no anticipation/overshoot and the interpolator becomes
+     *                a simple acceleration/deceleration interpolator.
+     */
+    public AnticipateOvershootInterpolator(float tension) {
+        mTension = tension * 1.5f;
+    }
+
+    /**
+     * @param tension Amount of anticipation/overshoot. When tension equals 0.0f,
+     *                there is no anticipation/overshoot and the interpolator becomes
+     *                a simple acceleration/deceleration interpolator.
+     * @param extraTension Amount by which to multiply the tension. For instance,
+     *                     to get the same overshoot as an OvershootInterpolator with
+     *                     a tension of 2.0f, you would use an extraTension of 1.5f.
+     */
+    public AnticipateOvershootInterpolator(float tension, float extraTension) {
+        mTension = tension * extraTension;
+    }
+
+    public AnticipateOvershootInterpolator(Context context, AttributeSet attrs) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public AnticipateOvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, AnticipateOvershootInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, AnticipateOvershootInterpolator);
+        }
+
+        mTension = a.getFloat(AnticipateOvershootInterpolator_tension, 2.0f) *
+                a.getFloat(AnticipateOvershootInterpolator_extraTension, 1.5f);
+        setChangingConfiguration(a.getChangingConfigurations());
+        a.recycle();
+    }
+
+    private static float a(float t, float s) {
+        return t * t * ((s + 1) * t - s);
+    }
+
+    private static float o(float t, float s) {
+        return t * t * ((s + 1) * t + s);
+    }
+
+    public float getInterpolation(float t) {
+        // a(t, s) = t * t * ((s + 1) * t - s)
+        // o(t, s) = t * t * ((s + 1) * t + s)
+        // f(t) = 0.5 * a(t * 2, tension * extraTension), when t < 0.5
+        // f(t) = 0.5 * (o(t * 2 - 2, tension * extraTension) + 2), when t <= 1.0
+        if (t < 0.5f) return 0.5f * a(t * 2.0f, mTension);
+        else return 0.5f * (o(t * 2.0f - 2.0f, mTension) + 2.0f);
+    }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createAnticipateOvershootInterpolator(mTension);
+    }
+}
diff --git a/android/view/animation/BaseInterpolator.java b/android/view/animation/BaseInterpolator.java
new file mode 100644
index 0000000..a78fa1e
--- /dev/null
+++ b/android/view/animation/BaseInterpolator.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2014 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 android.view.animation;
+
+import android.content.pm.ActivityInfo.Config;
+
+/**
+ * An abstract class which is extended by default interpolators.
+ */
+abstract public class BaseInterpolator implements Interpolator {
+    private @Config int mChangingConfiguration;
+    /**
+     * @hide
+     */
+    public @Config int getChangingConfiguration() {
+        return mChangingConfiguration;
+    }
+
+    /**
+     * @hide
+     */
+    void setChangingConfiguration(@Config int changingConfiguration) {
+        mChangingConfiguration = changingConfiguration;
+    }
+}
diff --git a/android/view/animation/BounceInterpolator.java b/android/view/animation/BounceInterpolator.java
new file mode 100644
index 0000000..d3f6a3f
--- /dev/null
+++ b/android/view/animation/BounceInterpolator.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2009 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 android.view.animation;
+
+import android.content.Context;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+/**
+ * An interpolator where the change bounces at the end.
+ */
+@HasNativeInterpolator
+public class BounceInterpolator extends BaseInterpolator implements NativeInterpolator {
+    public BounceInterpolator() {
+    }
+
+    @SuppressWarnings({"UnusedDeclaration"})
+    public BounceInterpolator(Context context, AttributeSet attrs) {
+    }
+
+    private static float bounce(float t) {
+        return t * t * 8.0f;
+    }
+
+    public float getInterpolation(float t) {
+        // _b(t) = t * t * 8
+        // bs(t) = _b(t) for t < 0.3535
+        // bs(t) = _b(t - 0.54719) + 0.7 for t < 0.7408
+        // bs(t) = _b(t - 0.8526) + 0.9 for t < 0.9644
+        // bs(t) = _b(t - 1.0435) + 0.95 for t <= 1.0
+        // b(t) = bs(t * 1.1226)
+        t *= 1.1226f;
+        if (t < 0.3535f) return bounce(t);
+        else if (t < 0.7408f) return bounce(t - 0.54719f) + 0.7f;
+        else if (t < 0.9644f) return bounce(t - 0.8526f) + 0.9f;
+        else return bounce(t - 1.0435f) + 0.95f;
+    }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createBounceInterpolator();
+    }
+}
\ No newline at end of file
diff --git a/android/view/animation/ClipRectAnimation.java b/android/view/animation/ClipRectAnimation.java
new file mode 100644
index 0000000..21509d3
--- /dev/null
+++ b/android/view/animation/ClipRectAnimation.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2014 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+
+/**
+ * An animation that controls the clip of an object. See the
+ * {@link android.view.animation full package} description for details and
+ * sample code.
+ *
+ * @hide
+ */
+public class ClipRectAnimation extends Animation {
+    protected final Rect mFromRect = new Rect();
+    protected final Rect mToRect = new Rect();
+
+    private int mFromLeftType = ABSOLUTE;
+    private int mFromTopType = ABSOLUTE;
+    private int mFromRightType = ABSOLUTE;
+    private int mFromBottomType = ABSOLUTE;
+
+    private int mToLeftType = ABSOLUTE;
+    private int mToTopType = ABSOLUTE;
+    private int mToRightType = ABSOLUTE;
+    private int mToBottomType = ABSOLUTE;
+
+    private float mFromLeftValue;
+    private float mFromTopValue;
+    private float mFromRightValue;
+    private float mFromBottomValue;
+
+    private float mToLeftValue;
+    private float mToTopValue;
+    private float mToRightValue;
+    private float mToBottomValue;
+
+    /**
+     * Constructor used when a ClipRectAnimation is loaded from a resource.
+     *
+     * @param context Application context to use
+     * @param attrs Attribute set from which to read values
+     */
+    public ClipRectAnimation(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.ClipRectAnimation);
+
+        Description d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_fromLeft));
+        mFromLeftType = d.type;
+        mFromLeftValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_fromTop));
+        mFromTopType = d.type;
+        mFromTopValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_fromRight));
+        mFromRightType = d.type;
+        mFromRightValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_fromBottom));
+        mFromBottomType = d.type;
+        mFromBottomValue = d.value;
+
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_toLeft));
+        mToLeftType = d.type;
+        mToLeftValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_toTop));
+        mToTopType = d.type;
+        mToTopValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_toRight));
+        mToRightType = d.type;
+        mToRightValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ClipRectAnimation_toBottom));
+        mToBottomType = d.type;
+        mToBottomValue = d.value;
+
+        a.recycle();
+    }
+
+    /**
+     * Constructor to use when building a ClipRectAnimation from code
+     *
+     * @param fromClip the clip rect to animate from
+     * @param toClip the clip rect to animate to
+     */
+    public ClipRectAnimation(Rect fromClip, Rect toClip) {
+        if (fromClip == null || toClip == null) {
+            throw new RuntimeException("Expected non-null animation clip rects");
+        }
+        mFromLeftValue = fromClip.left;
+        mFromTopValue = fromClip.top;
+        mFromRightValue= fromClip.right;
+        mFromBottomValue = fromClip.bottom;
+
+        mToLeftValue = toClip.left;
+        mToTopValue = toClip.top;
+        mToRightValue= toClip.right;
+        mToBottomValue = toClip.bottom;
+    }
+
+    /**
+     * Constructor to use when building a ClipRectAnimation from code
+     */
+    public ClipRectAnimation(int fromL, int fromT, int fromR, int fromB,
+            int toL, int toT, int toR, int toB) {
+        this(new Rect(fromL, fromT, fromR, fromB), new Rect(toL, toT, toR, toB));
+    }
+
+    @Override
+    protected void applyTransformation(float it, Transformation tr) {
+        int l = mFromRect.left + (int) ((mToRect.left - mFromRect.left) * it);
+        int t = mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it);
+        int r = mFromRect.right + (int) ((mToRect.right - mFromRect.right) * it);
+        int b = mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it);
+        tr.setClipRect(l, t, r, b);
+    }
+
+    @Override
+    public boolean willChangeTransformationMatrix() {
+        return false;
+    }
+
+    @Override
+    public void initialize(int width, int height, int parentWidth, int parentHeight) {
+        super.initialize(width, height, parentWidth, parentHeight);
+        mFromRect.set((int) resolveSize(mFromLeftType, mFromLeftValue, width, parentWidth),
+                (int) resolveSize(mFromTopType, mFromTopValue, height, parentHeight),
+                (int) resolveSize(mFromRightType, mFromRightValue, width, parentWidth),
+                (int) resolveSize(mFromBottomType, mFromBottomValue, height, parentHeight));
+        mToRect.set((int) resolveSize(mToLeftType, mToLeftValue, width, parentWidth),
+                (int) resolveSize(mToTopType, mToTopValue, height, parentHeight),
+                (int) resolveSize(mToRightType, mToRightValue, width, parentWidth),
+                (int) resolveSize(mToBottomType, mToBottomValue, height, parentHeight));
+    }
+}
diff --git a/android/view/animation/CycleInterpolator.java b/android/view/animation/CycleInterpolator.java
new file mode 100644
index 0000000..6b1a80a
--- /dev/null
+++ b/android/view/animation/CycleInterpolator.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+/**
+ * Repeats the animation for a specified number of cycles. The
+ * rate of change follows a sinusoidal pattern.
+ *
+ */
+@HasNativeInterpolator
+public class CycleInterpolator extends BaseInterpolator implements NativeInterpolator {
+    public CycleInterpolator(float cycles) {
+        mCycles = cycles;
+    }
+
+    public CycleInterpolator(Context context, AttributeSet attrs) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public CycleInterpolator(Resources resources, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.CycleInterpolator, 0, 0);
+        } else {
+            a = resources.obtainAttributes(attrs, R.styleable.CycleInterpolator);
+        }
+
+        mCycles = a.getFloat(R.styleable.CycleInterpolator_cycles, 1.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
+        a.recycle();
+    }
+
+    public float getInterpolation(float input) {
+        return (float)(Math.sin(2 * mCycles * Math.PI * input));
+    }
+
+    private float mCycles;
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createCycleInterpolator(mCycles);
+    }
+}
diff --git a/android/view/animation/DecelerateInterpolator.java b/android/view/animation/DecelerateInterpolator.java
new file mode 100644
index 0000000..2d2f770
--- /dev/null
+++ b/android/view/animation/DecelerateInterpolator.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+/**
+ * An interpolator where the rate of change starts out quickly and
+ * and then decelerates.
+ *
+ */
+@HasNativeInterpolator
+public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolator {
+    public DecelerateInterpolator() {
+    }
+
+    /**
+     * Constructor
+     *
+     * @param factor Degree to which the animation should be eased. Setting factor to 1.0f produces
+     *        an upside-down y=x^2 parabola. Increasing factor above 1.0f exaggerates the
+     *        ease-out effect (i.e., it starts even faster and ends evens slower).
+     */
+    public DecelerateInterpolator(float factor) {
+        mFactor = factor;
+    }
+
+    public DecelerateInterpolator(Context context, AttributeSet attrs) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public DecelerateInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.DecelerateInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.DecelerateInterpolator);
+        }
+
+        mFactor = a.getFloat(R.styleable.DecelerateInterpolator_factor, 1.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
+        a.recycle();
+    }
+
+    public float getInterpolation(float input) {
+        float result;
+        if (mFactor == 1.0f) {
+            result = (float)(1.0f - (1.0f - input) * (1.0f - input));
+        } else {
+            result = (float)(1.0f - Math.pow((1.0f - input), 2 * mFactor));
+        }
+        return result;
+    }
+
+    private float mFactor = 1.0f;
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createDecelerateInterpolator(mFactor);
+    }
+}
diff --git a/android/view/animation/GridLayoutAnimationController.java b/android/view/animation/GridLayoutAnimationController.java
new file mode 100644
index 0000000..0f189ae
--- /dev/null
+++ b/android/view/animation/GridLayoutAnimationController.java
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2007 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Random;
+
+/**
+ * A layout animation controller is used to animated a grid layout's children.
+ *
+ * While {@link LayoutAnimationController} relies only on the index of the child
+ * in the view group to compute the animation delay, this class uses both the
+ * X and Y coordinates of the child within a grid.
+ *
+ * In addition, the animation direction can be controlled. The default direction
+ * is <code>DIRECTION_LEFT_TO_RIGHT | DIRECTION_TOP_TO_BOTTOM</code>. You can
+ * also set the animation priority to columns or rows. The default priority is
+ * none.
+ *
+ * Information used to compute the animation delay of each child are stored
+ * in an instance of
+ * {@link android.view.animation.GridLayoutAnimationController.AnimationParameters},
+ * itself stored in the {@link android.view.ViewGroup.LayoutParams} of the view.
+ *
+ * @see LayoutAnimationController
+ * @see android.widget.GridView
+ *
+ * @attr ref android.R.styleable#GridLayoutAnimation_columnDelay
+ * @attr ref android.R.styleable#GridLayoutAnimation_rowDelay
+ * @attr ref android.R.styleable#GridLayoutAnimation_direction
+ * @attr ref android.R.styleable#GridLayoutAnimation_directionPriority
+ */
+public class GridLayoutAnimationController extends LayoutAnimationController {
+    /**
+     * Animates the children starting from the left of the grid to the right.
+     */
+    public static final int DIRECTION_LEFT_TO_RIGHT = 0x0;
+
+    /**
+     * Animates the children starting from the right of the grid to the left.
+     */
+    public static final int DIRECTION_RIGHT_TO_LEFT = 0x1;
+
+    /**
+     * Animates the children starting from the top of the grid to the bottom.
+     */
+    public static final int DIRECTION_TOP_TO_BOTTOM = 0x0;
+
+    /**
+     * Animates the children starting from the bottom of the grid to the top.
+     */
+    public static final int DIRECTION_BOTTOM_TO_TOP = 0x2;
+
+    /**
+     * Bitmask used to retrieve the horizontal component of the direction.
+     */
+    public static final int DIRECTION_HORIZONTAL_MASK = 0x1;
+
+    /**
+     * Bitmask used to retrieve the vertical component of the direction.
+     */
+    public static final int DIRECTION_VERTICAL_MASK   = 0x2;
+
+    /**
+     * Rows and columns are animated at the same time.
+     */
+    public static final int PRIORITY_NONE   = 0;
+
+    /**
+     * Columns are animated first.
+     */
+    public static final int PRIORITY_COLUMN = 1;
+
+    /**
+     * Rows are animated first.
+     */
+    public static final int PRIORITY_ROW    = 2;
+
+    private float mColumnDelay;
+    private float mRowDelay;
+
+    private int mDirection;
+    private int mDirectionPriority;
+
+    /**
+     * Creates a new grid layout animation controller from external resources.
+     *
+     * @param context the Context the view  group is running in, through which
+     *        it can access the resources
+     * @param attrs the attributes of the XML tag that is inflating the
+     *        layout animation controller
+     */
+    public GridLayoutAnimationController(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.GridLayoutAnimation);
+
+        Animation.Description d = Animation.Description.parseValue(
+                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_columnDelay));
+        mColumnDelay = d.value;
+        d = Animation.Description.parseValue(
+                a.peekValue(com.android.internal.R.styleable.GridLayoutAnimation_rowDelay));
+        mRowDelay = d.value;
+        //noinspection PointlessBitwiseExpression
+        mDirection = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_direction,
+                DIRECTION_LEFT_TO_RIGHT | DIRECTION_TOP_TO_BOTTOM);
+        mDirectionPriority = a.getInt(com.android.internal.R.styleable.GridLayoutAnimation_directionPriority,
+                PRIORITY_NONE);
+
+        a.recycle();
+    }
+
+    /**
+     * Creates a new layout animation controller with a delay of 50%
+     * for both rows and columns and the specified animation.
+     *
+     * @param animation the animation to use on each child of the view group
+     */
+    public GridLayoutAnimationController(Animation animation) {
+        this(animation, 0.5f, 0.5f);
+    }
+
+    /**
+     * Creates a new layout animation controller with the specified delays
+     * and the specified animation.
+     *
+     * @param animation the animation to use on each child of the view group
+     * @param columnDelay the delay by which each column animation must be offset
+     * @param rowDelay the delay by which each row animation must be offset
+     */
+    public GridLayoutAnimationController(Animation animation, float columnDelay, float rowDelay) {
+        super(animation);
+        mColumnDelay = columnDelay;
+        mRowDelay = rowDelay;
+    }
+
+    /**
+     * Returns the delay by which the children's animation are offset from one
+     * column to the other. The delay is expressed as a fraction of the
+     * animation duration.
+     *
+     * @return a fraction of the animation duration
+     *
+     * @see #setColumnDelay(float)
+     * @see #getRowDelay()
+     * @see #setRowDelay(float)
+     */
+    public float getColumnDelay() {
+        return mColumnDelay;
+    }
+
+    /**
+     * Sets the delay, as a fraction of the animation duration, by which the
+     * children's animations are offset from one column to the other.
+     *
+     * @param columnDelay a fraction of the animation duration
+     *
+     * @see #getColumnDelay()
+     * @see #getRowDelay()
+     * @see #setRowDelay(float)
+     */
+    public void setColumnDelay(float columnDelay) {
+        mColumnDelay = columnDelay;
+    }
+
+    /**
+     * Returns the delay by which the children's animation are offset from one
+     * row to the other. The delay is expressed as a fraction of the
+     * animation duration.
+     *
+     * @return a fraction of the animation duration
+     *
+     * @see #setRowDelay(float)
+     * @see #getColumnDelay()
+     * @see #setColumnDelay(float)
+     */
+    public float getRowDelay() {
+        return mRowDelay;
+    }
+
+    /**
+     * Sets the delay, as a fraction of the animation duration, by which the
+     * children's animations are offset from one row to the other.
+     *
+     * @param rowDelay a fraction of the animation duration
+     *
+     * @see #getRowDelay()
+     * @see #getColumnDelay()
+     * @see #setColumnDelay(float)
+     */
+    public void setRowDelay(float rowDelay) {
+        mRowDelay = rowDelay;
+    }
+
+    /**
+     * Returns the direction of the animation. {@link #DIRECTION_HORIZONTAL_MASK}
+     * and {@link #DIRECTION_VERTICAL_MASK} can be used to retrieve the
+     * horizontal and vertical components of the direction.
+     *
+     * @return the direction of the animation
+     *
+     * @see #setDirection(int)
+     * @see #DIRECTION_BOTTOM_TO_TOP
+     * @see #DIRECTION_TOP_TO_BOTTOM
+     * @see #DIRECTION_LEFT_TO_RIGHT
+     * @see #DIRECTION_RIGHT_TO_LEFT
+     * @see #DIRECTION_HORIZONTAL_MASK
+     * @see #DIRECTION_VERTICAL_MASK
+     */
+    public int getDirection() {
+        return mDirection;
+    }
+
+    /**
+     * Sets the direction of the animation. The direction is expressed as an
+     * integer containing a horizontal and vertical component. For instance,
+     * <code>DIRECTION_BOTTOM_TO_TOP | DIRECTION_RIGHT_TO_LEFT</code>.
+     *
+     * @param direction the direction of the animation
+     *
+     * @see #getDirection()
+     * @see #DIRECTION_BOTTOM_TO_TOP
+     * @see #DIRECTION_TOP_TO_BOTTOM
+     * @see #DIRECTION_LEFT_TO_RIGHT
+     * @see #DIRECTION_RIGHT_TO_LEFT
+     * @see #DIRECTION_HORIZONTAL_MASK
+     * @see #DIRECTION_VERTICAL_MASK
+     */
+    public void setDirection(int direction) {
+        mDirection = direction;
+    }
+
+    /**
+     * Returns the direction priority for the animation. The priority can
+     * be either {@link #PRIORITY_NONE}, {@link #PRIORITY_COLUMN} or
+     * {@link #PRIORITY_ROW}.
+     *
+     * @return the priority of the animation direction
+     *
+     * @see #setDirectionPriority(int)
+     * @see #PRIORITY_COLUMN
+     * @see #PRIORITY_NONE
+     * @see #PRIORITY_ROW
+     */
+    public int getDirectionPriority() {
+        return mDirectionPriority;
+    }
+
+    /**
+     * Specifies the direction priority of the animation. For instance,
+     * {@link #PRIORITY_COLUMN} will give priority to columns: the animation
+     * will first play on the column, then on the rows.Z
+     *
+     * @param directionPriority the direction priority of the animation
+     *
+     * @see #getDirectionPriority()
+     * @see #PRIORITY_COLUMN
+     * @see #PRIORITY_NONE
+     * @see #PRIORITY_ROW
+     */
+    public void setDirectionPriority(int directionPriority) {
+        mDirectionPriority = directionPriority;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean willOverlap() {
+        return mColumnDelay < 1.0f || mRowDelay < 1.0f;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected long getDelayForView(View view) {
+        ViewGroup.LayoutParams lp = view.getLayoutParams();
+        AnimationParameters params = (AnimationParameters) lp.layoutAnimationParameters;
+
+        if (params == null) {
+            return 0;
+        }
+
+        final int column = getTransformedColumnIndex(params);
+        final int row = getTransformedRowIndex(params);
+
+        final int rowsCount = params.rowsCount;
+        final int columnsCount = params.columnsCount;
+
+        final long duration = mAnimation.getDuration();
+        final float columnDelay = mColumnDelay * duration;
+        final float rowDelay = mRowDelay * duration;
+
+        float totalDelay;
+        long viewDelay;
+
+        if (mInterpolator == null) {
+            mInterpolator = new LinearInterpolator();
+        }
+
+        switch (mDirectionPriority) {
+            case PRIORITY_COLUMN:
+                viewDelay = (long) (row * rowDelay + column * rowsCount * rowDelay);
+                totalDelay = rowsCount * rowDelay + columnsCount * rowsCount * rowDelay;
+                break;
+            case PRIORITY_ROW:
+                viewDelay = (long) (column * columnDelay + row * columnsCount * columnDelay);
+                totalDelay = columnsCount * columnDelay + rowsCount * columnsCount * columnDelay;
+                break;
+            case PRIORITY_NONE:
+            default:
+                viewDelay = (long) (column * columnDelay + row * rowDelay);
+                totalDelay = columnsCount * columnDelay + rowsCount * rowDelay;
+                break;
+        }
+
+        float normalizedDelay = viewDelay / totalDelay;
+        normalizedDelay = mInterpolator.getInterpolation(normalizedDelay);
+
+        return (long) (normalizedDelay * totalDelay);
+    }
+
+    private int getTransformedColumnIndex(AnimationParameters params) {
+        int index;
+        switch (getOrder()) {
+            case ORDER_REVERSE:
+                index = params.columnsCount - 1 - params.column;
+                break;
+            case ORDER_RANDOM:
+                if (mRandomizer == null) {
+                    mRandomizer = new Random();
+                }
+                index = (int) (params.columnsCount * mRandomizer.nextFloat());
+                break;
+            case ORDER_NORMAL:
+            default:
+                index = params.column;
+                break;
+        }
+
+        int direction = mDirection & DIRECTION_HORIZONTAL_MASK;
+        if (direction == DIRECTION_RIGHT_TO_LEFT) {
+            index = params.columnsCount - 1 - index;
+        }
+
+        return index;
+    }
+
+    private int getTransformedRowIndex(AnimationParameters params) {
+        int index;
+        switch (getOrder()) {
+            case ORDER_REVERSE:
+                index = params.rowsCount - 1 - params.row;
+                break;
+            case ORDER_RANDOM:
+                if (mRandomizer == null) {
+                    mRandomizer = new Random();
+                }
+                index = (int) (params.rowsCount * mRandomizer.nextFloat());
+                break;
+            case ORDER_NORMAL:
+            default:
+                index = params.row;
+                break;
+        }
+
+        int direction = mDirection & DIRECTION_VERTICAL_MASK;
+        if (direction == DIRECTION_BOTTOM_TO_TOP) {
+            index = params.rowsCount - 1 - index;
+        }
+
+        return index;
+    }
+
+    /**
+     * The set of parameters that has to be attached to each view contained in
+     * the view group animated by the grid layout animation controller. These
+     * parameters are used to compute the start time of each individual view's
+     * animation.
+     */
+    public static class AnimationParameters extends
+            LayoutAnimationController.AnimationParameters {
+        /**
+         * The view group's column to which the view belongs.
+         */
+        public int column;
+
+        /**
+         * The view group's row to which the view belongs.
+         */
+        public int row;
+
+        /**
+         * The number of columns in the view's enclosing grid layout.
+         */
+        public int columnsCount;
+
+        /**
+         * The number of rows in the view's enclosing grid layout.
+         */
+        public int rowsCount;
+    }
+}
diff --git a/android/view/animation/Interpolator.java b/android/view/animation/Interpolator.java
new file mode 100644
index 0000000..5d0fe7e
--- /dev/null
+++ b/android/view/animation/Interpolator.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.animation.TimeInterpolator;
+
+/**
+ * An interpolator defines the rate of change of an animation. This allows
+ * the basic animation effects (alpha, scale, translate, rotate) to be 
+ * accelerated, decelerated, repeated, etc.
+ */
+public interface Interpolator extends TimeInterpolator {
+    // A new interface, TimeInterpolator, was introduced for the new android.animation
+    // package. This older Interpolator interface extends TimeInterpolator so that users of
+    // the new Animator-based animations can use either the old Interpolator implementations or
+    // new classes that implement TimeInterpolator directly.
+}
diff --git a/android/view/animation/LayoutAnimationController.java b/android/view/animation/LayoutAnimationController.java
new file mode 100644
index 0000000..7fa49c1
--- /dev/null
+++ b/android/view/animation/LayoutAnimationController.java
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2007 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 android.view.animation;
+
+import android.annotation.AnimRes;
+import android.annotation.InterpolatorRes;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.Random;
+
+/**
+ * A layout animation controller is used to animated a layout's, or a view
+ * group's, children. Each child uses the same animation but for every one of
+ * them, the animation starts at a different time. A layout animation controller
+ * is used by {@link android.view.ViewGroup} to compute the delay by which each
+ * child's animation start must be offset. The delay is computed by using
+ * characteristics of each child, like its index in the view group.
+ *
+ * This standard implementation computes the delay by multiplying a fixed
+ * amount of miliseconds by the index of the child in its parent view group.
+ * Subclasses are supposed to override
+ * {@link #getDelayForView(android.view.View)} to implement a different way
+ * of computing the delay. For instance, a
+ * {@link android.view.animation.GridLayoutAnimationController} will compute the
+ * delay based on the column and row indices of the child in its parent view
+ * group.
+ *
+ * Information used to compute the animation delay of each child are stored
+ * in an instance of
+ * {@link android.view.animation.LayoutAnimationController.AnimationParameters},
+ * itself stored in the {@link android.view.ViewGroup.LayoutParams} of the view.
+ *
+ * @attr ref android.R.styleable#LayoutAnimation_delay
+ * @attr ref android.R.styleable#LayoutAnimation_animationOrder
+ * @attr ref android.R.styleable#LayoutAnimation_interpolator
+ * @attr ref android.R.styleable#LayoutAnimation_animation
+ */
+public class LayoutAnimationController {
+    /**
+     * Distributes the animation delays in the order in which view were added
+     * to their view group.
+     */
+    public static final int ORDER_NORMAL  = 0;
+
+    /**
+     * Distributes the animation delays in the reverse order in which view were
+     * added to their view group.
+     */
+    public static final int ORDER_REVERSE = 1;
+
+    /**
+     * Randomly distributes the animation delays.
+     */
+    public static final int ORDER_RANDOM  = 2;
+
+    /**
+     * The animation applied on each child of the view group on which this
+     * layout animation controller is set.
+     */
+    protected Animation mAnimation;
+
+    /**
+     * The randomizer used when the order is set to random. Subclasses should
+     * use this object to avoid creating their own.
+     */
+    protected Random mRandomizer;
+
+    /**
+     * The interpolator used to interpolate the delays.
+     */
+    protected Interpolator mInterpolator;
+
+    private float mDelay;
+    private int mOrder;
+
+    private long mDuration;
+    private long mMaxDelay;    
+
+    /**
+     * Creates a new layout animation controller from external resources.
+     *
+     * @param context the Context the view  group is running in, through which
+     *        it can access the resources
+     * @param attrs the attributes of the XML tag that is inflating the
+     *        layout animation controller
+     */
+    public LayoutAnimationController(Context context, AttributeSet attrs) {
+        TypedArray a = context.obtainStyledAttributes(attrs, com.android.internal.R.styleable.LayoutAnimation);
+
+        Animation.Description d = Animation.Description.parseValue(
+                a.peekValue(com.android.internal.R.styleable.LayoutAnimation_delay));
+        mDelay = d.value;
+
+        mOrder = a.getInt(com.android.internal.R.styleable.LayoutAnimation_animationOrder, ORDER_NORMAL);
+
+        int resource = a.getResourceId(com.android.internal.R.styleable.LayoutAnimation_animation, 0);
+        if (resource > 0) {
+            setAnimation(context, resource);
+        }
+
+        resource = a.getResourceId(com.android.internal.R.styleable.LayoutAnimation_interpolator, 0);
+        if (resource > 0) {
+            setInterpolator(context, resource);
+        }
+
+        a.recycle();
+    }
+
+    /**
+     * Creates a new layout animation controller with a delay of 50%
+     * and the specified animation.
+     *
+     * @param animation the animation to use on each child of the view group
+     */
+    public LayoutAnimationController(Animation animation) {
+        this(animation, 0.5f);
+    }
+
+    /**
+     * Creates a new layout animation controller with the specified delay
+     * and the specified animation.
+     *
+     * @param animation the animation to use on each child of the view group
+     * @param delay the delay by which each child's animation must be offset
+     */
+    public LayoutAnimationController(Animation animation, float delay) {
+        mDelay = delay;
+        setAnimation(animation);
+    }
+
+    /**
+     * Returns the order used to compute the delay of each child's animation.
+     *
+     * @return one of {@link #ORDER_NORMAL}, {@link #ORDER_REVERSE} or
+     *         {@link #ORDER_RANDOM}
+     *
+     * @attr ref android.R.styleable#LayoutAnimation_animationOrder
+     */
+    public int getOrder() {
+        return mOrder;
+    }
+
+    /**
+     * Sets the order used to compute the delay of each child's animation.
+     *
+     * @param order one of {@link #ORDER_NORMAL}, {@link #ORDER_REVERSE} or
+     *        {@link #ORDER_RANDOM}
+     *
+     * @attr ref android.R.styleable#LayoutAnimation_animationOrder
+     */
+    public void setOrder(int order) {
+        mOrder = order;
+    }
+
+    /**
+     * Sets the animation to be run on each child of the view group on which
+     * this layout animation controller is .
+     *
+     * @param context the context from which the animation must be inflated
+     * @param resourceID the resource identifier of the animation
+     *
+     * @see #setAnimation(Animation)
+     * @see #getAnimation() 
+     *
+     * @attr ref android.R.styleable#LayoutAnimation_animation
+     */
+    public void setAnimation(Context context, @AnimRes int resourceID) {
+        setAnimation(AnimationUtils.loadAnimation(context, resourceID));
+    }
+
+    /**
+     * Sets the animation to be run on each child of the view group on which
+     * this layout animation controller is .
+     *
+     * @param animation the animation to run on each child of the view group
+
+     * @see #setAnimation(android.content.Context, int)
+     * @see #getAnimation()
+     *
+     * @attr ref android.R.styleable#LayoutAnimation_animation
+     */
+    public void setAnimation(Animation animation) {
+        mAnimation = animation;
+        mAnimation.setFillBefore(true);
+    }
+
+    /**
+     * Returns the animation applied to each child of the view group on which
+     * this controller is set.
+     *
+     * @return an {@link android.view.animation.Animation} instance
+     *
+     * @see #setAnimation(android.content.Context, int)
+     * @see #setAnimation(Animation)
+     */
+    public Animation getAnimation() {
+        return mAnimation;
+    }
+
+    /**
+     * Sets the interpolator used to interpolate the delays between the
+     * children.
+     *
+     * @param context the context from which the interpolator must be inflated
+     * @param resourceID the resource identifier of the interpolator
+     *
+     * @see #getInterpolator()
+     * @see #setInterpolator(Interpolator)
+     *
+     * @attr ref android.R.styleable#LayoutAnimation_interpolator
+     */
+    public void setInterpolator(Context context, @InterpolatorRes int resourceID) {
+        setInterpolator(AnimationUtils.loadInterpolator(context, resourceID));
+    }
+
+    /**
+     * Sets the interpolator used to interpolate the delays between the
+     * children.
+     *
+     * @param interpolator the interpolator
+     *
+     * @see #getInterpolator()
+     * @see #setInterpolator(Interpolator)
+     *
+     * @attr ref android.R.styleable#LayoutAnimation_interpolator
+     */
+    public void setInterpolator(Interpolator interpolator) {
+        mInterpolator = interpolator;
+    }
+
+    /**
+     * Returns the interpolator used to interpolate the delays between the
+     * children.
+     *
+     * @return an {@link android.view.animation.Interpolator}
+     */
+    public Interpolator getInterpolator() {
+        return mInterpolator;
+    }
+
+    /**
+     * Returns the delay by which the children's animation are offset. The
+     * delay is expressed as a fraction of the animation duration.
+     *
+     * @return a fraction of the animation duration
+     *
+     * @see #setDelay(float)
+     */
+    public float getDelay() {
+        return mDelay;
+    }
+
+    /**
+     * Sets the delay, as a fraction of the animation duration, by which the
+     * children's animations are offset. The general formula is:
+     *
+     * <pre>
+     * child animation delay = child index * delay * animation duration
+     * </pre>
+     *
+     * @param delay a fraction of the animation duration
+     *
+     * @see #getDelay()
+     */
+    public void setDelay(float delay) {
+        mDelay = delay;
+    }
+
+    /**
+     * Indicates whether two children's animations will overlap. Animations
+     * overlap when the delay is lower than 100% (or 1.0).
+     *
+     * @return true if animations will overlap, false otherwise
+     */
+    public boolean willOverlap() {
+        return mDelay < 1.0f;
+    }
+
+    /**
+     * Starts the animation.
+     */
+    public void start() {
+        mDuration = mAnimation.getDuration();
+        mMaxDelay = Long.MIN_VALUE;
+        mAnimation.setStartTime(-1);
+    }
+
+    /**
+     * Returns the animation to be applied to the specified view. The returned
+     * animation is delayed by an offset computed according to the information
+     * provided by
+     * {@link android.view.animation.LayoutAnimationController.AnimationParameters}.
+     * This method is called by view groups to obtain the animation to set on
+     * a specific child.
+     *
+     * @param view the view to animate
+     * @return an animation delayed by the number of milliseconds returned by
+     *         {@link #getDelayForView(android.view.View)}
+     *
+     * @see #getDelay()
+     * @see #setDelay(float)
+     * @see #getDelayForView(android.view.View)
+     */
+    public final Animation getAnimationForView(View view) {
+        final long delay = getDelayForView(view) + mAnimation.getStartOffset();
+        mMaxDelay = Math.max(mMaxDelay, delay);
+
+        try {
+            final Animation animation = mAnimation.clone();
+            animation.setStartOffset(delay);
+            return animation;
+        } catch (CloneNotSupportedException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Indicates whether the layout animation is over or not. A layout animation
+     * is considered done when the animation with the longest delay is done.
+     *
+     * @return true if all of the children's animations are over, false otherwise
+     */
+    public boolean isDone() {
+        return AnimationUtils.currentAnimationTimeMillis() >
+                mAnimation.getStartTime() + mMaxDelay + mDuration;
+    }
+
+    /**
+     * Returns the amount of milliseconds by which the specified view's
+     * animation must be delayed or offset. Subclasses should override this
+     * method to return a suitable value.
+     *
+     * This implementation returns <code>child animation delay</code>
+     * milliseconds where:
+     *
+     * <pre>
+     * child animation delay = child index * delay
+     * </pre>
+     *
+     * The index is retrieved from the
+     * {@link android.view.animation.LayoutAnimationController.AnimationParameters}
+     * found in the view's {@link android.view.ViewGroup.LayoutParams}.
+     *
+     * @param view the view for which to obtain the animation's delay
+     * @return a delay in milliseconds
+     *
+     * @see #getAnimationForView(android.view.View)
+     * @see #getDelay()
+     * @see #getTransformedIndex(android.view.animation.LayoutAnimationController.AnimationParameters)
+     * @see android.view.ViewGroup.LayoutParams
+     */
+    protected long getDelayForView(View view) {
+        ViewGroup.LayoutParams lp = view.getLayoutParams();
+        AnimationParameters params = lp.layoutAnimationParameters;
+
+        if (params == null) {
+            return 0;
+        }
+
+        final float delay = mDelay * mAnimation.getDuration();
+        final long viewDelay = (long) (getTransformedIndex(params) * delay);
+        final float totalDelay = delay * params.count;
+
+        if (mInterpolator == null) {
+            mInterpolator = new LinearInterpolator();
+        }
+
+        float normalizedDelay = viewDelay / totalDelay;
+        normalizedDelay = mInterpolator.getInterpolation(normalizedDelay);
+
+        return (long) (normalizedDelay * totalDelay);
+    }
+
+    /**
+     * Transforms the index stored in
+     * {@link android.view.animation.LayoutAnimationController.AnimationParameters}
+     * by the order returned by {@link #getOrder()}. Subclasses should override
+     * this method to provide additional support for other types of ordering.
+     * This method should be invoked by
+     * {@link #getDelayForView(android.view.View)} prior to any computation. 
+     *
+     * @param params the animation parameters containing the index
+     * @return a transformed index
+     */
+    protected int getTransformedIndex(AnimationParameters params) {
+        switch (getOrder()) {
+            case ORDER_REVERSE:
+                return params.count - 1 - params.index;
+            case ORDER_RANDOM:
+                if (mRandomizer == null) {
+                    mRandomizer = new Random();
+                }
+                return (int) (params.count * mRandomizer.nextFloat());
+            case ORDER_NORMAL:
+            default:
+                return params.index;
+        }
+    }
+
+    /**
+     * The set of parameters that has to be attached to each view contained in
+     * the view group animated by the layout animation controller. These
+     * parameters are used to compute the start time of each individual view's
+     * animation.
+     */
+    public static class AnimationParameters {
+        /**
+         * The number of children in the view group containing the view to which
+         * these parameters are attached.
+         */
+        public int count;
+
+        /**
+         * The index of the view to which these parameters are attached in its
+         * containing view group.
+         */
+        public int index;
+    }
+}
diff --git a/android/view/animation/LinearInterpolator.java b/android/view/animation/LinearInterpolator.java
new file mode 100644
index 0000000..f6a820c
--- /dev/null
+++ b/android/view/animation/LinearInterpolator.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.content.Context;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+/**
+ * An interpolator where the rate of change is constant
+ */
+@HasNativeInterpolator
+public class LinearInterpolator extends BaseInterpolator implements NativeInterpolator {
+
+    public LinearInterpolator() {
+    }
+
+    public LinearInterpolator(Context context, AttributeSet attrs) {
+    }
+
+    public float getInterpolation(float input) {
+        return input;
+    }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createLinearInterpolator();
+    }
+}
diff --git a/android/view/animation/OvershootInterpolator.java b/android/view/animation/OvershootInterpolator.java
new file mode 100644
index 0000000..e6445d7
--- /dev/null
+++ b/android/view/animation/OvershootInterpolator.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2009 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+
+import com.android.internal.R;
+
+/**
+ * An interpolator where the change flings forward and overshoots the last value
+ * then comes back.
+ */
+@HasNativeInterpolator
+public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolator {
+    private final float mTension;
+
+    public OvershootInterpolator() {
+        mTension = 2.0f;
+    }
+
+    /**
+     * @param tension Amount of overshoot. When tension equals 0.0f, there is
+     *                no overshoot and the interpolator becomes a simple
+     *                deceleration interpolator.
+     */
+    public OvershootInterpolator(float tension) {
+        mTension = tension;
+    }
+
+    public OvershootInterpolator(Context context, AttributeSet attrs) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public OvershootInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.OvershootInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.OvershootInterpolator);
+        }
+
+        mTension = a.getFloat(R.styleable.OvershootInterpolator_tension, 2.0f);
+        setChangingConfiguration(a.getChangingConfigurations());
+        a.recycle();
+    }
+
+    public float getInterpolation(float t) {
+        // _o(t) = t * t * ((tension + 1) * t + tension)
+        // o(t) = _o(t - 1) + 1
+        t -= 1.0f;
+        return t * t * ((mTension + 1) * t + mTension) + 1.0f;
+    }
+
+    /** @hide */
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createOvershootInterpolator(mTension);
+    }
+}
diff --git a/android/view/animation/PathInterpolator.java b/android/view/animation/PathInterpolator.java
new file mode 100644
index 0000000..99d6b9c
--- /dev/null
+++ b/android/view/animation/PathInterpolator.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2013 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Path;
+import android.graphics.animation.HasNativeInterpolator;
+import android.graphics.animation.NativeInterpolator;
+import android.graphics.animation.NativeInterpolatorFactory;
+import android.util.AttributeSet;
+import android.util.PathParser;
+import android.view.InflateException;
+
+import com.android.internal.R;
+
+/**
+ * An interpolator that can traverse a Path that extends from <code>Point</code>
+ * <code>(0, 0)</code> to <code>(1, 1)</code>. The x coordinate along the <code>Path</code>
+ * is the input value and the output is the y coordinate of the line at that point.
+ * This means that the Path must conform to a function <code>y = f(x)</code>.
+ *
+ * <p>The <code>Path</code> must not have gaps in the x direction and must not
+ * loop back on itself such that there can be two points sharing the same x coordinate.
+ * It is alright to have a disjoint line in the vertical direction:</p>
+ * <p><blockquote><pre>
+ *     Path path = new Path();
+ *     path.lineTo(0.25f, 0.25f);
+ *     path.moveTo(0.25f, 0.5f);
+ *     path.lineTo(1f, 1f);
+ * </pre></blockquote></p>
+ */
+@HasNativeInterpolator
+public class PathInterpolator extends BaseInterpolator implements NativeInterpolator {
+
+    // This governs how accurate the approximation of the Path is.
+    private static final float PRECISION = 0.002f;
+
+    private float[] mX; // x coordinates in the line
+
+    private float[] mY; // y coordinates in the line
+
+    /**
+     * Create an interpolator for an arbitrary <code>Path</code>. The <code>Path</code>
+     * must begin at <code>(0, 0)</code> and end at <code>(1, 1)</code>.
+     *
+     * @param path The <code>Path</code> to use to make the line representing the interpolator.
+     */
+    public PathInterpolator(Path path) {
+        initPath(path);
+    }
+
+    /**
+     * Create an interpolator for a quadratic Bezier curve. The end points
+     * <code>(0, 0)</code> and <code>(1, 1)</code> are assumed.
+     *
+     * @param controlX The x coordinate of the quadratic Bezier control point.
+     * @param controlY The y coordinate of the quadratic Bezier control point.
+     */
+    public PathInterpolator(float controlX, float controlY) {
+        initQuad(controlX, controlY);
+    }
+
+    /**
+     * Create an interpolator for a cubic Bezier curve.  The end points
+     * <code>(0, 0)</code> and <code>(1, 1)</code> are assumed.
+     *
+     * @param controlX1 The x coordinate of the first control point of the cubic Bezier.
+     * @param controlY1 The y coordinate of the first control point of the cubic Bezier.
+     * @param controlX2 The x coordinate of the second control point of the cubic Bezier.
+     * @param controlY2 The y coordinate of the second control point of the cubic Bezier.
+     */
+    public PathInterpolator(float controlX1, float controlY1, float controlX2, float controlY2) {
+        initCubic(controlX1, controlY1, controlX2, controlY2);
+    }
+
+    public PathInterpolator(Context context, AttributeSet attrs) {
+        this(context.getResources(), context.getTheme(), attrs);
+    }
+
+    /** @hide */
+    public PathInterpolator(Resources res, Theme theme, AttributeSet attrs) {
+        TypedArray a;
+        if (theme != null) {
+            a = theme.obtainStyledAttributes(attrs, R.styleable.PathInterpolator, 0, 0);
+        } else {
+            a = res.obtainAttributes(attrs, R.styleable.PathInterpolator);
+        }
+        parseInterpolatorFromTypeArray(a);
+        setChangingConfiguration(a.getChangingConfigurations());
+        a.recycle();
+    }
+
+    private void parseInterpolatorFromTypeArray(TypedArray a) {
+        // If there is pathData defined in the xml file, then the controls points
+        // will be all coming from pathData.
+        if (a.hasValue(R.styleable.PathInterpolator_pathData)) {
+            String pathData = a.getString(R.styleable.PathInterpolator_pathData);
+            Path path = PathParser.createPathFromPathData(pathData);
+            if (path == null) {
+                throw new InflateException("The path is null, which is created"
+                        + " from " + pathData);
+            }
+            initPath(path);
+        } else {
+            if (!a.hasValue(R.styleable.PathInterpolator_controlX1)) {
+                throw new InflateException("pathInterpolator requires the controlX1 attribute");
+            } else if (!a.hasValue(R.styleable.PathInterpolator_controlY1)) {
+                throw new InflateException("pathInterpolator requires the controlY1 attribute");
+            }
+            float x1 = a.getFloat(R.styleable.PathInterpolator_controlX1, 0);
+            float y1 = a.getFloat(R.styleable.PathInterpolator_controlY1, 0);
+
+            boolean hasX2 = a.hasValue(R.styleable.PathInterpolator_controlX2);
+            boolean hasY2 = a.hasValue(R.styleable.PathInterpolator_controlY2);
+
+            if (hasX2 != hasY2) {
+                throw new InflateException(
+                        "pathInterpolator requires both controlX2 and controlY2 for cubic Beziers.");
+            }
+
+            if (!hasX2) {
+                initQuad(x1, y1);
+            } else {
+                float x2 = a.getFloat(R.styleable.PathInterpolator_controlX2, 0);
+                float y2 = a.getFloat(R.styleable.PathInterpolator_controlY2, 0);
+                initCubic(x1, y1, x2, y2);
+            }
+        }
+    }
+
+    private void initQuad(float controlX, float controlY) {
+        Path path = new Path();
+        path.moveTo(0, 0);
+        path.quadTo(controlX, controlY, 1f, 1f);
+        initPath(path);
+    }
+
+    private void initCubic(float x1, float y1, float x2, float y2) {
+        Path path = new Path();
+        path.moveTo(0, 0);
+        path.cubicTo(x1, y1, x2, y2, 1f, 1f);
+        initPath(path);
+    }
+
+    private void initPath(Path path) {
+        float[] pointComponents = path.approximate(PRECISION);
+
+        int numPoints = pointComponents.length / 3;
+        if (pointComponents[1] != 0 || pointComponents[2] != 0
+                || pointComponents[pointComponents.length - 2] != 1
+                || pointComponents[pointComponents.length - 1] != 1) {
+            throw new IllegalArgumentException("The Path must start at (0,0) and end at (1,1)");
+        }
+
+        mX = new float[numPoints];
+        mY = new float[numPoints];
+        float prevX = 0;
+        float prevFraction = 0;
+        int componentIndex = 0;
+        for (int i = 0; i < numPoints; i++) {
+            float fraction = pointComponents[componentIndex++];
+            float x = pointComponents[componentIndex++];
+            float y = pointComponents[componentIndex++];
+            if (fraction == prevFraction && x != prevX) {
+                throw new IllegalArgumentException(
+                        "The Path cannot have discontinuity in the X axis.");
+            }
+            if (x < prevX) {
+                throw new IllegalArgumentException("The Path cannot loop back on itself.");
+            }
+            mX[i] = x;
+            mY[i] = y;
+            prevX = x;
+            prevFraction = fraction;
+        }
+    }
+
+    /**
+     * Using the line in the Path in this interpolator that can be described as
+     * <code>y = f(x)</code>, finds the y coordinate of the line given <code>t</code>
+     * as the x coordinate. Values less than 0 will always return 0 and values greater
+     * than 1 will always return 1.
+     *
+     * @param t Treated as the x coordinate along the line.
+     * @return The y coordinate of the Path along the line where x = <code>t</code>.
+     * @see Interpolator#getInterpolation(float)
+     */
+    @Override
+    public float getInterpolation(float t) {
+        if (t <= 0) {
+            return 0;
+        } else if (t >= 1) {
+            return 1;
+        }
+        // Do a binary search for the correct x to interpolate between.
+        int startIndex = 0;
+        int endIndex = mX.length - 1;
+
+        while (endIndex - startIndex > 1) {
+            int midIndex = (startIndex + endIndex) / 2;
+            if (t < mX[midIndex]) {
+                endIndex = midIndex;
+            } else {
+                startIndex = midIndex;
+            }
+        }
+
+        float xRange = mX[endIndex] - mX[startIndex];
+        if (xRange == 0) {
+            return mY[startIndex];
+        }
+
+        float tInRange = t - mX[startIndex];
+        float fraction = tInRange / xRange;
+
+        float startY = mY[startIndex];
+        float endY = mY[endIndex];
+        return startY + (fraction * (endY - startY));
+    }
+
+    /** @hide **/
+    @Override
+    public long createNativeInterpolator() {
+        return NativeInterpolatorFactory.createPathInterpolator(mX, mY);
+    }
+
+}
diff --git a/android/view/animation/RotateAnimation.java b/android/view/animation/RotateAnimation.java
new file mode 100644
index 0000000..3c325d9
--- /dev/null
+++ b/android/view/animation/RotateAnimation.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+/**
+ * An animation that controls the rotation of an object. This rotation takes
+ * place in the X-Y plane. You can specify the point to use for the center of
+ * the rotation, where (0,0) is the top left point. If not specified, (0,0) is
+ * the default rotation point.
+ * 
+ */
+public class RotateAnimation extends Animation {
+    private float mFromDegrees;
+    private float mToDegrees;
+
+    private int mPivotXType = ABSOLUTE;
+    private int mPivotYType = ABSOLUTE;
+    private float mPivotXValue = 0.0f;
+    private float mPivotYValue = 0.0f;
+
+    private float mPivotX;
+    private float mPivotY;
+
+    /**
+     * Constructor used when a RotateAnimation is loaded from a resource.
+     * 
+     * @param context Application context to use
+     * @param attrs Attribute set from which to read values
+     */
+    public RotateAnimation(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.RotateAnimation);
+
+        mFromDegrees = a.getFloat(
+                com.android.internal.R.styleable.RotateAnimation_fromDegrees, 0.0f);
+        mToDegrees = a.getFloat(com.android.internal.R.styleable.RotateAnimation_toDegrees, 0.0f);
+
+        Description d = Description.parseValue(a.peekValue(
+            com.android.internal.R.styleable.RotateAnimation_pivotX));
+        mPivotXType = d.type;
+        mPivotXValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+            com.android.internal.R.styleable.RotateAnimation_pivotY));
+        mPivotYType = d.type;
+        mPivotYValue = d.value;
+
+        a.recycle();
+
+        initializePivotPoint();
+    }
+
+    /**
+     * Constructor to use when building a RotateAnimation from code.
+     * Default pivotX/pivotY point is (0,0).
+     * 
+     * @param fromDegrees Rotation offset to apply at the start of the
+     *        animation.
+     * 
+     * @param toDegrees Rotation offset to apply at the end of the animation.
+     */
+    public RotateAnimation(float fromDegrees, float toDegrees) {
+        mFromDegrees = fromDegrees;
+        mToDegrees = toDegrees;
+        mPivotX = 0.0f;
+        mPivotY = 0.0f;
+    }
+
+    /**
+     * Constructor to use when building a RotateAnimation from code
+     * 
+     * @param fromDegrees Rotation offset to apply at the start of the
+     *        animation.
+     * 
+     * @param toDegrees Rotation offset to apply at the end of the animation.
+     * 
+     * @param pivotX The X coordinate of the point about which the object is
+     *        being rotated, specified as an absolute number where 0 is the left
+     *        edge.
+     * @param pivotY The Y coordinate of the point about which the object is
+     *        being rotated, specified as an absolute number where 0 is the top
+     *        edge.
+     */
+    public RotateAnimation(float fromDegrees, float toDegrees, float pivotX, float pivotY) {
+        mFromDegrees = fromDegrees;
+        mToDegrees = toDegrees;
+
+        mPivotXType = ABSOLUTE;
+        mPivotYType = ABSOLUTE;
+        mPivotXValue = pivotX;
+        mPivotYValue = pivotY;
+        initializePivotPoint();
+    }
+
+    /**
+     * Constructor to use when building a RotateAnimation from code
+     * 
+     * @param fromDegrees Rotation offset to apply at the start of the
+     *        animation.
+     * 
+     * @param toDegrees Rotation offset to apply at the end of the animation.
+     * 
+     * @param pivotXType Specifies how pivotXValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param pivotXValue The X coordinate of the point about which the object
+     *        is being rotated, specified as an absolute number where 0 is the
+     *        left edge. This value can either be an absolute number if
+     *        pivotXType is ABSOLUTE, or a percentage (where 1.0 is 100%)
+     *        otherwise.
+     * @param pivotYType Specifies how pivotYValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param pivotYValue The Y coordinate of the point about which the object
+     *        is being rotated, specified as an absolute number where 0 is the
+     *        top edge. This value can either be an absolute number if
+     *        pivotYType is ABSOLUTE, or a percentage (where 1.0 is 100%)
+     *        otherwise.
+     */
+    public RotateAnimation(float fromDegrees, float toDegrees, int pivotXType, float pivotXValue,
+            int pivotYType, float pivotYValue) {
+        mFromDegrees = fromDegrees;
+        mToDegrees = toDegrees;
+
+        mPivotXValue = pivotXValue;
+        mPivotXType = pivotXType;
+        mPivotYValue = pivotYValue;
+        mPivotYType = pivotYType;
+        initializePivotPoint();
+    }
+
+    /**
+     * Called at the end of constructor methods to initialize, if possible, values for
+     * the pivot point. This is only possible for ABSOLUTE pivot values.
+     */
+    private void initializePivotPoint() {
+        if (mPivotXType == ABSOLUTE) {
+            mPivotX = mPivotXValue;
+        }
+        if (mPivotYType == ABSOLUTE) {
+            mPivotY = mPivotYValue;
+        }
+    }
+
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        float degrees = mFromDegrees + ((mToDegrees - mFromDegrees) * interpolatedTime);
+        float scale = getScaleFactor();
+        
+        if (mPivotX == 0.0f && mPivotY == 0.0f) {
+            t.getMatrix().setRotate(degrees);
+        } else {
+            t.getMatrix().setRotate(degrees, mPivotX * scale, mPivotY * scale);
+        }
+    }
+
+    @Override
+    public void initialize(int width, int height, int parentWidth, int parentHeight) {
+        super.initialize(width, height, parentWidth, parentHeight);
+        mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
+        mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
+    }
+}
diff --git a/android/view/animation/ScaleAnimation.java b/android/view/animation/ScaleAnimation.java
new file mode 100644
index 0000000..e9a8436
--- /dev/null
+++ b/android/view/animation/ScaleAnimation.java
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+
+/**
+ * An animation that controls the scale of an object. You can specify the point
+ * to use for the center of scaling.
+ * 
+ */
+public class ScaleAnimation extends Animation {
+    private final Resources mResources;
+
+    private float mFromX;
+    private float mToX;
+    private float mFromY;
+    private float mToY;
+
+    private int mFromXType = TypedValue.TYPE_NULL;
+    private int mToXType = TypedValue.TYPE_NULL;
+    private int mFromYType = TypedValue.TYPE_NULL;
+    private int mToYType = TypedValue.TYPE_NULL;
+
+    private int mFromXData = 0;
+    private int mToXData = 0;
+    private int mFromYData = 0;
+    private int mToYData = 0;
+
+    private int mPivotXType = ABSOLUTE;
+    private int mPivotYType = ABSOLUTE;
+    private float mPivotXValue = 0.0f;
+    private float mPivotYValue = 0.0f;
+
+    private float mPivotX;
+    private float mPivotY;
+
+    /**
+     * Constructor used when a ScaleAnimation is loaded from a resource.
+     * 
+     * @param context Application context to use
+     * @param attrs Attribute set from which to read values
+     */
+    public ScaleAnimation(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        mResources = context.getResources();
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.ScaleAnimation);
+
+        TypedValue tv = a.peekValue(
+                com.android.internal.R.styleable.ScaleAnimation_fromXScale);
+        mFromX = 0.0f;
+        if (tv != null) {
+            if (tv.type == TypedValue.TYPE_FLOAT) {
+                // This is a scaling factor.
+                mFromX = tv.getFloat();
+            } else {
+                mFromXType = tv.type;
+                mFromXData = tv.data;
+            }
+        }
+        tv = a.peekValue(
+                com.android.internal.R.styleable.ScaleAnimation_toXScale);
+        mToX = 0.0f;
+        if (tv != null) {
+            if (tv.type == TypedValue.TYPE_FLOAT) {
+                // This is a scaling factor.
+                mToX = tv.getFloat();
+            } else {
+                mToXType = tv.type;
+                mToXData = tv.data;
+            }
+        }
+
+        tv = a.peekValue(
+                com.android.internal.R.styleable.ScaleAnimation_fromYScale);
+        mFromY = 0.0f;
+        if (tv != null) {
+            if (tv.type == TypedValue.TYPE_FLOAT) {
+                // This is a scaling factor.
+                mFromY = tv.getFloat();
+            } else {
+                mFromYType = tv.type;
+                mFromYData = tv.data;
+            }
+        }
+        tv = a.peekValue(
+                com.android.internal.R.styleable.ScaleAnimation_toYScale);
+        mToY = 0.0f;
+        if (tv != null) {
+            if (tv.type == TypedValue.TYPE_FLOAT) {
+                // This is a scaling factor.
+                mToY = tv.getFloat();
+            } else {
+                mToYType = tv.type;
+                mToYData = tv.data;
+            }
+        }
+
+        Description d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.ScaleAnimation_pivotX));
+        mPivotXType = d.type;
+        mPivotXValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+            com.android.internal.R.styleable.ScaleAnimation_pivotY));
+        mPivotYType = d.type;
+        mPivotYValue = d.value;
+
+        a.recycle();
+
+        initializePivotPoint();
+    }
+
+    /**
+     * Constructor to use when building a ScaleAnimation from code
+     * 
+     * @param fromX Horizontal scaling factor to apply at the start of the
+     *        animation
+     * @param toX Horizontal scaling factor to apply at the end of the animation
+     * @param fromY Vertical scaling factor to apply at the start of the
+     *        animation
+     * @param toY Vertical scaling factor to apply at the end of the animation
+     */
+    public ScaleAnimation(float fromX, float toX, float fromY, float toY) {
+        mResources = null;
+        mFromX = fromX;
+        mToX = toX;
+        mFromY = fromY;
+        mToY = toY;
+        mPivotX = 0;
+        mPivotY = 0;
+    }
+
+    /**
+     * Constructor to use when building a ScaleAnimation from code
+     * 
+     * @param fromX Horizontal scaling factor to apply at the start of the
+     *        animation
+     * @param toX Horizontal scaling factor to apply at the end of the animation
+     * @param fromY Vertical scaling factor to apply at the start of the
+     *        animation
+     * @param toY Vertical scaling factor to apply at the end of the animation
+     * @param pivotX The X coordinate of the point about which the object is
+     *        being scaled, specified as an absolute number where 0 is the left
+     *        edge. (This point remains fixed while the object changes size.)
+     * @param pivotY The Y coordinate of the point about which the object is
+     *        being scaled, specified as an absolute number where 0 is the top
+     *        edge. (This point remains fixed while the object changes size.)
+     */
+    public ScaleAnimation(float fromX, float toX, float fromY, float toY,
+            float pivotX, float pivotY) {
+        mResources = null;
+        mFromX = fromX;
+        mToX = toX;
+        mFromY = fromY;
+        mToY = toY;
+
+        mPivotXType = ABSOLUTE;
+        mPivotYType = ABSOLUTE;
+        mPivotXValue = pivotX;
+        mPivotYValue = pivotY;
+        initializePivotPoint();
+    }
+
+    /**
+     * Constructor to use when building a ScaleAnimation from code
+     * 
+     * @param fromX Horizontal scaling factor to apply at the start of the
+     *        animation
+     * @param toX Horizontal scaling factor to apply at the end of the animation
+     * @param fromY Vertical scaling factor to apply at the start of the
+     *        animation
+     * @param toY Vertical scaling factor to apply at the end of the animation
+     * @param pivotXType Specifies how pivotXValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param pivotXValue The X coordinate of the point about which the object
+     *        is being scaled, specified as an absolute number where 0 is the
+     *        left edge. (This point remains fixed while the object changes
+     *        size.) This value can either be an absolute number if pivotXType
+     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
+     * @param pivotYType Specifies how pivotYValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param pivotYValue The Y coordinate of the point about which the object
+     *        is being scaled, specified as an absolute number where 0 is the
+     *        top edge. (This point remains fixed while the object changes
+     *        size.) This value can either be an absolute number if pivotYType
+     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
+     */
+    public ScaleAnimation(float fromX, float toX, float fromY, float toY,
+            int pivotXType, float pivotXValue, int pivotYType, float pivotYValue) {
+        mResources = null;
+        mFromX = fromX;
+        mToX = toX;
+        mFromY = fromY;
+        mToY = toY;
+
+        mPivotXValue = pivotXValue;
+        mPivotXType = pivotXType;
+        mPivotYValue = pivotYValue;
+        mPivotYType = pivotYType;
+        initializePivotPoint();
+    }
+
+    /**
+     * Called at the end of constructor methods to initialize, if possible, values for
+     * the pivot point. This is only possible for ABSOLUTE pivot values.
+     */
+    private void initializePivotPoint() {
+        if (mPivotXType == ABSOLUTE) {
+            mPivotX = mPivotXValue;
+        }
+        if (mPivotYType == ABSOLUTE) {
+            mPivotY = mPivotYValue;
+        }
+    }
+
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        float sx = 1.0f;
+        float sy = 1.0f;
+        float scale = getScaleFactor();
+
+        if (mFromX != 1.0f || mToX != 1.0f) {
+            sx = mFromX + ((mToX - mFromX) * interpolatedTime);
+        }
+        if (mFromY != 1.0f || mToY != 1.0f) {
+            sy = mFromY + ((mToY - mFromY) * interpolatedTime);
+        }
+
+        if (mPivotX == 0 && mPivotY == 0) {
+            t.getMatrix().setScale(sx, sy);
+        } else {
+            t.getMatrix().setScale(sx, sy, scale * mPivotX, scale * mPivotY);
+        }
+    }
+
+    float resolveScale(float scale, int type, int data, int size, int psize) {
+        float targetSize;
+        if (type == TypedValue.TYPE_FRACTION) {
+            targetSize = TypedValue.complexToFraction(data, size, psize);
+        } else if (type == TypedValue.TYPE_DIMENSION) {
+            targetSize = TypedValue.complexToDimension(data, mResources.getDisplayMetrics());
+        } else {
+            return scale;
+        }
+
+        if (size == 0) {
+            return 1;
+        }
+
+        return targetSize/(float)size;
+    }
+
+    @Override
+    public void initialize(int width, int height, int parentWidth, int parentHeight) {
+        super.initialize(width, height, parentWidth, parentHeight);
+
+        mFromX = resolveScale(mFromX, mFromXType, mFromXData, width, parentWidth);
+        mToX = resolveScale(mToX, mToXType, mToXData, width, parentWidth);
+        mFromY = resolveScale(mFromY, mFromYType, mFromYData, height, parentHeight);
+        mToY = resolveScale(mToY, mToYType, mToYData, height, parentHeight);
+
+        mPivotX = resolveSize(mPivotXType, mPivotXValue, width, parentWidth);
+        mPivotY = resolveSize(mPivotYType, mPivotYValue, height, parentHeight);
+    }
+}
diff --git a/android/view/animation/Transformation.java b/android/view/animation/Transformation.java
new file mode 100644
index 0000000..cfc6e39
--- /dev/null
+++ b/android/view/animation/Transformation.java
@@ -0,0 +1,249 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.annotation.FloatRange;
+import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+
+import java.io.PrintWriter;
+
+/**
+ * Defines the transformation to be applied at
+ * one point in time of an Animation.
+ *
+ */
+public class Transformation {
+    /**
+     * Indicates a transformation that has no effect (alpha = 1 and identity matrix.)
+     */
+    public static final int TYPE_IDENTITY = 0x0;
+    /**
+     * Indicates a transformation that applies an alpha only (uses an identity matrix.)
+     */
+    public static final int TYPE_ALPHA = 0x1;
+    /**
+     * Indicates a transformation that applies a matrix only (alpha = 1.)
+     */
+    public static final int TYPE_MATRIX = 0x2;
+    /**
+     * Indicates a transformation that applies an alpha and a matrix.
+     */
+    public static final int TYPE_BOTH = TYPE_ALPHA | TYPE_MATRIX;
+
+    protected Matrix mMatrix;
+    protected float mAlpha;
+    protected int mTransformationType;
+
+    private boolean mHasClipRect;
+    private Rect mClipRect = new Rect();
+
+    /**
+     * Creates a new transformation with alpha = 1 and the identity matrix.
+     */
+    public Transformation() {
+        clear();
+    }
+
+    /**
+     * Reset the transformation to a state that leaves the object
+     * being animated in an unmodified state. The transformation type is
+     * {@link #TYPE_BOTH} by default.
+     */
+    public void clear() {
+        if (mMatrix == null) {
+            mMatrix = new Matrix();
+        } else {
+            mMatrix.reset();
+        }
+        mClipRect.setEmpty();
+        mHasClipRect = false;
+        mAlpha = 1.0f;
+        mTransformationType = TYPE_BOTH;
+    }
+
+    /**
+     * Indicates the nature of this transformation.
+     *
+     * @return {@link #TYPE_ALPHA}, {@link #TYPE_MATRIX},
+     *         {@link #TYPE_BOTH} or {@link #TYPE_IDENTITY}.
+     */
+    public int getTransformationType() {
+        return mTransformationType;
+    }
+
+    /**
+     * Sets the transformation type.
+     *
+     * @param transformationType One of {@link #TYPE_ALPHA},
+     *        {@link #TYPE_MATRIX}, {@link #TYPE_BOTH} or
+     *        {@link #TYPE_IDENTITY}.
+     */
+    public void setTransformationType(int transformationType) {
+        mTransformationType = transformationType;
+    }
+
+    /**
+     * Clones the specified transformation.
+     *
+     * @param t The transformation to clone.
+     */
+    public void set(Transformation t) {
+        mAlpha = t.getAlpha();
+        mMatrix.set(t.getMatrix());
+        if (t.mHasClipRect) {
+            setClipRect(t.getClipRect());
+        } else {
+            mHasClipRect = false;
+            mClipRect.setEmpty();
+        }
+        mTransformationType = t.getTransformationType();
+    }
+
+    /**
+     * Apply this Transformation to an existing Transformation, e.g. apply
+     * a scale effect to something that has already been rotated.
+     * @param t
+     */
+    public void compose(Transformation t) {
+        mAlpha *= t.getAlpha();
+        mMatrix.preConcat(t.getMatrix());
+        if (t.mHasClipRect) {
+            Rect bounds = t.getClipRect();
+            if (mHasClipRect) {
+                setClipRect(mClipRect.left + bounds.left, mClipRect.top + bounds.top,
+                        mClipRect.right + bounds.right, mClipRect.bottom + bounds.bottom);
+            } else {
+                setClipRect(bounds);
+            }
+        }
+    }
+    
+    /**
+     * Like {@link #compose(Transformation)} but does this.postConcat(t) of
+     * the transformation matrix.
+     * @hide
+     */
+    public void postCompose(Transformation t) {
+        mAlpha *= t.getAlpha();
+        mMatrix.postConcat(t.getMatrix());
+        if (t.mHasClipRect) {
+            Rect bounds = t.getClipRect();
+            if (mHasClipRect) {
+                setClipRect(mClipRect.left + bounds.left, mClipRect.top + bounds.top,
+                        mClipRect.right + bounds.right, mClipRect.bottom + bounds.bottom);
+            } else {
+                setClipRect(bounds);
+            }
+        }
+    }
+
+    /**
+     * @return The 3x3 Matrix representing the trnasformation to apply to the
+     * coordinates of the object being animated
+     */
+    public Matrix getMatrix() {
+        return mMatrix;
+    }
+    
+    /**
+     * Sets the degree of transparency
+     * @param alpha 1.0 means fully opaqe and 0.0 means fully transparent
+     */
+    public void setAlpha(@FloatRange(from=0.0, to=1.0) float alpha) {
+        mAlpha = alpha;
+    }
+
+    /**
+     * Sets the current Transform's clip rect
+     * @hide
+     */
+    public void setClipRect(Rect r) {
+        setClipRect(r.left, r.top, r.right, r.bottom);
+    }
+
+    /**
+     * Sets the current Transform's clip rect
+     * @hide
+     */
+    public void setClipRect(int l, int t, int r, int b) {
+        mClipRect.set(l, t, r, b);
+        mHasClipRect = true;
+    }
+
+    /**
+     * Returns the current Transform's clip rect
+     * @hide
+     */
+    public Rect getClipRect() {
+        return mClipRect;
+    }
+
+    /**
+     * Returns whether the current Transform's clip rect is set
+     * @hide
+     */
+    public boolean hasClipRect() {
+        return mHasClipRect;
+    }
+
+    /**
+     * @return The degree of transparency
+     */
+    public float getAlpha() {
+        return mAlpha;
+    }
+    
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder(64);
+        sb.append("Transformation");
+        toShortString(sb);
+        return sb.toString();
+    }
+    
+    /**
+     * Return a string representation of the transformation in a compact form.
+     */
+    public String toShortString() {
+        StringBuilder sb = new StringBuilder(64);
+        toShortString(sb);
+        return sb.toString();
+    }
+    
+    /**
+     * @hide
+     */
+    public void toShortString(StringBuilder sb) {
+        sb.append("{alpha="); sb.append(mAlpha);
+        sb.append(" matrix="); mMatrix.toShortString(sb);
+        sb.append('}');
+    }
+    
+    /**
+     * Print short string, to optimize dumping.
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public void printShortString(PrintWriter pw) {
+        pw.print("{alpha="); pw.print(mAlpha);
+        pw.print(" matrix=");
+        mMatrix.printShortString(pw);
+        pw.print('}');
+    }
+}
diff --git a/android/view/animation/TranslateAnimation.java b/android/view/animation/TranslateAnimation.java
new file mode 100644
index 0000000..ec55a02
--- /dev/null
+++ b/android/view/animation/TranslateAnimation.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2006 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 android.view.animation;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+
+/**
+ * An animation that controls the position of an object. See the
+ * {@link android.view.animation full package} description for details and
+ * sample code.
+ *
+ */
+public class TranslateAnimation extends Animation {
+    private int mFromXType = ABSOLUTE;
+    private int mToXType = ABSOLUTE;
+
+    private int mFromYType = ABSOLUTE;
+    private int mToYType = ABSOLUTE;
+
+    /** @hide */
+    @UnsupportedAppUsage
+    protected float mFromXValue = 0.0f;
+    /** @hide */
+    @UnsupportedAppUsage
+    protected float mToXValue = 0.0f;
+
+    /** @hide */
+    @UnsupportedAppUsage
+    protected float mFromYValue = 0.0f;
+    /** @hide */
+    @UnsupportedAppUsage
+    protected float mToYValue = 0.0f;
+
+    /** @hide */
+    protected float mFromXDelta;
+    /** @hide */
+    protected float mToXDelta;
+    /** @hide */
+    protected float mFromYDelta;
+    /** @hide */
+    protected float mToYDelta;
+
+    /**
+     * Constructor used when a TranslateAnimation is loaded from a resource.
+     *
+     * @param context Application context to use
+     * @param attrs Attribute set from which to read values
+     */
+    public TranslateAnimation(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.TranslateAnimation);
+
+        Description d = Description.parseValue(a.peekValue(
+            com.android.internal.R.styleable.TranslateAnimation_fromXDelta));
+        mFromXType = d.type;
+        mFromXValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+                com.android.internal.R.styleable.TranslateAnimation_toXDelta));
+        mToXType = d.type;
+        mToXValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+            com.android.internal.R.styleable.TranslateAnimation_fromYDelta));
+        mFromYType = d.type;
+        mFromYValue = d.value;
+
+        d = Description.parseValue(a.peekValue(
+            com.android.internal.R.styleable.TranslateAnimation_toYDelta));
+        mToYType = d.type;
+        mToYValue = d.value;
+
+        a.recycle();
+    }
+
+    /**
+     * Constructor to use when building a TranslateAnimation from code
+     *
+     * @param fromXDelta Change in X coordinate to apply at the start of the
+     *        animation
+     * @param toXDelta Change in X coordinate to apply at the end of the
+     *        animation
+     * @param fromYDelta Change in Y coordinate to apply at the start of the
+     *        animation
+     * @param toYDelta Change in Y coordinate to apply at the end of the
+     *        animation
+     */
+    public TranslateAnimation(float fromXDelta, float toXDelta, float fromYDelta, float toYDelta) {
+        mFromXValue = fromXDelta;
+        mToXValue = toXDelta;
+        mFromYValue = fromYDelta;
+        mToYValue = toYDelta;
+
+        mFromXType = ABSOLUTE;
+        mToXType = ABSOLUTE;
+        mFromYType = ABSOLUTE;
+        mToYType = ABSOLUTE;
+    }
+
+    /**
+     * Constructor to use when building a TranslateAnimation from code
+     * 
+     * @param fromXType Specifies how fromXValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param fromXValue Change in X coordinate to apply at the start of the
+     *        animation. This value can either be an absolute number if fromXType
+     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
+     * @param toXType Specifies how toXValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param toXValue Change in X coordinate to apply at the end of the
+     *        animation. This value can either be an absolute number if toXType
+     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
+     * @param fromYType Specifies how fromYValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param fromYValue Change in Y coordinate to apply at the start of the
+     *        animation. This value can either be an absolute number if fromYType
+     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
+     * @param toYType Specifies how toYValue should be interpreted. One of
+     *        Animation.ABSOLUTE, Animation.RELATIVE_TO_SELF, or
+     *        Animation.RELATIVE_TO_PARENT.
+     * @param toYValue Change in Y coordinate to apply at the end of the
+     *        animation. This value can either be an absolute number if toYType
+     *        is ABSOLUTE, or a percentage (where 1.0 is 100%) otherwise.
+     */
+    public TranslateAnimation(int fromXType, float fromXValue, int toXType, float toXValue,
+            int fromYType, float fromYValue, int toYType, float toYValue) {
+
+        mFromXValue = fromXValue;
+        mToXValue = toXValue;
+        mFromYValue = fromYValue;
+        mToYValue = toYValue;
+
+        mFromXType = fromXType;
+        mToXType = toXType;
+        mFromYType = fromYType;
+        mToYType = toYType;
+    }
+
+
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        float dx = mFromXDelta;
+        float dy = mFromYDelta;
+        if (mFromXDelta != mToXDelta) {
+            dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
+        }
+        if (mFromYDelta != mToYDelta) {
+            dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
+        }
+        t.getMatrix().setTranslate(dx, dy);
+    }
+
+    @Override
+    public void initialize(int width, int height, int parentWidth, int parentHeight) {
+        super.initialize(width, height, parentWidth, parentHeight);
+        mFromXDelta = resolveSize(mFromXType, mFromXValue, width, parentWidth);
+        mToXDelta = resolveSize(mToXType, mToXValue, width, parentWidth);
+        mFromYDelta = resolveSize(mFromYType, mFromYValue, height, parentHeight);
+        mToYDelta = resolveSize(mToYType, mToYValue, height, parentHeight);
+    }
+}
diff --git a/android/view/animation/TranslateXAnimation.java b/android/view/animation/TranslateXAnimation.java
new file mode 100644
index 0000000..d75323f
--- /dev/null
+++ b/android/view/animation/TranslateXAnimation.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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 android.view.animation;
+
+import android.graphics.Matrix;
+
+/**
+ * Special case of TranslateAnimation that translates only horizontally, picking up the
+ * vertical values from whatever is set on the Transformation already. When used in
+ * conjunction with a TranslateYAnimation, allows independent animation of x and y
+ * position.
+ * @hide
+ */
+public class TranslateXAnimation extends TranslateAnimation {
+    float[] mTmpValues = new float[9];
+
+    /**
+     * Constructor. Passes in 0 for the y parameters of TranslateAnimation
+     */
+    public TranslateXAnimation(float fromXDelta, float toXDelta) {
+        super(fromXDelta, toXDelta, 0, 0);
+    }
+
+    /**
+     * Constructor. Passes in 0 for the y parameters of TranslateAnimation
+     */
+    public TranslateXAnimation(int fromXType, float fromXValue, int toXType, float toXValue) {
+        super(fromXType, fromXValue, toXType, toXValue, ABSOLUTE, 0, ABSOLUTE, 0);
+    }
+
+    /**
+     * Calculates and sets x translation values on given transformation.
+     */
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        Matrix m = t.getMatrix();
+        m.getValues(mTmpValues);
+        float dx = mFromXDelta + ((mToXDelta - mFromXDelta) * interpolatedTime);
+        t.getMatrix().setTranslate(dx, mTmpValues[Matrix.MTRANS_Y]);
+    }
+}
diff --git a/android/view/animation/TranslateYAnimation.java b/android/view/animation/TranslateYAnimation.java
new file mode 100644
index 0000000..1a1dfbf
--- /dev/null
+++ b/android/view/animation/TranslateYAnimation.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 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 android.view.animation;
+
+import android.compat.annotation.UnsupportedAppUsage;
+import android.graphics.Matrix;
+
+/**
+ * Special case of TranslateAnimation that translates only vertically, picking up the
+ * horizontal values from whatever is set on the Transformation already. When used in
+ * conjunction with a TranslateXAnimation, allows independent animation of x and y
+ * position.
+ * @hide
+ */
+public class TranslateYAnimation extends TranslateAnimation {
+    float[] mTmpValues = new float[9];
+
+    /**
+     * Constructor. Passes in 0 for the x parameters of TranslateAnimation
+     */
+    public TranslateYAnimation(float fromYDelta, float toYDelta) {
+        super(0, 0, fromYDelta, toYDelta);
+    }
+
+    /**
+     * Constructor. Passes in 0 for the x parameters of TranslateAnimation
+     */
+    @UnsupportedAppUsage
+    public TranslateYAnimation(int fromYType, float fromYValue, int toYType, float toYValue) {
+        super(ABSOLUTE, 0, ABSOLUTE, 0, fromYType, fromYValue, toYType, toYValue);
+    }
+
+    /**
+     * Calculates and sets y translation values on given transformation.
+     */
+    @Override
+    protected void applyTransformation(float interpolatedTime, Transformation t) {
+        Matrix m = t.getMatrix();
+        m.getValues(mTmpValues);
+        float dy = mFromYDelta + ((mToYDelta - mFromYDelta) * interpolatedTime);
+        t.getMatrix().setTranslate(mTmpValues[Matrix.MTRANS_X], dy);
+    }
+}