Merge "Don't get stung!"
diff --git a/api/current.xml b/api/current.xml
index 384ca18..9e86f01 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -19851,8 +19851,6 @@
deprecated="not deprecated"
visibility="public"
>
-<exception name="CloneNotSupportedException" type="java.lang.CloneNotSupportedException">
-</exception>
</method>
<method name="end"
return="void"
@@ -19865,6 +19863,17 @@
visibility="public"
>
</method>
+<method name="getDuration"
+ return="long"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getListeners"
return="java.util.ArrayList<android.animation.Animatable.AnimatableListener>"
abstract="false"
@@ -19876,6 +19885,17 @@
visibility="public"
>
</method>
+<method name="getStartDelay"
+ return="long"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isRunning"
return="boolean"
abstract="true"
@@ -19911,6 +19931,80 @@
<parameter name="listener" type="android.animation.Animatable.AnimatableListener">
</parameter>
</method>
+<method name="setDuration"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="setInterpolator"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="value" type="android.view.animation.Interpolator">
+</parameter>
+</method>
+<method name="setStartDelay"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startDelay" type="long">
+</parameter>
+</method>
+<method name="setTarget"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="target" type="java.lang.Object">
+</parameter>
+</method>
+<method name="setupEndValues"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setupStartValues"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="start"
return="void"
abstract="false"
@@ -20230,6 +20324,17 @@
visibility="public"
>
</method>
+<method name="getValues"
+ return="android.animation.PropertyValuesHolder[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isRunning"
return="boolean"
abstract="false"
@@ -20566,6 +20671,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.lang.Cloneable">
+</implements>
<constructor name="Keyframe"
type="android.animation.Keyframe"
static="false"
@@ -20587,6 +20694,42 @@
>
<parameter name="fraction" type="float">
</parameter>
+<parameter name="value" type="java.lang.Float">
+</parameter>
+</constructor>
+<constructor name="Keyframe"
+ type="android.animation.Keyframe"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fraction" type="float">
+</parameter>
+<parameter name="value" type="java.lang.Integer">
+</parameter>
+</constructor>
+<constructor name="Keyframe"
+ type="android.animation.Keyframe"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fraction" type="float">
+</parameter>
+<parameter name="value" type="java.lang.Double">
+</parameter>
+</constructor>
+<constructor name="Keyframe"
+ type="android.animation.Keyframe"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fraction" type="float">
+</parameter>
<parameter name="value" type="int">
</parameter>
</constructor>
@@ -20614,6 +20757,17 @@
<parameter name="value" type="double">
</parameter>
</constructor>
+<method name="clone"
+ return="android.animation.Keyframe"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getFraction"
return="float"
abstract="false"
@@ -20698,6 +20852,333 @@
</parameter>
</method>
</class>
+<class name="LayoutTransition"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="LayoutTransition"
+ type="android.animation.LayoutTransition"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="addTransitionListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.animation.LayoutTransition.TransitionListener">
+</parameter>
+</method>
+<method name="childAdd"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
+<method name="childRemove"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="parent" type="android.view.ViewGroup">
+</parameter>
+<parameter name="child" type="android.view.View">
+</parameter>
+</method>
+<method name="getAnimatable"
+ return="android.animation.Animatable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+</method>
+<method name="getDuration"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+</method>
+<method name="getInterpolator"
+ return="android.view.animation.Interpolator"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+</method>
+<method name="getStagger"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+</method>
+<method name="getStartDelay"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+</method>
+<method name="getTransitionListeners"
+ return="java.util.List<android.animation.LayoutTransition.TransitionListener>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="removeTransitionListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.animation.LayoutTransition.TransitionListener">
+</parameter>
+</method>
+<method name="setAnimatable"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+<parameter name="animatable" type="android.animation.Animatable">
+</parameter>
+</method>
+<method name="setDuration"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="setDuration"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="setInterpolator"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+<parameter name="interpolator" type="android.view.animation.Interpolator">
+</parameter>
+</method>
+<method name="setStagger"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="setStartDelay"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transitionType" type="int">
+</parameter>
+<parameter name="delay" type="long">
+</parameter>
+</method>
+<field name="APPEARING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANGE_APPEARING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="CHANGE_DISAPPEARING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="DISAPPEARING"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
+<interface name="LayoutTransition.TransitionListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="endTransition"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transition" type="android.animation.LayoutTransition">
+</parameter>
+<parameter name="container" type="android.view.ViewGroup">
+</parameter>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="transitionType" type="int">
+</parameter>
+</method>
+<method name="startTransition"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transition" type="android.animation.LayoutTransition">
+</parameter>
+<parameter name="container" type="android.view.ViewGroup">
+</parameter>
+<parameter name="view" type="android.view.View">
+</parameter>
+<parameter name="transitionType" type="int">
+</parameter>
+</method>
+</interface>
<class name="PropertyAnimator"
extends="android.animation.Animator"
abstract="false"
@@ -20779,19 +21260,6 @@
<parameter name="propertyName" type="java.lang.String">
</parameter>
</method>
-<method name="setTarget"
- return="void"
- abstract="false"
- native="false"
- synchronized="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-<parameter name="target" type="java.lang.Object">
-</parameter>
-</method>
</class>
<class name="PropertyValuesHolder"
extends="java.lang.Object"
@@ -20801,6 +21269,8 @@
deprecated="not deprecated"
visibility="public"
>
+<implements name="java.lang.Cloneable">
+</implements>
<constructor name="PropertyValuesHolder"
type="android.animation.PropertyValuesHolder"
static="false"
@@ -20823,6 +21293,17 @@
<parameter name="values" type="T...">
</parameter>
</constructor>
+<method name="clone"
+ return="android.animation.PropertyValuesHolder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getGetter"
return="java.lang.reflect.Method"
abstract="false"
@@ -20985,6 +21466,28 @@
visibility="public"
>
</method>
+<method name="getDuration"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getStartDelay"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="isRunning"
return="boolean"
abstract="false"
@@ -21035,7 +21538,7 @@
<parameter name="sequenceItems" type="android.animation.Animatable...">
</parameter>
</method>
-<method name="setTarget"
+<method name="setDuration"
return="void"
abstract="false"
native="false"
@@ -21045,7 +21548,33 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="target" type="java.lang.Object">
+<parameter name="duration" type="long">
+</parameter>
+</method>
+<method name="setInterpolator"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="interpolator" type="android.view.animation.Interpolator">
+</parameter>
+</method>
+<method name="setStartDelay"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="startDelay" type="long">
</parameter>
</method>
</class>
@@ -194495,6 +195024,19 @@
<parameter name="focusableMode" type="int">
</parameter>
</method>
+<method name="addOnLayoutChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.view.View.OnLayoutChangeListener">
+</parameter>
+</method>
<method name="addTouchables"
return="void"
abstract="false"
@@ -195584,6 +196126,17 @@
visibility="public"
>
</method>
+<method name="getOnLayoutChangeListeners"
+ return="java.util.List<android.view.View.OnLayoutChangeListener>"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
<method name="getPaddingBottom"
return="int"
abstract="false"
@@ -197188,6 +197741,19 @@
<parameter name="action" type="java.lang.Runnable">
</parameter>
</method>
+<method name="removeOnLayoutChangeListener"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="listener" type="android.view.View.OnLayoutChangeListener">
+</parameter>
+</method>
<method name="requestFocus"
return="boolean"
abstract="false"
@@ -197456,6 +198022,19 @@
<parameter name="resid" type="int">
</parameter>
</method>
+<method name="setBottom"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="bottom" type="int">
+</parameter>
+</method>
<method name="setClickable"
return="void"
abstract="false"
@@ -197664,6 +198243,19 @@
<parameter name="params" type="android.view.ViewGroup.LayoutParams">
</parameter>
</method>
+<method name="setLeft"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="left" type="int">
+</parameter>
+</method>
<method name="setLongClickable"
return="void"
abstract="false"
@@ -197906,6 +198498,19 @@
<parameter name="pressed" type="boolean">
</parameter>
</method>
+<method name="setRight"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="right" type="int">
+</parameter>
+</method>
<method name="setRotation"
return="void"
abstract="false"
@@ -198090,6 +198695,19 @@
<parameter name="tag" type="java.lang.Object">
</parameter>
</method>
+<method name="setTop"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="top" type="int">
+</parameter>
+</method>
<method name="setTouchDelegate"
return="void"
abstract="false"
@@ -199152,6 +199770,43 @@
</parameter>
</method>
</interface>
+<interface name="View.OnLayoutChangeListener"
+ abstract="true"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="onLayoutChange"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="v" type="android.view.View">
+</parameter>
+<parameter name="left" type="int">
+</parameter>
+<parameter name="top" type="int">
+</parameter>
+<parameter name="right" type="int">
+</parameter>
+<parameter name="bottom" type="int">
+</parameter>
+<parameter name="oldLeft" type="int">
+</parameter>
+<parameter name="oldTop" type="int">
+</parameter>
+<parameter name="oldRight" type="int">
+</parameter>
+<parameter name="oldBottom" type="int">
+</parameter>
+</method>
+</interface>
<interface name="View.OnLongClickListener"
abstract="true"
static="true"
@@ -200980,6 +201635,19 @@
<parameter name="animationListener" type="android.view.animation.Animation.AnimationListener">
</parameter>
</method>
+<method name="setLayoutTransition"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="transition" type="android.animation.LayoutTransition">
+</parameter>
+</method>
<method name="setMotionEventSplittingEnabled"
return="void"
abstract="false"
diff --git a/core/java/android/animation/Animatable.java b/core/java/android/animation/Animatable.java
index d6cf7c0..3fdf200 100644
--- a/core/java/android/animation/Animatable.java
+++ b/core/java/android/animation/Animatable.java
@@ -16,6 +16,8 @@
package android.animation;
+import android.view.animation.Interpolator;
+
import java.util.ArrayList;
/**
@@ -56,6 +58,46 @@
public void end() {
}
+ /**
+ * The amount of time, in milliseconds, to delay starting the animation after
+ * {@link #start()} is called.
+ *
+ * @return the number of milliseconds to delay running the animation
+ */
+ public abstract long getStartDelay();
+
+ /**
+ * The amount of time, in milliseconds, to delay starting the animation after
+ * {@link #start()} is called.
+
+ * @param startDelay The amount of the delay, in milliseconds
+ */
+ public abstract void setStartDelay(long startDelay);
+
+
+ /**
+ * Sets the length of the animation.
+ *
+ * @param duration The length of the animation, in milliseconds.
+ */
+ public abstract void setDuration(long duration);
+
+ /**
+ * Gets the length of the animation.
+ *
+ * @return The length of the animation, in milliseconds.
+ */
+ public abstract long getDuration();
+
+ /**
+ * The time interpolator used in calculating the elapsed fraction of this animation. The
+ * interpolator determines whether the animation runs with linear or non-linear motion,
+ * such as acceleration and deceleration. The default value is
+ * {@link android.view.animation.AccelerateDecelerateInterpolator}
+ *
+ * @param value the interpolator to be used by this animation
+ */
+ public abstract void setInterpolator(Interpolator value);
/**
* Returns whether this Animatable is currently running (having been started and not yet ended).
@@ -115,17 +157,56 @@
}
@Override
- public Animatable clone() throws CloneNotSupportedException {
- final Animatable anim = (Animatable) super.clone();
- if (mListeners != null) {
- ArrayList<AnimatableListener> oldListeners = mListeners;
- anim.mListeners = new ArrayList<AnimatableListener>();
- int numListeners = oldListeners.size();
- for (int i = 0; i < numListeners; ++i) {
- anim.mListeners.add(oldListeners.get(i));
+ public Animatable clone() {
+ try {
+ final Animatable anim = (Animatable) super.clone();
+ if (mListeners != null) {
+ ArrayList<AnimatableListener> oldListeners = mListeners;
+ anim.mListeners = new ArrayList<AnimatableListener>();
+ int numListeners = oldListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ anim.mListeners.add(oldListeners.get(i));
+ }
}
+ return anim;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError();
}
- return anim;
+ }
+
+ /**
+ * This method tells the object to use appropriate information to extract
+ * starting values for the animation. For example, a Sequencer object will pass
+ * this call to its child objects to tell them to set up the values. A
+ * PropertyAnimator object will use the information it has about its target object
+ * and PropertyValuesHolder objects to get the start values for its properties.
+ * An Animator object will ignore the request since it does not have enough
+ * information (such as a target object) to gather these values.
+ */
+ public void setupStartValues() {
+ }
+
+ /**
+ * This method tells the object to use appropriate information to extract
+ * ending values for the animation. For example, a Sequencer object will pass
+ * this call to its child objects to tell them to set up the values. A
+ * PropertyAnimator object will use the information it has about its target object
+ * and PropertyValuesHolder objects to get the start values for its properties.
+ * An Animator object will ignore the request since it does not have enough
+ * information (such as a target object) to gather these values.
+ */
+ public void setupEndValues() {
+ }
+
+ /**
+ * Sets the target object whose property will be animated by this animation. Not all subclasses
+ * operate on target objects (for example, {@link android.animation.Animator}, but this method
+ * is on the superclass for the convenience of dealing generically with those subclasses
+ * that do handle targets.
+ *
+ * @param target The object being animated
+ */
+ public void setTarget(Object target) {
}
/**
diff --git a/core/java/android/animation/AnimatableListenerAdapter.java b/core/java/android/animation/AnimatableListenerAdapter.java
index 25a842b..c169b28 100644
--- a/core/java/android/animation/AnimatableListenerAdapter.java
+++ b/core/java/android/animation/AnimatableListenerAdapter.java
@@ -26,28 +26,28 @@
public abstract class AnimatableListenerAdapter implements AnimatableListener {
/**
- * @{inheritdoc}
+ * {@inheritdoc}
*/
@Override
public void onAnimationCancel(Animatable animation) {
}
/**
- * @{inheritdoc}
+ * {@inheritdoc}
*/
@Override
public void onAnimationEnd(Animatable animation) {
}
/**
- * @{inheritdoc}
+ * {@inheritdoc}
*/
@Override
public void onAnimationRepeat(Animatable animation) {
}
/**
- * @{inheritdoc}
+ * {@inheritdoc}
*/
@Override
public void onAnimationStart(Animatable animation) {
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 8b74658..8e947ec 100755
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -145,10 +145,10 @@
private static final ArrayList<Animator> sReadyAnims = new ArrayList<Animator>();
/**
- * Flag that denotes whether the animation is set up and ready to go. Used by seek() to
+ * Flag that denotes whether the animation is set up and ready to go. Used to
* set up animation that has not yet been started.
*/
- private boolean mInitialized = false;
+ boolean mInitialized = false;
//
// Backing variables
@@ -243,6 +243,14 @@
}
}
+ /**
+ * Sets the values, per property, being animated between. This function is called internally
+ * by the constructors of Animator that take a list of values. But an Animator can
+ * be constructed without values and this method can be called to set the values manually
+ * instead.
+ *
+ * @param values The set of values, per property, being animated between.
+ */
public void setValues(PropertyValuesHolder... values) {
int numValues = values.length;
mValues = values;
@@ -254,6 +262,18 @@
}
/**
+ * Returns the values that this Animator animates between. These values are stored in
+ * PropertyValuesHolder objects, even if the Animator was created with a simple list
+ * of value objects instead.
+ *
+ * @return PropertyValuesHolder[] An array of PropertyValuesHolder objects which hold the
+ * values, per property, that define the animation.
+ */
+ public PropertyValuesHolder[] getValues() {
+ return mValues;
+ }
+
+ /**
* Sets the values to animate between for this animation. If <code>values</code> is
* a set of PropertyValuesHolder objects, these objects will become the set of properties
* animated and the values that those properties are animated between. Otherwise, this method
@@ -286,12 +306,14 @@
* that internal mechanisms for the animation are set up correctly.</p>
*/
void initAnimation() {
- int numValues = mValues.length;
- for (int i = 0; i < numValues; ++i) {
- mValues[i].init();
+ if (!mInitialized) {
+ int numValues = mValues.length;
+ for (int i = 0; i < numValues; ++i) {
+ mValues[i].init();
+ }
+ mCurrentIteration = 0;
+ mInitialized = true;
}
- mCurrentIteration = 0;
- mInitialized = true;
}
@@ -324,9 +346,7 @@
* @param playTime The time, in milliseconds, to which the animation is advanced or rewound.
*/
public void setCurrentPlayTime(long playTime) {
- if (!mInitialized) {
- initAnimation();
- }
+ initAnimation();
long currentTime = AnimationUtils.currentAnimationTimeMillis();
if (mPlayingState != RUNNING) {
mSeekTime = playTime;
@@ -619,6 +639,7 @@
*
* @param value the interpolator to be used by this animation
*/
+ @Override
public void setInterpolator(Interpolator value) {
if (value != null) {
mInterpolator = value;
@@ -783,6 +804,10 @@
* should be added to the set of active animations.
*/
private boolean delayedAnimationFrame(long currentTime) {
+ if (mPlayingState == CANCELED || mPlayingState == ENDED) {
+ // end the delay, process an animation frame to actually cancel it
+ return true;
+ }
if (!mStartedDelay) {
mStartedDelay = true;
mDelayStartTime = currentTime;
@@ -898,7 +923,7 @@
}
@Override
- public Animator clone() throws CloneNotSupportedException {
+ public Animator clone() {
final Animator anim = (Animator) super.clone();
if (mUpdateListeners != null) {
ArrayList<AnimatorUpdateListener> oldListeners = mUpdateListeners;
@@ -919,7 +944,7 @@
int numValues = oldValues.length;
anim.mValues = new PropertyValuesHolder[numValues];
for (int i = 0; i < numValues; ++i) {
- anim.mValues[i] = oldValues[i];
+ anim.mValues[i] = oldValues[i].clone();
}
anim.mValuesMap = new HashMap<String, PropertyValuesHolder>(numValues);
for (int i = 0; i < numValues; ++i) {
diff --git a/core/java/android/animation/Keyframe.java b/core/java/android/animation/Keyframe.java
index e2800b3..7d4d104 100644
--- a/core/java/android/animation/Keyframe.java
+++ b/core/java/android/animation/Keyframe.java
@@ -26,7 +26,7 @@
* next keyframe. Each keyframe also holds an option {@link android.view.animation.Interpolator}
* object, which defines the time interpolation over the intervalue preceding the keyframe.
*/
-public class Keyframe {
+public class Keyframe implements Cloneable {
/**
* The time at which mValue will hold true.
*/
@@ -81,7 +81,55 @@
* this keyframe.
*/
public Keyframe(float fraction, Object value) {
- this(fraction, value, Object.class);
+ this(fraction, value, (value != null) ? value.getClass() : Object.class);
+ }
+
+ /**
+ * Constructs a Keyframe object with the given time and float value. The time defines the
+ * time, as a proportion of an overall animation's duration, at which the value will hold true
+ * for the animation. The value for the animation between keyframes will be calculated as
+ * an interpolation between the values at those keyframes.
+ *
+ * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+ * of time elapsed of the overall animation duration.
+ * @param value The value that the object will animate to as the animation time approaches
+ * the time in this keyframe, and the the value animated from as the time passes the time in
+ * this keyframe.
+ */
+ public Keyframe(float fraction, Float value) {
+ this(fraction, value, Float.class);
+ }
+
+ /**
+ * Constructs a Keyframe object with the given time and integer value. The time defines the
+ * time, as a proportion of an overall animation's duration, at which the value will hold true
+ * for the animation. The value for the animation between keyframes will be calculated as
+ * an interpolation between the values at those keyframes.
+ *
+ * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+ * of time elapsed of the overall animation duration.
+ * @param value The value that the object will animate to as the animation time approaches
+ * the time in this keyframe, and the the value animated from as the time passes the time in
+ * this keyframe.
+ */
+ public Keyframe(float fraction, Integer value) {
+ this(fraction, value, Integer.class);
+ }
+
+ /**
+ * Constructs a Keyframe object with the given time and double value. The time defines the
+ * time, as a proportion of an overall animation's duration, at which the value will hold true
+ * for the animation. The value for the animation between keyframes will be calculated as
+ * an interpolation between the values at those keyframes.
+ *
+ * @param fraction The time, expressed as a value between 0 and 1, representing the fraction
+ * of time elapsed of the overall animation duration.
+ * @param value The value that the object will animate to as the animation time approaches
+ * the time in this keyframe, and the the value animated from as the time passes the time in
+ * this keyframe.
+ */
+ public Keyframe(float fraction, Double value) {
+ this(fraction, value, Double.class);
}
/**
@@ -200,4 +248,11 @@
public Class getType() {
return mValueType;
}
+
+ @Override
+ public Keyframe clone() {
+ Keyframe kfClone = new Keyframe(mFraction, mValue, mValueType);
+ kfClone.setInterpolator(mInterpolator);
+ return kfClone;
+ }
}
diff --git a/core/java/android/animation/LayoutTransition.java b/core/java/android/animation/LayoutTransition.java
new file mode 100644
index 0000000..5dfdfbd
--- /dev/null
+++ b/core/java/android/animation/LayoutTransition.java
@@ -0,0 +1,778 @@
+/*
+ * Copyright (C) 2010 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.animation;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewTreeObserver;
+import android.view.animation.AccelerateDecelerateInterpolator;
+import android.view.animation.DecelerateInterpolator;
+import android.view.animation.Interpolator;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * This class enables automatic animations on layout changes in ViewGroup objects. To enable
+ * transitions for a layout container, create a LayoutTransition object and set it on any
+ * ViewGroup by calling {@link ViewGroup#setLayoutTransition(LayoutTransition)}. This will cause
+ * default animations to run whenever items are added to or removed from that container. To specify
+ * custom animations, use the {@link LayoutTransition#setAnimatable(int, Animatable)
+ * setAnimatable()} method.
+ *
+ * <p>One of the core concepts of these transition animations is that there are two core
+ * changes that cause the transition and four different animations that run because of
+ * those changes. The changes that trigger the transition are items being added to a container
+ * (referred to as an "appearing" transition) or removed from a container (also known as
+ * "disappearing"). The animations that run due to those events are one that animates
+ * items being added, one that animates items being removed, and two that animate the other
+ * items in the container that change due to the add/remove occurrence. Users of
+ * the transition may want different animations for the changing items depending on whether
+ * they are changing due to anappearing or disappearing event, so there is one animation for
+ * each of these variations of the changing event. Most of the API of this class is concerned
+ * with setting up the basic properties of the animations used in these four situations,
+ * or with setting up custom animations for any or all of the four.</p>
+ *
+ * <p>The animations specified for the transition, both the defaults and any custom animations
+ * set on the transition object, are templates only. That is, these animations exist to hold the
+ * basic animation properties, such as the duration, start delay, and properties being animated.
+ * But the actual target object, as well as the start and end values for those properties, are
+ * set automatically in the process of setting up the transition each time it runs. Each of the
+ * animations is cloned from the original copy and the clone is then populated with the dynamic
+ * values of the target being animated (such as one of the items in a layout container that is
+ * moving as a result of the layout event) as well as the values that are changing (such as the
+ * position and size of that object). The actual values that are pushed to each animation
+ * depends on what properties are specified for the animation. For example, the default
+ * CHANGE_APPEARING animation animates <code>left</code>, <code>top</code>, <code>right</code>,
+ * and <code>bottom</code>. Values for these properties are updated with the pre- and post-layout
+ * values when the transition begins. Custom animations will be similarly populated with
+ * the target and values being animated, assuming they use PropertyAnimator objects with
+ * property names that are known on the target object.</p>
+ */
+public class LayoutTransition {
+
+ /**
+ * A flag indicating the animation that runs on those items that are changing
+ * due to a new item appearing in the container.
+ */
+ public static final int CHANGE_APPEARING = 0;
+
+ /**
+ * A flag indicating the animation that runs on those items that are changing
+ * due to a new item disappearing from the container.
+ */
+ public static final int CHANGE_DISAPPEARING = 1;
+
+ /**
+ * A flag indicating the animation that runs on those items that are changing
+ * due to a new item appearing in the container.
+ */
+ public static final int APPEARING = 2;
+
+ /**
+ * A flag indicating the animation that runs on those items that are changing
+ * due to a new item appearing in the container.
+ */
+ public static final int DISAPPEARING = 3;
+
+ /**
+ * These variables hold the animations that are currently used to run the transition effects.
+ * These animations are set to defaults, but can be changed to custom animations by
+ * calls to setAnimatable().
+ */
+ private Animatable mDisappearingAnim = null;
+ private Animatable mAppearingAnim = null;
+ private Animatable mChangingAppearingAnim = null;
+ private Animatable mChangingDisappearingAnim = null;
+
+ /**
+ * These are the default animations, defined in the constructor, that will be used
+ * unless the user specifies custom animations.
+ */
+ private static PropertyAnimator defaultChangeIn;
+ private static PropertyAnimator defaultChangeOut;
+ private static PropertyAnimator defaultFadeIn;
+ private static PropertyAnimator defaultFadeOut;
+
+ /**
+ * The default duration used by all animations.
+ */
+ private static long DEFAULT_DURATION = 300;
+
+ /**
+ * The durations of the four different animations
+ */
+ private long mChangingAppearingDuration = DEFAULT_DURATION;
+ private long mChangingDisappearingDuration = DEFAULT_DURATION;
+ private long mAppearingDuration = DEFAULT_DURATION;
+ private long mDisappearingDuration = DEFAULT_DURATION;
+
+ /**
+ * The start delays of the four different animations. Note that the default behavior of
+ * the appearing item is the default duration, since it should wait for the items to move
+ * before fading it. Same for the changing animation when disappearing; it waits for the item
+ * to fade out before moving the other items.
+ */
+ private long mAppearingDelay = DEFAULT_DURATION;
+ private long mDisappearingDelay = 0;
+ private long mChangingAppearingDelay = 0;
+ private long mChangingDisappearingDelay = DEFAULT_DURATION;
+
+ /**
+ * The inter-animation delays used on the two changing animations
+ */
+ private long mChangingAppearingStagger = 0;
+ private long mChangingDisappearingStagger = 0;
+
+ /**
+ * The default interpolators used for the animations
+ */
+ private Interpolator mAppearingInterpolator = new AccelerateDecelerateInterpolator();
+ private Interpolator mDisappearingInterpolator = new AccelerateDecelerateInterpolator();
+ private Interpolator mChangingAppearingInterpolator = new DecelerateInterpolator();
+ private Interpolator mChangingDisappearingInterpolator = new DecelerateInterpolator();
+
+ /**
+ * This hashmap is used to store the animations that are currently running as part of
+ * the transition. The reason for this is that a further layout event should cause
+ * existing animations to stop where they are prior to starting new animations. So
+ * we cache all of the current animations in this map for possible cancellation on
+ * another layout event.
+ */
+ private HashMap<View, Animatable> currentAnimations = new HashMap<View, Animatable>();
+
+ /**
+ * This hashmap is used to track the listeners that have been added to the children of
+ * a container. When a layout change occurs, an animation is created for each View, so that
+ * the pre-layout values can be cached in that animation. Then a listener is added to the
+ * view to see whether the layout changes the bounds of that view. If so, the animation
+ * is set with the final values and then run. If not, the animation is not started. When
+ * the process of setting up and running all appropriate animations is done, we need to
+ * remove these listeners and clear out the map.
+ */
+ private HashMap<View, View.OnLayoutChangeListener> layoutChangeListenerMap =
+ new HashMap<View, View.OnLayoutChangeListener>();
+
+ /**
+ * Used to track the current delay being assigned to successive animations as they are
+ * started. This value is incremented for each new animation, then zeroed before the next
+ * transition begins.
+ */
+ private long staggerDelay;
+
+ /**
+ * The set of listeners that should be notified when APPEARING/DISAPPEARING transitions
+ * start and end.
+ */
+ private ArrayList<TransitionListener> mListeners;
+
+
+ /**
+ * Constructs a LayoutTransition object. By default, the object will listen to layout
+ * events on any ViewGroup that it is set on and will run default animations for each
+ * type of layout event.
+ */
+ public LayoutTransition() {
+ if (defaultChangeIn == null) {
+ // "left" is just a placeholder; we'll put real properties/values in when needed
+ PropertyValuesHolder<Integer> pvhLeft = new PropertyValuesHolder<Integer>("left", 0, 1);
+ PropertyValuesHolder<Integer> pvhTop = new PropertyValuesHolder<Integer>("top", 0, 1);
+ PropertyValuesHolder<Integer> pvhRight = new PropertyValuesHolder<Integer>("right", 0, 1);
+ PropertyValuesHolder<Integer> pvhBottom = new PropertyValuesHolder<Integer>("bottom", 0, 1);
+ defaultChangeIn = new PropertyAnimator<PropertyValuesHolder>(DEFAULT_DURATION, this,
+ pvhLeft, pvhTop, pvhRight, pvhBottom);
+ defaultChangeIn.setStartDelay(mChangingAppearingDelay);
+ defaultChangeIn.setInterpolator(mChangingAppearingInterpolator);
+ defaultChangeOut = defaultChangeIn.clone();
+ defaultChangeOut.setStartDelay(mChangingDisappearingDelay);
+ defaultChangeOut.setInterpolator(mChangingDisappearingInterpolator);
+ defaultFadeIn =
+ new PropertyAnimator<Float>(DEFAULT_DURATION, this, "alpha", 0f, 1f);
+ defaultFadeIn.setStartDelay(mAppearingDelay);
+ defaultFadeIn.setInterpolator(mAppearingInterpolator);
+ defaultFadeOut =
+ new PropertyAnimator<Float>(DEFAULT_DURATION, this, "alpha", 1f, 0f);
+ defaultFadeOut.setStartDelay(mDisappearingDelay);
+ defaultFadeOut.setInterpolator(mDisappearingInterpolator);
+ }
+ mChangingAppearingAnim = defaultChangeIn;
+ mChangingDisappearingAnim = defaultChangeOut;
+ mAppearingAnim = defaultFadeIn;
+ mDisappearingAnim = defaultFadeOut;
+ }
+
+ /**
+ * Sets the duration to be used by all animations of this transition object. If you want to
+ * set the duration of just one of the animations in particular, use the
+ * {@link #setDuration(int, long)} method.
+ *
+ * @param duration The length of time, in milliseconds, that the transition animations
+ * should last.
+ */
+ public void setDuration(long duration) {
+ mChangingAppearingDuration = duration;
+ mChangingDisappearingDuration = duration;
+ mAppearingDuration = duration;
+ mDisappearingDuration = duration;
+ }
+
+ /**
+ * Sets the start delay on one of the animation objects used by this transition. The
+ * <code>transitionType</code> parameter determines the animation whose start delay
+ * is being set.
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
+ * delay is being set.
+ * @param delay The length of time, in milliseconds, to delay before starting the animation.
+ * @see android.animation.Animatable#setStartDelay(long)
+ */
+ public void setStartDelay(int transitionType, long delay) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ mChangingAppearingDelay = delay;
+ break;
+ case CHANGE_DISAPPEARING:
+ mChangingDisappearingDelay = delay;
+ break;
+ case APPEARING:
+ mAppearingDelay = delay;
+ break;
+ case DISAPPEARING:
+ mDisappearingDelay = delay;
+ break;
+ }
+ }
+
+ /**
+ * Gets the start delay on one of the animation objects used by this transition. The
+ * <code>transitionType</code> parameter determines the animation whose start delay
+ * is returned.
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose start
+ * delay is returned.
+ * @return long The start delay of the specified animation.
+ * @see android.animation.Animatable#getStartDelay()
+ */
+ public long getStartDelay(int transitionType) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ return mChangingAppearingDuration;
+ case CHANGE_DISAPPEARING:
+ return mChangingDisappearingDuration;
+ case APPEARING:
+ return mAppearingDuration;
+ case DISAPPEARING:
+ return mDisappearingDuration;
+ }
+ // shouldn't reach here
+ return 0;
+ }
+
+ /**
+ * Sets the duration on one of the animation objects used by this transition. The
+ * <code>transitionType</code> parameter determines the animation whose duration
+ * is being set.
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
+ * duration is being set.
+ * @param duration The length of time, in milliseconds, that the specified animation should run.
+ * @see android.animation.Animatable#setDuration(long)
+ */
+ public void setDuration(int transitionType, long duration) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ mChangingAppearingDuration = duration;
+ break;
+ case CHANGE_DISAPPEARING:
+ mChangingDisappearingDuration = duration;
+ break;
+ case APPEARING:
+ mAppearingDuration = duration;
+ break;
+ case DISAPPEARING:
+ mDisappearingDuration = duration;
+ break;
+ }
+ }
+
+ /**
+ * Gets the duration on one of the animation objects used by this transition. The
+ * <code>transitionType</code> parameter determines the animation whose duration
+ * is returned.
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
+ * duration is returned.
+ * @return long The duration of the specified animation.
+ * @see android.animation.Animatable#getDuration()
+ */
+ public long getDuration(int transitionType) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ return mChangingAppearingDuration;
+ case CHANGE_DISAPPEARING:
+ return mChangingDisappearingDuration;
+ case APPEARING:
+ return mAppearingDuration;
+ case DISAPPEARING:
+ return mDisappearingDuration;
+ }
+ // shouldn't reach here
+ return 0;
+ }
+
+ /**
+ * Sets the length of time to delay between starting each animation during one of the
+ * CHANGE animations.
+ *
+ * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
+ * @param duration The length of time, in milliseconds, to delay before launching the next
+ * animation in the sequence.
+ */
+ public void setStagger(int transitionType, long duration) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ mChangingAppearingStagger = duration;
+ break;
+ case CHANGE_DISAPPEARING:
+ mChangingDisappearingStagger = duration;
+ break;
+ // noop other cases
+ }
+ }
+
+ /**
+ * Tets the length of time to delay between starting each animation during one of the
+ * CHANGE animations.
+ *
+ * @param transitionType A value of {@link #CHANGE_APPEARING} or @link #CHANGE_DISAPPEARING}.
+ * @return long The length of time, in milliseconds, to delay before launching the next
+ * animation in the sequence.
+ */
+ public long getStagger(int transitionType) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ return mChangingAppearingStagger;
+ case CHANGE_DISAPPEARING:
+ return mChangingDisappearingStagger;
+ }
+ // shouldn't reach here
+ return 0;
+ }
+
+ /**
+ * Sets the interpolator on one of the animation objects used by this transition. The
+ * <code>transitionType</code> parameter determines the animation whose interpolator
+ * is being set.
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
+ * duration is being set.
+ * @param interpolator The interpolator that the specified animation should use.
+ * @see android.animation.Animatable#setInterpolator(android.view.animation.Interpolator)
+ */
+ public void setInterpolator(int transitionType, Interpolator interpolator) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ mChangingAppearingInterpolator = interpolator;
+ break;
+ case CHANGE_DISAPPEARING:
+ mChangingDisappearingInterpolator = interpolator;
+ break;
+ case APPEARING:
+ mAppearingInterpolator = interpolator;
+ break;
+ case DISAPPEARING:
+ mDisappearingInterpolator = interpolator;
+ break;
+ }
+ }
+
+ /**
+ * Gets the interpolator on one of the animation objects used by this transition. The
+ * <code>transitionType</code> parameter determines the animation whose interpolator
+ * is returned.
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
+ * duration is being set.
+ * @return Interpolator The interpolator that the specified animation uses.
+ * @see android.animation.Animatable#setInterpolator(android.view.animation.Interpolator)
+ */
+ public Interpolator getInterpolator(int transitionType) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ return mChangingAppearingInterpolator;
+ case CHANGE_DISAPPEARING:
+ return mChangingDisappearingInterpolator;
+ case APPEARING:
+ return mAppearingInterpolator;
+ case DISAPPEARING:
+ return mDisappearingInterpolator;
+ }
+ // shouldn't reach here
+ return null;
+ }
+
+ /**
+ * Sets the animation used during one of the transition types that may run. Any
+ * Animatable object can be used, but to be most useful in the context of layout
+ * transitions, the animation should either be a PropertyAnimator or a Sequencer
+ * of animations including PropertyAnimators. Also, these PropertyAnimator objects
+ * should be able to get and set values on their target objects automatically. For
+ * example, a PropertyAnimator that animates the property "left" is able to set and get the
+ * <code>left</code> property from the View objects being animated by the layout
+ * transition. The transition works by setting target objects and properties
+ * dynamically, according to the pre- and post-layoout values of those objects, so
+ * having animations that can handle those properties appropriately will work best
+ * for custom animation. The dynamic setting of values is only the case for the
+ * CHANGE animations; the APPEARING and DISAPPEARING animations are simply run with
+ * the values they have.
+ *
+ * <p>It is also worth noting that any and all animations (and their underlying
+ * PropertyValuesHolder objects) will have their start and end values set according
+ * to the pre- and post-layout values. So, for example, a custom animation on "alpha"
+ * as the CHANGE_APPEARING animation will inherit the real value of alpha on the target
+ * object (presumably 1) as its starting and ending value when the animation begins.
+ * Animations which need to use values at the beginning and end that may not match the
+ * values queried when the transition begins may need to use a different mechanism
+ * than a standard PropertyAnimator object.</p>
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
+ * duration is being set.
+ * @param animatable The animation being assigned.
+ */
+ public void setAnimatable(int transitionType, Animatable animatable) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ mChangingAppearingAnim = (animatable != null) ? animatable : defaultChangeIn;
+ break;
+ case CHANGE_DISAPPEARING:
+ mChangingDisappearingAnim = (animatable != null) ? animatable : defaultChangeOut;
+ break;
+ case APPEARING:
+ mAppearingAnim = (animatable != null) ? animatable : defaultFadeIn;
+ break;
+ case DISAPPEARING:
+ mDisappearingAnim = (animatable != null) ? animatable : defaultFadeOut;
+ break;
+ }
+ }
+
+ /**
+ * Gets the animation used during one of the transition types that may run.
+ *
+ * @param transitionType one of {@link #CHANGE_APPEARING}, {@link #CHANGE_DISAPPEARING},
+ * {@link #APPEARING}, or {@link #DISAPPEARING}, which determines the animation whose
+ * duration is being set.
+ * @return Animatable The animation being used for the given transition type.
+ * @see #setAnimatable(int, Animatable)
+ */
+ public Animatable getAnimatable(int transitionType) {
+ switch (transitionType) {
+ case CHANGE_APPEARING:
+ return mChangingAppearingAnim;
+ case CHANGE_DISAPPEARING:
+ return mChangingDisappearingAnim;
+ case APPEARING:
+ return mAppearingAnim;
+ case DISAPPEARING:
+ return mDisappearingAnim;
+ }
+ // shouldn't reach here
+ return null;
+ }
+
+ /**
+ * This function sets up runs animations on all of the views that change during layout.
+ * For every child in the parent, we create a change animation of the appropriate
+ * type (appearing or disappearing) and ask it to populate its start values from its
+ * target view. We add layout listeners to all child views and listen for changes. For
+ * those views that change, we populate the end values for those animations and start them.
+ * Animations are not run on unchanging views.
+ *
+ * @param parent The container which is undergoing an appearing or disappearing change.
+ * @param newView The view being added to or removed from the parent.
+ * @param changeReason A value of APPEARING or DISAPPEARING, indicating whether the
+ * transition is occuring because an item is being added to or removed from the parent.
+ */
+ private void runChangeTransition(final ViewGroup parent, View newView, final int changeReason) {
+ // reset the inter-animation delay, in case we use it later
+ staggerDelay = 0;
+
+ final ViewTreeObserver observer = parent.getViewTreeObserver(); // used for later cleanup
+ int numChildren = parent.getChildCount();
+
+ for (int i = 0; i < numChildren; ++i) {
+ final View child = parent.getChildAt(i);
+
+ // only animate the views not being added or removed
+ if (child != newView) {
+
+ // If there's an animation running on this view already, cancel it
+ Animatable currentAnimation = currentAnimations.get(child);
+ if (currentAnimation != null) {
+ currentAnimation.cancel();
+ currentAnimations.remove(child);
+ }
+
+ // Make a copy of the appropriate animation
+ final Animatable anim = (changeReason == APPEARING) ?
+ mChangingAppearingAnim.clone() :
+ mChangingDisappearingAnim.clone();
+
+ // Set the target object for the animation
+ anim.setTarget(child);
+
+ // A PropertyAnimator (or Sequencer of them) can extract start values from
+ // its target object
+ anim.setupStartValues();
+
+ // Add a listener to track layout changes on this view. If we don't get a callback,
+ // then there's nothing to animate.
+ View.OnLayoutChangeListener listener = new View.OnLayoutChangeListener() {
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+
+ // Cache the animation in case we need to cancel it later
+ currentAnimations.put(child, anim);
+
+ // Tell the animation to extract end values from the changed object
+ anim.setupEndValues();
+
+ long startDelay;
+ long duration;
+ if (changeReason == APPEARING) {
+ startDelay = mChangingAppearingDelay + staggerDelay;
+ staggerDelay += mChangingAppearingStagger;
+ duration = mChangingAppearingDuration;
+ } else {
+ startDelay = mChangingDisappearingDelay + staggerDelay;
+ staggerDelay += mChangingDisappearingStagger;
+ duration = mChangingDisappearingDuration;
+ }
+ anim.setStartDelay(startDelay);
+ anim.setDuration(duration);
+
+ // Remove the animation from the cache when it ends
+ anim.addListener(new AnimatableListenerAdapter() {
+ private boolean canceled = false;
+ public void onAnimationCancel(Animatable animatable) {
+ // we remove canceled animations immediately, not here
+ canceled = true;
+ }
+ public void onAnimationEnd(Animatable animatable) {
+ if (!canceled) {
+ currentAnimations.remove(child);
+ }
+ }
+ });
+ if (anim instanceof PropertyAnimator) {
+ ((PropertyAnimator) anim).setCurrentPlayTime(0);
+ }
+ anim.start();
+
+ // this only removes listeners whose views changed - must clear the
+ // other listeners later
+ child.removeOnLayoutChangeListener(this);
+ layoutChangeListenerMap.remove(child);
+ }
+ };
+ child.addOnLayoutChangeListener(listener);
+ // cache the listener for later removal
+ layoutChangeListenerMap.put(child, listener);
+ }
+ }
+ // This is the cleanup step. When we get this rendering event, we know that all of
+ // the appropriate animations have been set up and run. Now we can clear out the
+ // layout listeners.
+ observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ public boolean onPreDraw() {
+ observer.removeOnPreDrawListener(this);
+ int numChildren = parent.getChildCount();
+ for (int i = 0; i < numChildren; ++i) {
+ final View child = parent.getChildAt(i);
+ child.removeOnLayoutChangeListener(layoutChangeListenerMap.get(child));
+ }
+ layoutChangeListenerMap.clear();
+ return true;
+ }
+ });
+ }
+
+ /**
+ * This method runs the animation that makes an added item appear.
+ *
+ * @param parent The ViewGroup to which the View is being added.
+ * @param child The View being added to the ViewGroup.
+ */
+ private void runAppearingTransition(final ViewGroup parent, final View child) {
+ Animatable anim = mAppearingAnim.clone();
+ anim.setTarget(child);
+ anim.setStartDelay(mAppearingDelay);
+ anim.setDuration(mAppearingDuration);
+ if (anim instanceof PropertyAnimator) {
+ ((PropertyAnimator) anim).setCurrentPlayTime(0);
+ }
+ if (mListeners != null) {
+ anim.addListener(new AnimatableListenerAdapter() {
+ public void onAnimationEnd() {
+ for (TransitionListener listener : mListeners) {
+ listener.endTransition(LayoutTransition.this, parent, child, APPEARING);
+ }
+ }
+ });
+ }
+ anim.start();
+ }
+
+ /**
+ * This method runs the animation that makes a removed item disappear.
+ *
+ * @param parent The ViewGroup from which the View is being removed.
+ * @param child The View being removed from the ViewGroup.
+ */
+ private void runDisappearingTransition(final ViewGroup parent, final View child) {
+ Animatable anim = mDisappearingAnim.clone();
+ anim.setStartDelay(mDisappearingDelay);
+ anim.setDuration(mDisappearingDuration);
+ anim.setTarget(child);
+ if (mListeners != null) {
+ anim.addListener(new AnimatableListenerAdapter() {
+ public void onAnimationEnd() {
+ for (TransitionListener listener : mListeners) {
+ listener.endTransition(LayoutTransition.this, parent, child, DISAPPEARING);
+ }
+ }
+ });
+ }
+ if (anim instanceof PropertyAnimator) {
+ ((PropertyAnimator) anim).setCurrentPlayTime(0);
+ }
+ anim.start();
+ }
+
+ /**
+ * This method is called by ViewGroup when a child view is about to be added to the
+ * container. This callback starts the process of a transition; we grab the starting
+ * values, listen for changes to all of the children of the container, and start appropriate
+ * animations.
+ *
+ * @param parent The ViewGroup to which the View is being added.
+ * @param child The View being added to the ViewGroup.
+ */
+ public void childAdd(ViewGroup parent, View child) {
+ if (mListeners != null) {
+ for (TransitionListener listener : mListeners) {
+ listener.startTransition(this, parent, child, APPEARING);
+ }
+ }
+ runChangeTransition(parent, child, APPEARING);
+ runAppearingTransition(parent, child);
+ }
+
+ /**
+ * This method is called by ViewGroup when a child view is about to be removed from the
+ * container. This callback starts the process of a transition; we grab the starting
+ * values, listen for changes to all of the children of the container, and start appropriate
+ * animations.
+ *
+ * @param parent The ViewGroup from which the View is being removed.
+ * @param child The View being removed from the ViewGroup.
+ */
+ public void childRemove(ViewGroup parent, View child) {
+ if (mListeners != null) {
+ for (TransitionListener listener : mListeners) {
+ listener.startTransition(this, parent, child, DISAPPEARING);
+ }
+ }
+ runChangeTransition(parent, child, DISAPPEARING);
+ runDisappearingTransition(parent, child);
+ }
+
+ /**
+ * Add a listener that will be called when the bounds of the view change due to
+ * layout processing.
+ *
+ * @param listener The listener that will be called when layout bounds change.
+ */
+ public void addTransitionListener(TransitionListener listener) {
+ if (mListeners == null) {
+ mListeners = new ArrayList<TransitionListener>();
+ }
+ mListeners.add(listener);
+ }
+
+ /**
+ * Remove a listener for layout changes.
+ *
+ * @param listener The listener for layout bounds change.
+ */
+ public void removeTransitionListener(TransitionListener listener) {
+ if (mListeners == null) {
+ return;
+ }
+ mListeners.remove(listener);
+ }
+
+ /**
+ * Gets the current list of listeners for layout changes.
+ * @return
+ */
+ public List<TransitionListener> getTransitionListeners() {
+ return mListeners;
+ }
+
+ /**
+ * This interface is used for listening to starting and ending events for transitions.
+ */
+ public interface TransitionListener {
+
+ /**
+ * This event is sent to listeners when an APPEARING or DISAPPEARING transition
+ * begins.
+ *
+ * @param transition The LayoutTransition sending out the event.
+ * @param container The ViewGroup on which the transition is playing.
+ * @param view The View object being added or removed from its parent.
+ * @param transitionType The type of transition that is beginning, either
+ * {@link android.animation.LayoutTransition#APPEARING} or
+ * {@link android.animation.LayoutTransition#DISAPPEARING}.
+ */
+ public void startTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType);
+
+ /**
+ * This event is sent to listeners when an APPEARING or DISAPPEARING transition ends.
+ *
+ * @param transition The LayoutTransition sending out the event.
+ * @param container The ViewGroup on which the transition is playing.
+ * @param view The View object being added or removed from its parent.
+ * @param transitionType The type of transition that is ending, either
+ * {@link android.animation.LayoutTransition#APPEARING} or
+ * {@link android.animation.LayoutTransition#DISAPPEARING}.
+ */
+ public void endTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType);
+ }
+
+}
\ No newline at end of file
diff --git a/core/java/android/animation/PropertyAnimator.java b/core/java/android/animation/PropertyAnimator.java
index 8a6edcc..e555cc6 100644
--- a/core/java/android/animation/PropertyAnimator.java
+++ b/core/java/android/animation/PropertyAnimator.java
@@ -168,10 +168,14 @@
*/
@Override
void initAnimation() {
- super.initAnimation();
- int numValues = mValues.length;
- for (int i = 0; i < numValues; ++i) {
- mValues[i].setupSetterAndGetter(mTarget);
+ if (!mInitialized) {
+ // mValueType may change due to setter/getter setup; do this before calling super.init(),
+ // which uses mValueType to set up the default type evaluator.
+ int numValues = mValues.length;
+ for (int i = 0; i < numValues; ++i) {
+ mValues[i].setupSetterAndGetter(mTarget);
+ }
+ super.initAnimation();
}
}
@@ -190,10 +194,29 @@
*
* @param target The object being animated
*/
+ @Override
public void setTarget(Object target) {
mTarget = target;
}
+ @Override
+ public void setupStartValues() {
+ initAnimation();
+ int numValues = mValues.length;
+ for (int i = 0; i < numValues; ++i) {
+ mValues[i].setupStartValue(mTarget);
+ }
+ }
+
+ @Override
+ public void setupEndValues() {
+ initAnimation();
+ int numValues = mValues.length;
+ for (int i = 0; i < numValues; ++i) {
+ mValues[i].setupEndValue(mTarget);
+ }
+ }
+
/**
* This method is called with the elapsed fraction of the animation during every
* animation frame. This function turns the elapsed fraction into an interpolated fraction
@@ -216,7 +239,7 @@
}
@Override
- public PropertyAnimator clone() throws CloneNotSupportedException {
+ public PropertyAnimator clone() {
final PropertyAnimator anim = (PropertyAnimator) super.clone();
return anim;
}
diff --git a/core/java/android/animation/PropertyValuesHolder.java b/core/java/android/animation/PropertyValuesHolder.java
index fc829b8..b6ff54e 100644
--- a/core/java/android/animation/PropertyValuesHolder.java
+++ b/core/java/android/animation/PropertyValuesHolder.java
@@ -25,8 +25,12 @@
import java.util.concurrent.locks.ReentrantReadWriteLock;
/**
+ * This class holds information about a property and the values that that property
+ * should take on during an animation. PropertyValuesHolder objects can be used to create
+ * animations with Animator or PropertyAnimator that operate on several different properties
+ * in parallel.
*/
-public class PropertyValuesHolder<T> {
+public class PropertyValuesHolder<T> implements Cloneable {
/**
* The name of the property associated with the values. This need not be a real property,
@@ -192,7 +196,7 @@
}
} else {
if (numKeyframes == 1) {
- keyframes[0] = new Keyframe(0f, null);
+ keyframes[0] = new Keyframe(0f, (Object) null);
keyframes[1] = new Keyframe(1f, values[0]);
} else {
keyframes[0] = new Keyframe(0f, values[0]);
@@ -256,6 +260,8 @@
args[0] = typeVariant;
try {
returnVal = targetClass.getMethod(methodName, args);
+ // change the value type to suit
+ mValueType = typeVariant;
return returnVal;
} catch (NoSuchMethodException e) {
// Swallow the error and keep trying other variants
@@ -356,6 +362,63 @@
}
/**
+ * Utility function to set the value stored in a particular Keyframe. The value used is
+ * whatever the value is for the property name specified in the keyframe on the target object.
+ *
+ * @param target The target object from which the current value should be extracted.
+ * @param kf The keyframe which holds the property name and value.
+ */
+ private void setupValue(Object target, Keyframe kf) {
+ try {
+ if (mGetter == null) {
+ Class targetClass = target.getClass();
+ setupGetter(targetClass);
+ }
+ kf.setValue((T) mGetter.invoke(target));
+ } catch (InvocationTargetException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ } catch (IllegalAccessException e) {
+ Log.e("PropertyValuesHolder", e.toString());
+ }
+ }
+
+ /**
+ * This function is called by PropertyAnimator when setting the start values for an animation.
+ * The start values are set according to the current values in the target object. The
+ * property whose value is extracted is whatever is specified by the propertyName of this
+ * PropertyValuesHolder object.
+ *
+ * @param target The object which holds the start values that should be set.
+ */
+ void setupStartValue(Object target) {
+ setupValue(target, mKeyframeSet.mKeyframes.get(0));
+ }
+
+ /**
+ * This function is called by PropertyAnimator when setting the end values for an animation.
+ * The end values are set according to the current values in the target object. The
+ * property whose value is extracted is whatever is specified by the propertyName of this
+ * PropertyValuesHolder object.
+ *
+ * @param target The object which holds the start values that should be set.
+ */
+ void setupEndValue(Object target) {
+ setupValue(target, mKeyframeSet.mKeyframes.get(mKeyframeSet.mKeyframes.size() - 1));
+ }
+
+ @Override
+ public PropertyValuesHolder clone() {
+ ArrayList<Keyframe> keyframes = mKeyframeSet.mKeyframes;
+ int numKeyframes = mKeyframeSet.mKeyframes.size();
+ Keyframe[] newKeyframes = new Keyframe[numKeyframes];
+ for (int i = 0; i < numKeyframes; ++i) {
+ newKeyframes[i] = keyframes.get(i).clone();
+ }
+ PropertyValuesHolder pvhClone = new PropertyValuesHolder(mPropertyName,
+ (Object[]) newKeyframes);
+ return pvhClone;
+ }
+ /**
* Internal function to set the value on the target object, using the setter set up
* earlier on this PropertyValuesHolder object. This function is called by PropertyAnimator
* to handle turning the value calculated by Animator into a value set on the object
@@ -381,8 +444,9 @@
*/
void init() {
if (mEvaluator == null) {
- mEvaluator = (mValueType == int.class) ? sIntEvaluator :
- (mValueType == double.class) ? sDoubleEvaluator : sFloatEvaluator;
+ mEvaluator = (mValueType == int.class || mValueType == Integer.class) ? sIntEvaluator :
+ (mValueType == double.class || mValueType == Double.class) ? sDoubleEvaluator :
+ sFloatEvaluator;
}
}
diff --git a/core/java/android/animation/Sequencer.java b/core/java/android/animation/Sequencer.java
index 8779b3d..04bede0 100644
--- a/core/java/android/animation/Sequencer.java
+++ b/core/java/android/animation/Sequencer.java
@@ -20,6 +20,7 @@
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
import java.util.ArrayList;
import java.util.HashMap;
@@ -96,6 +97,16 @@
*/
boolean mCanceled = false;
+ // The amount of time in ms to delay starting the animation after start() is called
+ private long mStartDelay = 0;
+
+
+ // How long the child animations should last in ms. The default value is negative, which
+ // simply means that there is no duration set on the Sequencer. When a real duration is
+ // set, it is passed along to the child animations.
+ private long mDuration = -1;
+
+
/**
* Sets up this Sequencer to play all of the supplied animations at the same time.
*
@@ -153,6 +164,7 @@
*
* @param target The object being animated
*/
+ @Override
public void setTarget(Object target) {
for (Node node : mNodes) {
Animatable animation = node.animation;
@@ -165,6 +177,19 @@
}
/**
+ * Sets the Interpolator for all current {@link #getChildAnimations() child animations}
+ * of this Sequencer.
+ *
+ * @param interpolator the interpolator to be used by each child animation of this Sequencer
+ */
+ @Override
+ public void setInterpolator(Interpolator interpolator) {
+ for (Node node : mNodes) {
+ node.animation.setInterpolator(interpolator);
+ }
+ }
+
+ /**
* This method creates a <code>Builder</code> object, which is used to
* set up playing constraints. This initial <code>play()</code> method
* tells the <code>Builder</code> the animation that is the dependency for
@@ -266,6 +291,62 @@
}
/**
+ * The amount of time, in milliseconds, to delay starting the animation after
+ * {@link #start()} is called.
+ *
+ * @return the number of milliseconds to delay running the animation
+ */
+ @Override
+ public long getStartDelay() {
+ return mStartDelay;
+ }
+
+ /**
+ * The amount of time, in milliseconds, to delay starting the animation after
+ * {@link #start()} is called.
+
+ * @param startDelay The amount of the delay, in milliseconds
+ */
+ @Override
+ public void setStartDelay(long startDelay) {
+ mStartDelay = startDelay;
+ }
+
+ /**
+ * Gets the length of each of the child animations of this Sequencer. This value may
+ * be less than 0, which indicates that no duration has been set on this Sequencer
+ * and each of the child animations will use their own duration.
+ *
+ * @return The length of the animation, in milliseconds, of each of the child
+ * animations of this Sequencer.
+ */
+ @Override
+ public long getDuration() {
+ return mDuration;
+ }
+
+ /**
+ * Sets the length of each of the current child animations of this Sequencer. By default,
+ * each child animation will use its own duration. If the duration is set on the Sequencer,
+ * then each child animation inherits this duration.
+ *
+ * @param duration The length of the animation, in milliseconds, of each of the child
+ * animations of this Sequencer.
+ */
+ @Override
+ public void setDuration(long duration) {
+ if (duration < 0) {
+ throw new IllegalArgumentException("duration must be a value of zero or greater");
+ }
+ for (Node node : mNodes) {
+ // TODO: don't set the duration of the timing-only nodes created by Sequencer to
+ // insert "play-after" delays
+ node.animation.setDuration(duration);
+ }
+ mDuration = duration;
+ }
+
+ /**
* {@inheritDoc}
*
* <p>Starting this <code>Sequencer</code> will, in turn, start the animations for which
@@ -285,7 +366,7 @@
// start the animations in the loop directly because we first need to set up
// dependencies on all of the nodes. For example, we don't want to start an animation
// when some other animation also wants to start when the first animation begins.
- ArrayList<Node> nodesToStart = new ArrayList<Node>();
+ final ArrayList<Node> nodesToStart = new ArrayList<Node>();
for (Node node : mSortedNodes) {
if (mSequenceListener == null) {
mSequenceListener = new SequencerAnimatableListener(this);
@@ -302,9 +383,22 @@
node.animation.addListener(mSequenceListener);
}
// Now that all dependencies are set up, start the animations that should be started.
- for (Node node : nodesToStart) {
- node.animation.start();
- mPlayingSet.add(node.animation);
+ if (mStartDelay <= 0) {
+ for (Node node : nodesToStart) {
+ node.animation.start();
+ mPlayingSet.add(node.animation);
+ }
+ } else {
+ // TODO: Need to cancel out of the delay appropriately
+ Animator delayAnim = new Animator(mStartDelay, 0f, 1f);
+ delayAnim.addListener(new AnimatableListenerAdapter() {
+ public void onAnimationEnd(Animatable anim) {
+ for (Node node : nodesToStart) {
+ node.animation.start();
+ mPlayingSet.add(node.animation);
+ }
+ }
+ });
}
if (mListeners != null) {
ArrayList<AnimatableListener> tmpListeners =
@@ -316,7 +410,7 @@
}
@Override
- public Sequencer clone() throws CloneNotSupportedException {
+ public Sequencer clone() {
final Sequencer anim = (Sequencer) super.clone();
/*
* The basic clone() operation copies all items. This doesn't work very well for
@@ -688,10 +782,14 @@
}
@Override
- public Node clone() throws CloneNotSupportedException {
- Node node = (Node) super.clone();
- node.animation = (Animatable) animation.clone();
- return node;
+ public Node clone() {
+ try {
+ Node node = (Node) super.clone();
+ node.animation = (Animatable) animation.clone();
+ return node;
+ } catch (CloneNotSupportedException e) {
+ throw new AssertionError();
+ }
}
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e4be0fb44..47dae03 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -72,6 +72,7 @@
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import java.util.WeakHashMap;
/**
@@ -1837,6 +1838,11 @@
protected OnFocusChangeListener mOnFocusChangeListener;
/**
+ * Listeners for layout change events.
+ */
+ private ArrayList<OnLayoutChangeListener> mOnLayoutChangeListeners;
+
+ /**
* Listener used to dispatch click events.
* This field should be made private, so it is hidden from the SDK.
* {@hide}
@@ -2495,6 +2501,39 @@
}
/**
+ * Add a listener that will be called when the bounds of the view change due to
+ * layout processing.
+ *
+ * @param listener The listener that will be called when layout bounds change.
+ */
+ public void addOnLayoutChangeListener(OnLayoutChangeListener listener) {
+ if (mOnLayoutChangeListeners == null) {
+ mOnLayoutChangeListeners = new ArrayList<OnLayoutChangeListener>();
+ }
+ mOnLayoutChangeListeners.add(listener);
+ }
+
+ /**
+ * Remove a listener for layout changes.
+ *
+ * @param listener The listener for layout bounds change.
+ */
+ public void removeOnLayoutChangeListener(OnLayoutChangeListener listener) {
+ if (mOnLayoutChangeListeners == null) {
+ return;
+ }
+ mOnLayoutChangeListeners.remove(listener);
+ }
+
+ /**
+ * Gets the current list of listeners for layout changes.
+ * @return
+ */
+ public List<OnLayoutChangeListener> getOnLayoutChangeListeners() {
+ return mOnLayoutChangeListeners;
+ }
+
+ /**
* Returns the focus-change callback registered for this view.
*
* @return The callback, or null if one is not registered.
@@ -4805,6 +4844,28 @@
}
/**
+ * Interface definition for a callback to be invoked when the layout bounds of a view
+ * changes due to layout processing.
+ */
+ public interface OnLayoutChangeListener {
+ /**
+ * Called when the focus state of a view has changed.
+ *
+ * @param v The view whose state has changed.
+ * @param left The new value of the view's left property.
+ * @param top The new value of the view's top property.
+ * @param right The new value of the view's right property.
+ * @param bottom The new value of the view's bottom property.
+ * @param oldLeft The previous value of the view's left property.
+ * @param oldTop The previous value of the view's top property.
+ * @param oldRight The previous value of the view's right property.
+ * @param oldBottom The previous value of the view's bottom property.
+ */
+ void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom);
+ }
+
+ /**
* This is called during layout when the size of this view has changed. If
* you were just added to the view hierarchy, you're called with the old
* values of 0.
@@ -5265,6 +5326,45 @@
}
/**
+ * Sets the top position of this view relative to its parent. This method is meant to be called
+ * by the layout system and should not generally be called otherwise, because the property
+ * may be changed at any time by the layout.
+ *
+ * @param top The top of this view, in pixels.
+ */
+ public final void setTop(int top) {
+ if (top != mTop) {
+ if (hasIdentityMatrix()) {
+ final ViewParent p = mParent;
+ if (p != null && mAttachInfo != null) {
+ final Rect r = mAttachInfo.mTmpInvalRect;
+ int minTop;
+ int yLoc;
+ if (top < mTop) {
+ minTop = top;
+ yLoc = top - mTop;
+ } else {
+ minTop = mTop;
+ yLoc = 0;
+ }
+ r.set(0, yLoc, mRight - mLeft, mBottom - minTop);
+ p.invalidateChild(this, r);
+ }
+ } else {
+ // Double-invalidation is necessary to capture view's old and new areas
+ invalidate();
+ }
+
+ mTop = top;
+
+ if (!mMatrixIsIdentity) {
+ mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+ invalidate();
+ }
+ }
+ }
+
+ /**
* Bottom position of this view relative to its parent.
*
* @return The bottom of this view, in pixels.
@@ -5275,6 +5375,42 @@
}
/**
+ * Sets the bottom position of this view relative to its parent. This method is meant to be
+ * called by the layout system and should not generally be called otherwise, because the
+ * property may be changed at any time by the layout.
+ *
+ * @param bottom The bottom of this view, in pixels.
+ */
+ public final void setBottom(int bottom) {
+ if (bottom != mBottom) {
+ if (hasIdentityMatrix()) {
+ final ViewParent p = mParent;
+ if (p != null && mAttachInfo != null) {
+ final Rect r = mAttachInfo.mTmpInvalRect;
+ int maxBottom;
+ if (bottom < mBottom) {
+ maxBottom = mBottom;
+ } else {
+ maxBottom = bottom;
+ }
+ r.set(0, 0, mRight - mLeft, maxBottom - mTop);
+ p.invalidateChild(this, r);
+ }
+ } else {
+ // Double-invalidation is necessary to capture view's old and new areas
+ invalidate();
+ }
+
+ mBottom = bottom;
+
+ if (!mMatrixIsIdentity) {
+ mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+ invalidate();
+ }
+ }
+ }
+
+ /**
* Left position of this view relative to its parent.
*
* @return The left edge of this view, in pixels.
@@ -5285,6 +5421,46 @@
}
/**
+ * Sets the left position of this view relative to its parent. This method is meant to be called
+ * by the layout system and should not generally be called otherwise, because the property
+ * may be changed at any time by the layout.
+ *
+ * @param left The bottom of this view, in pixels.
+ */
+ public final void setLeft(int left) {
+ if (left != mLeft) {
+ System.out.println("view " + this + " left = " + left);
+ if (hasIdentityMatrix()) {
+ final ViewParent p = mParent;
+ if (p != null && mAttachInfo != null) {
+ final Rect r = mAttachInfo.mTmpInvalRect;
+ int minLeft;
+ int xLoc;
+ if (left < mLeft) {
+ minLeft = left;
+ xLoc = left - mLeft;
+ } else {
+ minLeft = mLeft;
+ xLoc = 0;
+ }
+ r.set(xLoc, 0, mRight - minLeft, mBottom - mTop);
+ p.invalidateChild(this, r);
+ }
+ } else {
+ // Double-invalidation is necessary to capture view's old and new areas
+ invalidate();
+ }
+
+ mLeft = left;
+
+ if (!mMatrixIsIdentity) {
+ mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+ invalidate();
+ }
+ }
+ }
+
+ /**
* Right position of this view relative to its parent.
*
* @return The right edge of this view, in pixels.
@@ -5295,6 +5471,42 @@
}
/**
+ * Sets the right position of this view relative to its parent. This method is meant to be called
+ * by the layout system and should not generally be called otherwise, because the property
+ * may be changed at any time by the layout.
+ *
+ * @param right The bottom of this view, in pixels.
+ */
+ public final void setRight(int right) {
+ if (right != mRight) {
+ if (hasIdentityMatrix()) {
+ final ViewParent p = mParent;
+ if (p != null && mAttachInfo != null) {
+ final Rect r = mAttachInfo.mTmpInvalRect;
+ int maxRight;
+ if (right < mRight) {
+ maxRight = mRight;
+ } else {
+ maxRight = right;
+ }
+ r.set(0, 0, maxRight - mLeft, mBottom - mTop);
+ p.invalidateChild(this, r);
+ }
+ } else {
+ // Double-invalidation is necessary to capture view's old and new areas
+ invalidate();
+ }
+
+ mRight = right;
+
+ if (!mMatrixIsIdentity) {
+ mPrivateFlags |= DRAWN; // force another invalidation with the new orientation
+ invalidate();
+ }
+ }
+ }
+
+ /**
* The visual x position of this view, in pixels. This is equivalent to the
* {@link #setTranslationX(float) translationX} property plus the current
* {@link #getLeft() left} property.
@@ -7741,7 +7953,7 @@
*
* Derived classes with children should override
* onLayout. In that method, they should
- * call layout on each of their their children.
+ * call layout on each of their children.
*
* @param l Left position, relative to parent
* @param t Top position, relative to parent
@@ -7749,6 +7961,10 @@
* @param b Bottom position, relative to parent
*/
public final void layout(int l, int t, int r, int b) {
+ int oldL = mLeft;
+ int oldT = mTop;
+ int oldB = mBottom;
+ int oldR = mRight;
boolean changed = setFrame(l, t, r, b);
if (changed || (mPrivateFlags & LAYOUT_REQUIRED) == LAYOUT_REQUIRED) {
if (ViewDebug.TRACE_HIERARCHY) {
@@ -7757,6 +7973,15 @@
onLayout(changed, l, t, r, b);
mPrivateFlags &= ~LAYOUT_REQUIRED;
+
+ if (mOnLayoutChangeListeners != null) {
+ ArrayList<OnLayoutChangeListener> listenersCopy =
+ (ArrayList<OnLayoutChangeListener>) mOnLayoutChangeListeners.clone();
+ int numListeners = listenersCopy.size();
+ for (int i = 0; i < numListeners; ++i) {
+ listenersCopy.get(i).onLayoutChange(this, l, r, t, b, oldL, oldT, oldR, oldB);
+ }
+ }
}
mPrivateFlags &= ~FORCE_LAYOUT;
}
@@ -7767,7 +7992,7 @@
*
* Derived classes with children should override
* this method and call layout on each of
- * their their children.
+ * their children.
* @param changed This is a new size or position for this view
* @param left Left position, relative to parent
* @param top Top position, relative to parent
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index dfe4295..649f3e7 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -16,6 +16,7 @@
package android.view;
+import android.animation.LayoutTransition;
import com.android.internal.R;
import android.content.Context;
@@ -66,6 +67,7 @@
* @attr ref android.R.styleable#ViewGroup_descendantFocusability
*/
public abstract class ViewGroup extends View implements ViewParent, ViewManager {
+
private static final boolean DBG = false;
/**
@@ -298,6 +300,14 @@
// Used to draw cached views
private final Paint mCachePaint = new Paint();
+ // Used to animate add/remove changes in layout
+ private LayoutTransition mTransition;
+
+ // The set of views that are currently being transitioned. This list is used to track views
+ // being removed that should not actually be removed from the parent yet because they are
+ // being animated.
+ private ArrayList<View> mTransitioningViews;
+
public ViewGroup(Context context) {
super(context);
initViewGroup();
@@ -2327,6 +2337,10 @@
"You must call removeView() on the child's parent first.");
}
+ if (mTransition != null) {
+ mTransition.childAdd(this, child);
+ }
+
if (!checkLayoutParams(params)) {
params = generateLayoutParams(params);
}
@@ -2404,7 +2418,9 @@
// This method also sets the child's mParent to null
private void removeFromArray(int index) {
final View[] children = mChildren;
- children[index].mParent = null;
+ if (!(mTransitioningViews != null && mTransitioningViews.contains(children[index]))) {
+ children[index].mParent = null;
+ }
final int count = mChildrenCount;
if (index == count - 1) {
children[--mChildrenCount] = null;
@@ -2539,13 +2555,19 @@
}
private void removeViewInternal(int index, View view) {
+
+ if (mTransition != null) {
+ mTransition.childRemove(this, view);
+ }
+
boolean clearChildFocus = false;
if (view == mFocused) {
view.clearFocusForRemoval();
clearChildFocus = true;
}
- if (view.getAnimation() != null) {
+ if (view.getAnimation() != null ||
+ (mTransitioningViews != null && mTransitioningViews.contains(view))) {
addDisappearingView(view);
} else if (view.mAttachInfo != null) {
view.dispatchDetachedFromWindow();
@@ -2564,6 +2586,20 @@
}
}
+ /**
+ * Sets the LayoutTransition object for this ViewGroup. If the LayoutTransition object is
+ * not null, changes in layout which occur because of children being added to or removed from
+ * the ViewGroup will be animated according to the animations defined in that LayoutTransition
+ * object. By default, the transition object is null (so layout changes are not animated).
+ *
+ * @param transition The LayoutTransition object that will animated changes in layout. A value
+ * of <code>null</code> means no transition will run on layout changes.
+ */
+ public void setLayoutTransition(LayoutTransition transition) {
+ mTransition = transition;
+ mTransition.addTransitionListener(mLayoutTransitionListener);
+ }
+
private void removeViewsInternal(int start, int count) {
final OnHierarchyChangeListener onHierarchyChangeListener = mOnHierarchyChangeListener;
final boolean notifyListener = onHierarchyChangeListener != null;
@@ -2577,12 +2613,17 @@
for (int i = start; i < end; i++) {
final View view = children[i];
+ if (mTransition != null) {
+ mTransition.childRemove(this, view);
+ }
+
if (view == focused) {
view.clearFocusForRemoval();
clearChildFocus = view;
}
- if (view.getAnimation() != null) {
+ if (view.getAnimation() != null ||
+ (mTransitioningViews != null && mTransitioningViews.contains(view))) {
addDisappearingView(view);
} else if (detach) {
view.dispatchDetachedFromWindow();
@@ -2641,12 +2682,17 @@
for (int i = count - 1; i >= 0; i--) {
final View view = children[i];
+ if (mTransition != null) {
+ mTransition.childRemove(this, view);
+ }
+
if (view == focused) {
view.clearFocusForRemoval();
clearChildFocus = view;
}
- if (view.getAnimation() != null) {
+ if (view.getAnimation() != null ||
+ (mTransitioningViews != null && mTransitioningViews.contains(view))) {
addDisappearingView(view);
} else if (detach) {
view.dispatchDetachedFromWindow();
@@ -2679,11 +2725,16 @@
* @see #detachViewFromParent(int)
*/
protected void removeDetachedView(View child, boolean animate) {
+ if (mTransition != null) {
+ mTransition.childRemove(this, child);
+ }
+
if (child == mFocused) {
child.clearFocus();
}
- if (animate && child.getAnimation() != null) {
+ if ((animate && child.getAnimation() != null) ||
+ (mTransitioningViews != null && mTransitioningViews.contains(child))) {
addDisappearingView(child);
} else if (child.mAttachInfo != null) {
child.dispatchDetachedFromWindow();
@@ -3658,6 +3709,41 @@
}
}
+ private LayoutTransition.TransitionListener mLayoutTransitionListener =
+ new LayoutTransition.TransitionListener() {
+ @Override
+ public void startTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ // We only care about disappearing items, since we need special logic to keep
+ // those items visible after they've been 'removed'
+ if (transitionType == LayoutTransition.DISAPPEARING) {
+ if (mTransitioningViews == null) {
+ mTransitioningViews = new ArrayList<View>();
+ }
+ mTransitioningViews.add(view);
+ }
+ }
+
+ @Override
+ public void endTransition(LayoutTransition transition, ViewGroup container,
+ View view, int transitionType) {
+ if (transitionType == LayoutTransition.DISAPPEARING && mTransitioningViews != null) {
+ mTransitioningViews.remove(view);
+ final ArrayList<View> disappearingChildren = mDisappearingChildren;
+ if (disappearingChildren != null && disappearingChildren.contains(view)) {
+ disappearingChildren.remove(view);
+ if (view.mAttachInfo != null) {
+ view.dispatchDetachedFromWindow();
+ }
+ if (view.mParent != null) {
+ view.mParent = null;
+ }
+ mGroupFlags |= FLAG_INVALIDATE_REQUIRED;
+ }
+ }
+ }
+ };
+
/**
* {@inheritDoc}
*/
diff --git a/include/media/stagefright/MPEG4Writer.h b/include/media/stagefright/MPEG4Writer.h
index 52b93e1..70bd8e8 100644
--- a/include/media/stagefright/MPEG4Writer.h
+++ b/include/media/stagefright/MPEG4Writer.h
@@ -62,6 +62,7 @@
class Track;
FILE *mFile;
+ bool mUse4ByteNalLength;
bool mUse32BitOffset;
bool mPaused;
bool mStarted;
@@ -135,6 +136,10 @@
void setDriftTimeUs(int64_t driftTimeUs);
int64_t getDriftTimeUs();
+ // Return whether the nal length is 4 bytes or 2 bytes
+ // Only makes sense for H.264/AVC
+ bool useNalLengthFour();
+
void lock();
void unlock();
diff --git a/include/media/stagefright/MetaData.h b/include/media/stagefright/MetaData.h
index 3b31e68..0b6201c 100644
--- a/include/media/stagefright/MetaData.h
+++ b/include/media/stagefright/MetaData.h
@@ -79,6 +79,7 @@
// Set this key to enable authoring files in 64-bit offset
kKey64BitFileOffset = 'fobt', // int32_t (bool)
+ kKey2ByteNalLength = '2NAL', // int32_t (bool)
// Identify the file output format for authoring
// Please see <media/mediarecorder.h> for the supported
diff --git a/media/libstagefright/MPEG4Writer.cpp b/media/libstagefright/MPEG4Writer.cpp
index 5dcbc22..806836d 100644
--- a/media/libstagefright/MPEG4Writer.cpp
+++ b/media/libstagefright/MPEG4Writer.cpp
@@ -32,7 +32,6 @@
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/Utils.h>
#include <media/mediarecorder.h>
-#include <cutils/properties.h>
#include "include/ESDS.h"
@@ -113,7 +112,6 @@
size_t mNumStssTableEntries;
List<int32_t> mStssTableEntries;
- List<int64_t> mChunkDurations;
size_t mNumSttsTableEntries;
struct SttsTableEntry {
@@ -167,12 +165,6 @@
void trackProgressStatus(int64_t timeUs, status_t err = OK);
void initTrackingProgressStatus(MetaData *params);
- // Utilities for collecting statistical data
- void logStatisticalData(bool isAudio);
- void findMinAvgMaxSampleDurationMs(
- int32_t *min, int32_t *avg, int32_t *max);
- void findMinMaxChunkDurations(int64_t *min, int64_t *max);
-
void getCodecSpecificDataFromInputFormatIfPossible();
// Determine the track time scale
@@ -193,10 +185,9 @@
Track &operator=(const Track &);
};
-#define USE_NALLEN_FOUR 1
-
MPEG4Writer::MPEG4Writer(const char *filename)
: mFile(fopen(filename, "wb")),
+ mUse4ByteNalLength(true),
mUse32BitOffset(true),
mPaused(false),
mStarted(false),
@@ -209,6 +200,7 @@
MPEG4Writer::MPEG4Writer(int fd)
: mFile(fdopen(fd, "wb")),
+ mUse4ByteNalLength(true),
mUse32BitOffset(true),
mPaused(false),
mStarted(false),
@@ -360,11 +352,11 @@
}
}
- // System property can overwrite the file offset bits parameter
- char value[PROPERTY_VALUE_MAX];
- if (property_get("media.stagefright.record-64bits", value, NULL)
- && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
- mUse32BitOffset = false;
+ int32_t use2ByteNalLength;
+ if (param &&
+ param->findInt32(kKey2ByteNalLength, &use2ByteNalLength) &&
+ use2ByteNalLength) {
+ mUse4ByteNalLength = false;
}
mStartTimestampUs = -1;
@@ -639,32 +631,30 @@
size_t length = buffer->range_length();
-#if USE_NALLEN_FOUR
- uint8_t x = length >> 24;
- fwrite(&x, 1, 1, mFile);
- x = (length >> 16) & 0xff;
- fwrite(&x, 1, 1, mFile);
- x = (length >> 8) & 0xff;
- fwrite(&x, 1, 1, mFile);
- x = length & 0xff;
- fwrite(&x, 1, 1, mFile);
-#else
- CHECK(length < 65536);
+ if (mUse4ByteNalLength) {
+ uint8_t x = length >> 24;
+ fwrite(&x, 1, 1, mFile);
+ x = (length >> 16) & 0xff;
+ fwrite(&x, 1, 1, mFile);
+ x = (length >> 8) & 0xff;
+ fwrite(&x, 1, 1, mFile);
+ x = length & 0xff;
+ fwrite(&x, 1, 1, mFile);
- uint8_t x = length >> 8;
- fwrite(&x, 1, 1, mFile);
- x = length & 0xff;
- fwrite(&x, 1, 1, mFile);
-#endif
+ fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
+ 1, length, mFile);
+ mOffset += length + 4;
+ } else {
+ CHECK(length < 65536);
- fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
- 1, length, mFile);
-
-#if USE_NALLEN_FOUR
- mOffset += length + 4;
-#else
- mOffset += length + 2;
-#endif
+ uint8_t x = length >> 8;
+ fwrite(&x, 1, 1, mFile);
+ x = length & 0xff;
+ fwrite(&x, 1, 1, mFile);
+ fwrite((const uint8_t *)buffer->data() + buffer->range_offset(),
+ 1, length, mFile);
+ mOffset += length + 2;
+ }
return old_offset;
}
@@ -1204,46 +1194,6 @@
return (void *) err;
}
-#include <ctype.h>
-static void hexdump(const void *_data, size_t size) {
- const uint8_t *data = (const uint8_t *)_data;
- size_t offset = 0;
- while (offset < size) {
- printf("0x%04x ", offset);
-
- size_t n = size - offset;
- if (n > 16) {
- n = 16;
- }
-
- for (size_t i = 0; i < 16; ++i) {
- if (i == 8) {
- printf(" ");
- }
-
- if (offset + i < size) {
- printf("%02x ", data[offset + i]);
- } else {
- printf(" ");
- }
- }
-
- printf(" ");
-
- for (size_t i = 0; i < n; ++i) {
- if (isprint(data[offset + i])) {
- printf("%c", data[offset + i]);
- } else {
- printf(".");
- }
- }
-
- printf("\n");
-
- offset += 16;
- }
-}
-
static void getNalUnitType(uint8_t byte, uint8_t* type) {
LOGV("getNalUnitType: %d", byte);
@@ -1415,7 +1365,6 @@
status_t MPEG4Writer::Track::makeAVCCodecSpecificData(
const uint8_t *data, size_t size) {
- // hexdump(data, size);
if (mCodecSpecificData != NULL) {
LOGE("Already have codec specific data");
@@ -1446,11 +1395,11 @@
header[3] = mLevelIdc;
// 6-bit '111111' followed by 2-bit to lengthSizeMinuusOne
-#if USE_NALLEN_FOUR
- header[4] = 0xfc | 3; // length size == 4 bytes
-#else
- header[4] = 0xfc | 1; // length size == 2 bytes
-#endif
+ if (mOwner->useNalLengthFour()) {
+ header[4] = 0xfc | 3; // length size == 4 bytes
+ } else {
+ header[4] = 0xfc | 1; // length size == 2 bytes
+ }
// 3-bit '111' followed by 5-bit numSequenceParameterSets
int nSequenceParamSets = mSeqParamSets.size();
@@ -1487,15 +1436,6 @@
return OK;
}
-static bool collectStatisticalData() {
- char value[PROPERTY_VALUE_MAX];
- if (property_get("media.stagefright.record-stats", value, NULL)
- && (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
- return true;
- }
- return false;
-}
-
status_t MPEG4Writer::Track::threadEntry() {
int32_t count = 0;
const int64_t interleaveDurationUs = mOwner->interleaveDuration();
@@ -1512,7 +1452,6 @@
int64_t timestampUs;
sp<MetaData> meta_data;
- bool collectStats = collectStatisticalData();
mNumSamples = 0;
status_t err = OK;
@@ -1575,14 +1514,14 @@
if (mIsAvc) StripStartcode(copy);
- size_t sampleSize;
- sampleSize = mIsAvc
-#if USE_NALLEN_FOUR
- ? copy->range_length() + 4
-#else
- ? copy->range_length() + 2
-#endif
- : copy->range_length();
+ size_t sampleSize = copy->range_length();
+ if (mIsAvc) {
+ if (mOwner->useNalLengthFour()) {
+ sampleSize += 4;
+ } else {
+ sampleSize += 2;
+ }
+ }
// Max file size or duration handling
mMdatSizeBytes += sampleSize;
@@ -1722,9 +1661,6 @@
} else {
if (timestampUs - chunkTimestampUs > interleaveDurationUs) {
++nChunks;
- if (collectStats) {
- mChunkDurations.push_back(timestampUs - chunkTimestampUs);
- }
if (nChunks == 1 || // First chunk
(--(mStscTableEntries.end()))->samplesPerChunk !=
mChunkSamples.size()) {
@@ -1767,7 +1703,6 @@
LOGI("Received total/0-length (%d/%d) buffers and encoded %d frames. - %s",
count, nZeroLengthFrames, mNumSamples, mIsAudio? "audio": "video");
- logStatisticalData(mIsAudio);
if (err == ERROR_END_OF_STREAM) {
return OK;
}
@@ -1792,17 +1727,6 @@
CHECK(nTracks < 64); // Arbitrary number
int32_t trackNum = 0;
-#if 0
- // In the worst case, we can put the trackNum
- // along with MEDIA_RECORDER_INFO_COMPLETION_STATUS
- // to report the progress.
- for (List<Track *>::iterator it = mTracks.begin();
- it != mTracks.end(); ++it, ++trackNum) {
- if (track == (*it)) {
- break;
- }
- }
-#endif
CHECK(trackNum < nTracks);
trackNum <<= 16;
@@ -1829,91 +1753,6 @@
}
}
-void MPEG4Writer::Track::findMinAvgMaxSampleDurationMs(
- int32_t *min, int32_t *avg, int32_t *max) {
- CHECK(!mSampleSizes.empty());
- int32_t avgSampleDurationMs = mTrackDurationUs / 1000 / mNumSamples;
- int32_t minSampleDurationMs = 0x7FFFFFFF;
- int32_t maxSampleDurationMs = 0;
- for (List<SttsTableEntry>::iterator it = mSttsTableEntries.begin();
- it != mSttsTableEntries.end(); ++it) {
- int32_t sampleDurationMs =
- (static_cast<int32_t>(it->sampleDurationUs) + 500) / 1000;
- if (sampleDurationMs > maxSampleDurationMs) {
- maxSampleDurationMs = sampleDurationMs;
- } else if (sampleDurationMs < minSampleDurationMs) {
- minSampleDurationMs = sampleDurationMs;
- }
- LOGI("sample duration: %d ms", sampleDurationMs);
- }
- CHECK(minSampleDurationMs != 0);
- CHECK(avgSampleDurationMs != 0);
- CHECK(maxSampleDurationMs != 0);
- *min = minSampleDurationMs;
- *avg = avgSampleDurationMs;
- *max = maxSampleDurationMs;
-}
-
-// Don't count the last duration
-void MPEG4Writer::Track::findMinMaxChunkDurations(int64_t *min, int64_t *max) {
- int64_t duration = mOwner->interleaveDuration();
- int64_t minChunkDuration = duration;
- int64_t maxChunkDuration = duration;
- if (mChunkDurations.size() > 1) {
- for (List<int64_t>::iterator it = mChunkDurations.begin();
- it != --mChunkDurations.end(); ++it) {
- if (minChunkDuration > (*it)) {
- minChunkDuration = (*it);
- } else if (maxChunkDuration < (*it)) {
- maxChunkDuration = (*it);
- }
- }
- }
- *min = minChunkDuration;
- *max = maxChunkDuration;
-}
-
-void MPEG4Writer::Track::logStatisticalData(bool isAudio) {
- if (mTrackDurationUs <= 0 || mSampleSizes.empty()) {
- LOGI("nothing is recorded");
- return;
- }
-
- bool collectStats = collectStatisticalData();
-
- if (collectStats) {
- LOGI("%s track - duration %lld us, total %d frames",
- isAudio? "audio": "video", mTrackDurationUs,
- mNumSamples);
- int32_t min, avg, max;
- findMinAvgMaxSampleDurationMs(&min, &avg, &max);
- LOGI("min/avg/max sample duration (ms): %d/%d/%d", min, avg, max);
- if (!isAudio) {
- float avgFps = 1000.0 / avg;
- float minFps = 1000.0 / max;
- float maxFps = 1000.0 / min;
- LOGI("min/avg/max frame rate (fps): %.2f/%.2f/%.2f",
- minFps, avgFps, maxFps);
- }
-
- int64_t totalBytes = 0;
- for (List<size_t>::iterator it = mSampleSizes.begin();
- it != mSampleSizes.end(); ++it) {
- totalBytes += (*it);
- }
- float bitRate = (totalBytes * 8000000.0) / mTrackDurationUs;
- LOGI("avg bit rate (bps): %.2f", bitRate);
-
- int64_t duration = mOwner->interleaveDuration();
- if (duration != 0) { // If interleaving is enabled
- int64_t minChunk, maxChunk;
- findMinMaxChunkDurations(&minChunk, &maxChunk);
- LOGI("min/avg/max chunk duration (ms): %lld/%lld/%lld",
- minChunk, duration, maxChunk);
- }
- }
-}
-
void MPEG4Writer::setDriftTimeUs(int64_t driftTimeUs) {
LOGV("setDriftTimeUs: %lld us", driftTimeUs);
Mutex::Autolock autolock(mLock);
@@ -1926,6 +1765,10 @@
return mDriftTimeUs;
}
+bool MPEG4Writer::useNalLengthFour() {
+ return mUse4ByteNalLength;
+}
+
void MPEG4Writer::Track::bufferChunk(int64_t timestampUs) {
LOGV("bufferChunk");
diff --git a/packages/SystemUI/res/anim/hydraulic_brake_interpolator.xml b/packages/SystemUI/res/anim/hydraulic_brake_interpolator.xml
new file mode 100644
index 0000000..5b6778e
--- /dev/null
+++ b/packages/SystemUI/res/anim/hydraulic_brake_interpolator.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/anim/ease_out_interpolator.xml
+**
+** Copyright 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.
+*/
+-->
+
+<decelerateInterpolator
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:factor="10.0" />
diff --git a/packages/SystemUI/res/anim/lights_out_in.xml b/packages/SystemUI/res/anim/lights_out_in.xml
index 0f0e7ce..8154ec0 100644
--- a/packages/SystemUI/res/anim/lights_out_in.xml
+++ b/packages/SystemUI/res/anim/lights_out_in.xml
@@ -18,8 +18,9 @@
>
<translate android:fromYDelta="100%p" android:toYDelta="0"
android:duration="@android:integer/config_mediumAnimTime"
+ android:interpolator="@anim/hydraulic_brake_interpolator"
/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime"
+ android:duration="@android:integer/config_longAnimTime"
/>
</set>
diff --git a/packages/SystemUI/res/anim/lights_out_out.xml b/packages/SystemUI/res/anim/lights_out_out.xml
index cb895d9..b4bc55a 100644
--- a/packages/SystemUI/res/anim/lights_out_out.xml
+++ b/packages/SystemUI/res/anim/lights_out_out.xml
@@ -18,8 +18,9 @@
>
<translate android:toYDelta="100%p" android:fromYDelta="0"
android:duration="@android:integer/config_mediumAnimTime"
+ android:interpolator="@anim/hydraulic_brake_interpolator"
/>
- <alpha android:toAlpha="0.1" android:fromAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime"
+ <alpha android:toAlpha="0.0" android:fromAlpha="1.0"
+ android:duration="@android:integer/config_longAnimTime"
/>
</set>
diff --git a/packages/SystemUI/res/anim/status_bar_in.xml b/packages/SystemUI/res/anim/status_bar_in.xml
index 48663f4..460fe50 100644
--- a/packages/SystemUI/res/anim/status_bar_in.xml
+++ b/packages/SystemUI/res/anim/status_bar_in.xml
@@ -17,9 +17,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate android:fromYDelta="-100%p" android:toYDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"
+ android:duration="@android:integer/config_longAnimTime"
+ android:interpolator="@anim/hydraulic_brake_interpolator"
/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime"
+ android:duration="@android:integer/config_longAnimTime"
/>
</set>
diff --git a/packages/SystemUI/res/anim/status_bar_out.xml b/packages/SystemUI/res/anim/status_bar_out.xml
index b3f8953..6572ab4 100644
--- a/packages/SystemUI/res/anim/status_bar_out.xml
+++ b/packages/SystemUI/res/anim/status_bar_out.xml
@@ -17,9 +17,10 @@
<set xmlns:android="http://schemas.android.com/apk/res/android"
>
<translate android:toYDelta="-100%p" android:fromYDelta="0"
- android:duration="@android:integer/config_mediumAnimTime"
+ android:duration="@android:integer/config_longAnimTime"
+ android:interpolator="@anim/hydraulic_brake_interpolator"
/>
<alpha android:toAlpha="0.0" android:fromAlpha="1.0"
- android:duration="@android:integer/config_mediumAnimTime"
+ android:duration="@android:integer/config_longAnimTime"
/>
</set>
diff --git a/packages/SystemUI/res/drawable/sysbar_batterymini.xml b/packages/SystemUI/res/drawable/sysbar_batterymini.xml
index f7ba6b1..c7300e6 100644
--- a/packages/SystemUI/res/drawable/sysbar_batterymini.xml
+++ b/packages/SystemUI/res/drawable/sysbar_batterymini.xml
@@ -23,7 +23,7 @@
android:maxLevel="100"
android:gravity="left">
<level-list>
- <item android:maxLevel="15" android:drawable="@drawable/sysbar_batterymini_red" />
- <item android:maxLevel="101" android:drawable="@drawable/sysbar_batterymini_100" />
+ <item android:maxLevel="1500" android:drawable="@drawable/sysbar_batterymini_red" />
+ <item android:maxLevel="10000" android:drawable="@drawable/sysbar_batterymini_100" />
</level-list>
</clip>
diff --git a/packages/SystemUI/res/drawable/sysbar_signalmini.xml b/packages/SystemUI/res/drawable/sysbar_signalmini.xml
index ca6c9ed..598bf10 100644
--- a/packages/SystemUI/res/drawable/sysbar_signalmini.xml
+++ b/packages/SystemUI/res/drawable/sysbar_signalmini.xml
@@ -21,5 +21,5 @@
<clip xmlns:android="http://schemas.android.com/apk/res/android"
android:clipOrientation="horizontal"
android:gravity="right"
- android:maxLevel="100"
+ android:maxLevel="10000"
android:drawable="@drawable/sysbar_signalmini_100" />
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 1611af1..5ae87cf 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -2022,7 +2022,11 @@
ActivityInfo ai = getActivityInfo(pa.mActivity, flags);
if (DEBUG_PREFERRED) {
Log.v(TAG, "Got preferred activity:");
- ai.dump(new LogPrinter(Log.INFO, TAG), " ");
+ if (ai != null) {
+ ai.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
+ } else {
+ Log.v(TAG, " null");
+ }
}
if (ai != null) {
for (int j=0; j<N; j++) {