summaryrefslogtreecommitdiff
path: root/android/view/animation
diff options
context:
space:
mode:
Diffstat (limited to 'android/view/animation')
-rw-r--r--android/view/animation/AccelerateDecelerateInterpolator.java49
-rw-r--r--android/view/animation/AccelerateInterpolator.java90
-rw-r--r--android/view/animation/AlphaAnimation.java89
-rw-r--r--android/view/animation/Animation.java1169
-rw-r--r--android/view/animation/AnimationSet.java524
-rw-r--r--android/view/animation/AnimationUtils.java402
-rw-r--r--android/view/animation/AnticipateInterpolator.java78
-rw-r--r--android/view/animation/AnticipateOvershootInterpolator.java108
-rw-r--r--android/view/animation/BaseInterpolator.java39
-rw-r--r--android/view/animation/BounceInterpolator.java61
-rw-r--r--android/view/animation/ClipRectAnimation.java68
-rw-r--r--android/view/animation/CycleInterpolator.java70
-rw-r--r--android/view/animation/DecelerateInterpolator.java86
-rw-r--r--android/view/animation/GridLayoutAnimationController.java424
-rw-r--r--android/view/animation/Interpolator.java31
-rw-r--r--android/view/animation/LayoutAnimationController.java437
-rw-r--r--android/view/animation/LinearInterpolator.java47
-rw-r--r--android/view/animation/OvershootInterpolator.java81
-rw-r--r--android/view/animation/PathInterpolator.java243
-rw-r--r--android/view/animation/RotateAnimation.java183
-rw-r--r--android/view/animation/ScaleAnimation.java289
-rw-r--r--android/view/animation/Transformation.java247
-rw-r--r--android/view/animation/TranslateAnimation.java178
-rw-r--r--android/view/animation/TranslateXAnimation.java55
-rw-r--r--android/view/animation/TranslateYAnimation.java55
25 files changed, 5103 insertions, 0 deletions
diff --git a/android/view/animation/AccelerateDecelerateInterpolator.java b/android/view/animation/AccelerateDecelerateInterpolator.java
new file mode 100644
index 00000000..21d5a5b8
--- /dev/null
+++ b/android/view/animation/AccelerateDecelerateInterpolator.java
@@ -0,0 +1,49 @@
+/*
+ * 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.util.AttributeSet;
+
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * An interpolator where the rate of change starts and ends slowly but
+ * accelerates through the middle.
+ */
+@HasNativeInterpolator
+public class AccelerateDecelerateInterpolator extends BaseInterpolator
+ implements NativeInterpolatorFactory {
+ 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 NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
+ }
+}
diff --git a/android/view/animation/AccelerateInterpolator.java b/android/view/animation/AccelerateInterpolator.java
new file mode 100644
index 00000000..6c8d7b19
--- /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.util.AttributeSet;
+
+import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * An interpolator where the rate of change starts out slowly and
+ * and then accelerates.
+ *
+ */
+@HasNativeInterpolator
+public class AccelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
+ 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 NativeInterpolatorFactoryHelper.createAccelerateInterpolator(mFactor);
+ }
+}
diff --git a/android/view/animation/AlphaAnimation.java b/android/view/animation/AlphaAnimation.java
new file mode 100644
index 00000000..c4d9afcc
--- /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 00000000..474db128
--- /dev/null
+++ b/android/view/animation/Animation.java
@@ -0,0 +1,1169 @@
+/*
+ * 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.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.RectF;
+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;
+
+ /**
+ * The animation listener to be notified when the animation starts, ends or repeats.
+ */
+ 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;
+
+ /**
+ * Don't animate the wallpaper.
+ */
+ private boolean mDetachWallpaper = false;
+
+ private boolean mMore = true;
+ private boolean mOneMoreTime = true;
+
+ RectF mPreviousRegion = new RectF();
+ RectF mRegion = new RectF();
+ Transformation mTransformation = new Transformation();
+ 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));
+
+ 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
+ */
+ 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() {
+ if (mListener != null) {
+ mListener.onAnimationStart(Animation.this);
+ }
+ }
+ };
+ mOnRepeat = new Runnable() {
+ public void run() {
+ if (mListener != null) {
+ mListener.onAnimationRepeat(Animation.this);
+ }
+ }
+ };
+ mOnEnd = new Runnable() {
+ public void run() {
+ if (mListener != null) {
+ mListener.onAnimationEnd(Animation.this);
+ }
+ }
+ };
+ }
+ 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.
+ */
+ public void setBackgroundColor(@ColorInt int bg) {
+ mBackgroundColor = bg;
+ }
+
+ /**
+ * 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
+ */
+ public void setDetachWallpaper(boolean detachWallpaper) {
+ mDetachWallpaper = detachWallpaper;
+ }
+
+ /**
+ * 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.
+ */
+ @ColorInt
+ public int getBackgroundColor() {
+ return mBackgroundColor;
+ }
+
+ /**
+ * Return value of {@link #setDetachWallpaper(boolean)}.
+ * @attr ref android.R.styleable#Animation_detachWallpaper
+ */
+ public boolean getDetachWallpaper() {
+ return mDetachWallpaper;
+ }
+
+ /**
+ * <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;
+ }
+
+ /**
+ * <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 (mListener != null) {
+ if (mListenerHandler == null) mListener.onAnimationStart(this);
+ else mListenerHandler.postAtFrontOfQueue(mOnStart);
+ }
+ }
+
+ private void fireAnimationRepeat() {
+ if (mListener != null) {
+ if (mListenerHandler == null) mListener.onAnimationRepeat(this);
+ else mListenerHandler.postAtFrontOfQueue(mOnRepeat);
+ }
+ }
+
+ private void fireAnimationEnd() {
+ if (mListener != null) {
+ if (mListenerHandler == null) mListener.onAnimationEnd(this);
+ else mListenerHandler.postAtFrontOfQueue(mOnEnd);
+ }
+ }
+
+ /**
+ * 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
+ */
+ 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
+ */
+ 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 00000000..767024ec
--- /dev/null
+++ b/android/view/animation/AnimationSet.java
@@ -0,0 +1,524 @@
+/*
+ * 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) {
+ if (mListener != null) {
+ mListener.onAnimationStart(this);
+ }
+ mStarted = true;
+ }
+
+ if (ended != mEnded) {
+ if (mListener != null) {
+ mListener.onAnimationEnd(this);
+ }
+ 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 00000000..f5c36139
--- /dev/null
+++ b/android/view/animation/AnimationUtils.java
@@ -0,0 +1,402 @@
+/*
+ * 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.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();
+ }
+ };
+
+ /** @hide */
+ public static void lockAnimationClock(long vsyncMillis) {
+ AnimationState state = sAnimationState.get();
+ state.animationClockLocked = true;
+ state.currentVsyncTimeMillis = vsyncMillis;
+ }
+
+ /** @hide */
+ 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 reference 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));
+ }
+
+ 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 {
+ 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 object reference 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 animation object reference 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 reference 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 00000000..7a837c37
--- /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.util.AttributeSet;
+
+import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * An interpolator where the change starts backward then flings forward.
+ */
+@HasNativeInterpolator
+public class AnticipateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
+ 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 NativeInterpolatorFactoryHelper.createAnticipateInterpolator(mTension);
+ }
+}
diff --git a/android/view/animation/AnticipateOvershootInterpolator.java b/android/view/animation/AnticipateOvershootInterpolator.java
new file mode 100644
index 00000000..9a75134a
--- /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.util.AttributeSet;
+
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * 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 NativeInterpolatorFactory {
+ 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 NativeInterpolatorFactoryHelper.createAnticipateOvershootInterpolator(mTension);
+ }
+}
diff --git a/android/view/animation/BaseInterpolator.java b/android/view/animation/BaseInterpolator.java
new file mode 100644
index 00000000..a78fa1ea
--- /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 00000000..909eaa4c
--- /dev/null
+++ b/android/view/animation/BounceInterpolator.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util.AttributeSet;
+
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * An interpolator where the change bounces at the end.
+ */
+@HasNativeInterpolator
+public class BounceInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
+ 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 NativeInterpolatorFactoryHelper.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 00000000..e194927e
--- /dev/null
+++ b/android/view/animation/ClipRectAnimation.java
@@ -0,0 +1,68 @@
+/*
+ * 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.graphics.Rect;
+
+/**
+ * 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 Rect mFromRect = new Rect();
+ protected Rect mToRect = new Rect();
+
+ /**
+ * 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");
+ }
+ mFromRect.set(fromClip);
+ mToRect.set(toClip);
+ }
+
+ /**
+ * 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) {
+ mFromRect.set(fromL, fromT, fromR, fromB);
+ mToRect.set(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;
+ }
+}
diff --git a/android/view/animation/CycleInterpolator.java b/android/view/animation/CycleInterpolator.java
new file mode 100644
index 00000000..72d64a16
--- /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.util.AttributeSet;
+
+import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * Repeats the animation for a specified number of cycles. The
+ * rate of change follows a sinusoidal pattern.
+ *
+ */
+@HasNativeInterpolator
+public class CycleInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
+ 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 NativeInterpolatorFactoryHelper.createCycleInterpolator(mCycles);
+ }
+}
diff --git a/android/view/animation/DecelerateInterpolator.java b/android/view/animation/DecelerateInterpolator.java
new file mode 100644
index 00000000..f89743c1
--- /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.util.AttributeSet;
+
+import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * An interpolator where the rate of change starts out quickly and
+ * and then decelerates.
+ *
+ */
+@HasNativeInterpolator
+public class DecelerateInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
+ 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 makes 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 NativeInterpolatorFactoryHelper.createDecelerateInterpolator(mFactor);
+ }
+}
diff --git a/android/view/animation/GridLayoutAnimationController.java b/android/view/animation/GridLayoutAnimationController.java
new file mode 100644
index 00000000..0f189ae9
--- /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 00000000..5d0fe7ef
--- /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 00000000..7fa49c1a
--- /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 00000000..2a047b48
--- /dev/null
+++ b/android/view/animation/LinearInterpolator.java
@@ -0,0 +1,47 @@
+/*
+ * 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.util.AttributeSet;
+
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * An interpolator where the rate of change is constant
+ */
+@HasNativeInterpolator
+public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
+
+ public LinearInterpolator() {
+ }
+
+ public LinearInterpolator(Context context, AttributeSet attrs) {
+ }
+
+ public float getInterpolation(float input) {
+ return input;
+ }
+
+ /** @hide */
+ @Override
+ public long createNativeInterpolator() {
+ return NativeInterpolatorFactoryHelper.createLinearInterpolator();
+ }
+}
diff --git a/android/view/animation/OvershootInterpolator.java b/android/view/animation/OvershootInterpolator.java
new file mode 100644
index 00000000..306688a1
--- /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.util.AttributeSet;
+
+import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * An interpolator where the change flings forward and overshoots the last value
+ * then comes back.
+ */
+@HasNativeInterpolator
+public class OvershootInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
+ 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 NativeInterpolatorFactoryHelper.createOvershootInterpolator(mTension);
+ }
+}
diff --git a/android/view/animation/PathInterpolator.java b/android/view/animation/PathInterpolator.java
new file mode 100644
index 00000000..924437a2
--- /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.util.AttributeSet;
+import android.util.PathParser;
+import android.view.InflateException;
+
+import com.android.internal.R;
+import com.android.internal.view.animation.HasNativeInterpolator;
+import com.android.internal.view.animation.NativeInterpolatorFactory;
+import com.android.internal.view.animation.NativeInterpolatorFactoryHelper;
+
+/**
+ * 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 NativeInterpolatorFactory {
+
+ // 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 NativeInterpolatorFactoryHelper.createPathInterpolator(mX, mY);
+ }
+
+}
diff --git a/android/view/animation/RotateAnimation.java b/android/view/animation/RotateAnimation.java
new file mode 100644
index 00000000..3c325d9b
--- /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 00000000..e9a84364
--- /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 00000000..8eb5b5cf
--- /dev/null
+++ b/android/view/animation/Transformation.java
@@ -0,0 +1,247 @@
+/*
+ * 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.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
+ */
+ 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 00000000..216022b2
--- /dev/null
+++ b/android/view/animation/TranslateAnimation.java
@@ -0,0 +1,178 @@
+/*
+ * 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 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 */
+ protected float mFromXValue = 0.0f;
+ /** @hide */
+ protected float mToXValue = 0.0f;
+
+ /** @hide */
+ protected float mFromYValue = 0.0f;
+ /** @hide */
+ 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 00000000..d75323f2
--- /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 00000000..714558dc
--- /dev/null
+++ b/android/view/animation/TranslateYAnimation.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 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
+ */
+ 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);
+ }
+}