Merge "Fix for the incorrect size of the new added DRM file. (bug 2897238)"
diff --git a/api/current.xml b/api/current.xml
index 384ca18..8476d96 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>
@@ -24655,17 +25184,6 @@
visibility="public"
>
</field>
-<field name="FLAG_HEAVY_WEIGHT"
- type="int"
- transient="false"
- volatile="false"
- value="1"
- static="true"
- final="true"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="IMPORTANCE_BACKGROUND"
type="int"
transient="false"
@@ -24776,16 +25294,6 @@
visibility="public"
>
</field>
-<field name="flags"
- type="int"
- transient="false"
- volatile="false"
- static="false"
- final="false"
- deprecated="not deprecated"
- visibility="public"
->
-</field>
<field name="importance"
type="int"
transient="false"
@@ -55740,6 +56248,17 @@
visibility="public"
>
</field>
+<field name="FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND"
+ type="java.lang.String"
+ transient="false"
+ volatile="false"
+ value=""android.hardware.touchscreen.multitouch.jazzhand""
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="FEATURE_WIFI"
type="java.lang.String"
transient="false"
@@ -194495,6 +195014,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 +196116,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 +197731,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 +198012,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 +198233,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 +198488,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 +198685,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 +199760,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 +201625,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/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index d5741fc..4736404 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -755,14 +755,17 @@
public String pkgList[];
/**
- * Constant for {@link #flags}: this is a heavy-weight process,
- * meaning it will not be killed while in the background.
+ * Constant for {@link #flags}: this is an app that is unable to
+ * correctly save its state when going to the background,
+ * so it can not be killed while in the background.
+ * @hide
*/
- public static final int FLAG_HEAVY_WEIGHT = 1<<0;
+ public static final int FLAG_CANT_SAVE_STATE = 1<<0;
/**
* Flags of information. May be any of
- * {@link #FLAG_HEAVY_WEIGHT}.
+ * {@link #FLAG_CANT_SAVE_STATE}.
+ * @hide
*/
public int flags;
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 460328d..8963d0c 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -816,6 +816,15 @@
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device's touch screen is capable of
+ * tracking a full hand of fingers fully independently -- that is, 5 or
+ * more simultaneous independent pointers.
+ */
+ @SdkConstant(SdkConstantType.FEATURE)
+ public static final String FEATURE_TOUCHSCREEN_MULTITOUCH_JAZZHAND = "android.hardware.touchscreen.multitouch.jazzhand";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The device supports live wallpapers.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index f3f2d60..63bdf8d 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -105,10 +105,9 @@
mTarget = target;
mContext = context;
- IntentFilter filter =
- new IntentFilter(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(TelephonyIntents.ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
filter.addAction(TelephonyIntents.ACTION_DATA_CONNECTION_FAILED);
- filter.addAction(TelephonyIntents.ACTION_SERVICE_STATE_CHANGED);
mContext.registerReceiver(new MobileDataStateReceiver(), filter);
mMobileDataState = Phone.DataState.DISCONNECTED;
@@ -192,7 +191,7 @@
ConnectivityManager.TYPE_MOBILE);
if (mConnectivityManager == null) {
IBinder b = ServiceManager.getService(
- mContext.CONNECTIVITY_SERVICE);
+ Context.CONNECTIVITY_SERVICE);
mConnectivityManager = IConnectivityManager.Stub.asInterface(b);
}
try {
@@ -251,7 +250,6 @@
" broadcast" + reason == null ? "" : "(" + reason + ")");
setDetailedState(DetailedState.FAILED, reason, apnName);
}
- TelephonyManager tm = TelephonyManager.getDefault();
}
}
@@ -269,15 +267,6 @@
}
/**
- * {@inheritDoc}
- * The mobile data network subtype indicates what generation network technology is in effect,
- * e.g., GPRS, EDGE, UMTS, etc.
- */
- public int getNetworkSubtype() {
- return TelephonyManager.getDefault().getNetworkType();
- }
-
- /**
* Return the system properties name associated with the tcp buffer sizes
* for this network.
*/
@@ -338,16 +327,6 @@
* change from the previous state, send a notification to
* any listeners.
* @param state the new @{code DetailedState}
- */
- private void setDetailedState(NetworkInfo.DetailedState state) {
- setDetailedState(state, null, null);
- }
-
- /**
- * Record the detailed state of a network, and if it is a
- * change from the previous state, send a notification to
- * any listeners.
- * @param state the new @{code DetailedState}
* @param reason a {@code String} indicating a reason for the state change,
* if one was supplied. May be {@code null}.
* @param extraInfo optional {@code String} providing extra information about the state change
@@ -372,10 +351,6 @@
}
}
- private void setDetailedStateInternal(NetworkInfo.DetailedState state) {
- mNetworkInfo.setDetailedState(state, null, null);
- }
-
public void setTeardownRequested(boolean isRequested) {
mTeardownRequested = isRequested;
}
diff --git a/core/java/android/preference/PreferenceManager.java b/core/java/android/preference/PreferenceManager.java
index 2b20946..fa83897 100644
--- a/core/java/android/preference/PreferenceManager.java
+++ b/core/java/android/preference/PreferenceManager.java
@@ -443,7 +443,7 @@
pm.setSharedPreferencesMode(sharedPreferencesMode);
pm.inflateFromResource(context, resId, null);
- defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true).commit();
+ defaultValueSp.edit().putBoolean(KEY_HAS_SET_DEFAULT_VALUES, true).apply();
}
}
@@ -481,7 +481,7 @@
private void setNoCommit(boolean noCommit) {
if (!noCommit && mEditor != null) {
- mEditor.commit();
+ mEditor.apply();
}
mNoCommit = noCommit;
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/core/java/android/webkit/URLUtil.java b/core/java/android/webkit/URLUtil.java
index 7c5f2b0..c1319e5 100644
--- a/core/java/android/webkit/URLUtil.java
+++ b/core/java/android/webkit/URLUtil.java
@@ -47,7 +47,7 @@
String retVal = inUrl;
WebAddress webAddress;
- Log.v(LOGTAG, "guessURL before queueRequest: " + inUrl);
+ if (DebugFlags.URL_UTIL) Log.v(LOGTAG, "guessURL before queueRequest: " + inUrl);
if (inUrl.length() == 0) return inUrl;
if (inUrl.startsWith("about:")) return inUrl;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2cd38cd..c2c2138 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1274,7 +1274,7 @@
android:excludeFromRecents="true">
</activity>
<activity android:name="com.android.internal.app.PlatLogoActivity"
- android:theme="@style/Theme.NoTitleBar.Fullscreen">
+ android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen">
</activity>
<activity android:name="com.android.internal.app.DisableCarModeActivity"
android:theme="@style/Theme.NoDisplay"
diff --git a/core/res/res/drawable-nodpi/platlogo.jpg b/core/res/res/drawable-nodpi/platlogo.jpg
deleted file mode 100644
index 0e7780c..0000000
--- a/core/res/res/drawable-nodpi/platlogo.jpg
+++ /dev/null
Binary files differ
diff --git a/core/res/res/drawable-nodpi/platlogo.png b/core/res/res/drawable-nodpi/platlogo.png
new file mode 100644
index 0000000..e5af356
--- /dev/null
+++ b/core/res/res/drawable-nodpi/platlogo.png
Binary files differ
diff --git a/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml b/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml
new file mode 100644
index 0000000..80bf859
--- /dev/null
+++ b/data/etc/android.hardware.touchscreen.multitouch.jazzhand.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard set of features for a touchscreen that supports
+ independently-trackable multiple-finger multitouch. -->
+<permissions>
+ <feature name="android.hardware.touchscreen" />
+ <feature name="android.hardware.touchscreen.multitouch" />
+ <feature name="android.hardware.touchscreen.multitouch.distinct" />
+ <feature name="android.hardware.touchscreen.multitouch.jazzhand" />
+</permissions>
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index efca4c2..a3c9f6d 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -38,10 +38,19 @@
<!-- devices with a front facing camera must include
android.hardware.camera.front.xml -->
<!-- devices with WiFi must also include android.hardware.wifi.xml -->
- <!-- devices with limited/gestural multitouch must also include
- android.hardware.touchscreen.multitouch.xml -->
- <!-- devices with full multitouch must also include
- android.hardware.touchscreen.multitouch.distinct.xml -->
+ <!-- devices that support multitouch must include the most appropriate one
+ of these files:
+
+ If only partial (non-independent) pointers are supported:
+ android.hardware.touchscreen.multitouch.xml
+
+ If up to 4 independently tracked pointers are supported:
+ include android.hardware.touchscreen.multitouch.distinct.xml
+
+ If 5 or more independently tracked pointers are supported:
+ include android.hardware.touchscreen.multitouch.jazzhand.xml
+
+ ONLY ONE of the above should be included. -->
<!-- devices with an ambient light sensor must also include
android.hardware.sensor.light.xml -->
<!-- devices with a proximity sensor must also include
diff --git a/docs/html/guide/topics/data/data-storage.jd b/docs/html/guide/topics/data/data-storage.jd
index 293a057..e20d1ed 100644
--- a/docs/html/guide/topics/data/data-storage.jd
+++ b/docs/html/guide/topics/data/data-storage.jd
@@ -115,7 +115,7 @@
public static final String PREFS_NAME = "MyPrefsFile";
@Override
- protected void onCreate(Bundle state){
+ protected void onCreate(Bundle state){
super.onCreate(state);
. . .
@@ -374,7 +374,7 @@
can execute a SQLite command to create tables in the database. For example:</p>
<pre>
-public class MyDbOpenHelper extends SQLiteOpenHelper {
+public class DictionaryOpenHelper extends SQLiteOpenHelper {
private static final int DATABASE_VERSION = 2;
private static final String DICTIONARY_TABLE_NAME = "dictionary";
diff --git a/include/media/IOMX.h b/include/media/IOMX.h
index 2f61cbe..1f8ce71 100644
--- a/include/media/IOMX.h
+++ b/include/media/IOMX.h
@@ -19,6 +19,7 @@
#define ANDROID_IOMX_H_
#include <binder/IInterface.h>
+#include <ui/GraphicBuffer.h>
#include <utils/List.h>
#include <utils/String8.h>
@@ -78,10 +79,17 @@
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size) = 0;
+ virtual status_t enableGraphicBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable) = 0;
+
virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) = 0;
+ virtual status_t useGraphicBuffer(
+ node_id node, OMX_U32 port_index,
+ const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) = 0;
+
// This API clearly only makes sense if the caller lives in the
// same process as the callee, i.e. is the media_server, as the
// returned "buffer_data" pointer is just that, a pointer into local
diff --git a/include/media/stagefright/HardwareAPI.h b/include/media/stagefright/HardwareAPI.h
index 221c679..4ded5e8 100644
--- a/include/media/stagefright/HardwareAPI.h
+++ b/include/media/stagefright/HardwareAPI.h
@@ -21,10 +21,60 @@
#include <media/stagefright/OMXPluginBase.h>
#include <media/stagefright/VideoRenderer.h>
#include <surfaceflinger/ISurface.h>
+#include <ui/android_native_buffer.h>
#include <utils/RefBase.h>
#include <OMX_Component.h>
+namespace android {
+
+// A pointer to this struct is passed to the OMX_SetParameter when the extension
+// index for the 'OMX.google.android.index.enableAndroidNativeBuffers' extension
+// is given.
+//
+// When Android native buffer use is disabled for a port (the default state),
+// the OMX node should operate as normal, and expect UseBuffer calls to set its
+// buffers. This is the mode that will be used when CPU access to the buffer is
+// required.
+//
+// When Android native buffer use has been enabled, the OMX node must support
+// only color formats in the range [OMX_COLOR_FormatAndroidPrivateStart,
+// OMX_COLOR_FormatAndroidPrivateEnd). The node should then expect to receive
+// UseAndroidNativeBuffer calls (via OMX_SetParameter) rather than UseBuffer
+// calls.
+struct EnableAndroidNativeBuffersParams {
+ OMX_U32 nSize;
+ OMX_VERSIONTYPE nVersion;
+ OMX_U32 nPortIndex;
+ OMX_BOOL enable;
+};
+
+// Color formats in the range [OMX_COLOR_FormatAndroidPrivateStart,
+// OMX_COLOR_FormatAndroidPrivateEnd) will be converted to a gralloc pixel
+// format when used to allocate Android native buffers via gralloc. The
+// conversion is done by subtracting OMX_COLOR_FormatAndroidPrivateStart from
+// the color format reported by the codec.
+enum {
+ OMX_COLOR_FormatAndroidPrivateStart = 0xA0000000,
+ OMX_COLOR_FormatAndroidPrivateEnd = 0xB0000000,
+};
+
+// A pointer to this struct is passed to OMX_SetParameter when the extension
+// index for the 'OMX.google.android.index.useAndroidNativeBuffer' extension is
+// given. This call will only be performed if a prior call was made with the
+// 'OMX.google.android.index.enableAndroidNativeBuffers' extension index,
+// enabling use of Android native buffers.
+struct UseAndroidNativeBufferParams {
+ OMX_U32 nSize;
+ OMX_VERSIONTYPE nVersion;
+ OMX_U32 nPortIndex;
+ OMX_PTR pAppPrivate;
+ OMX_BUFFERHEADERTYPE **bufferHeader;
+ const sp<android_native_buffer_t>& nativeBuffer;
+};
+
+} // namespace android
+
extern android::VideoRenderer *createRenderer(
const android::sp<android::ISurface> &surface,
const char *componentName,
@@ -35,4 +85,3 @@
extern android::OMXPluginBase *createOMXPlugin();
#endif // HARDWARE_API_H_
-
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..1e447f1 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
@@ -91,6 +92,8 @@
kKeyNotRealTime = 'ntrt', // bool (int32_t)
+ // Ogg files can be tagged to be automatically looping...
+ kKeyAutoLoop = 'autL', // bool (int32_t)
};
enum {
diff --git a/libs/rs/rsProgramFragment.cpp b/libs/rs/rsProgramFragment.cpp
index ec9c569..83321d3 100644
--- a/libs/rs/rsProgramFragment.cpp
+++ b/libs/rs/rsProgramFragment.cpp
@@ -62,15 +62,6 @@
mTextureEnableMask |= 2;
}
- mUniformCount = 0;
- mUniformNames[mUniformCount++].setTo("uni_Tex0");
- mUniformNames[mUniformCount++].setTo("uni_Tex1");
-
- mConstantColorUniformIndex = -1;
- //if (!mVaryingColor) {
- mConstantColorUniformIndex = mUniformCount;
- mUniformNames[mUniformCount++].setTo("uni_Color");
- //}
init(rsc);
}
@@ -89,10 +80,6 @@
LOGE("Custom FP");
- mUniformCount = 2;
- mUniformNames[0].setTo("uni_Tex0");
- mUniformNames[1].setTo("uni_Tex1");
-
mTextureEnableMask = (1 << mTextureCount) -1;
init(rsc);
@@ -156,7 +143,7 @@
rsc->checkError("ProgramFragment::setupGL2 tex env");
}
- glUniform1i(sc->fragUniformSlot(ct), ct);
+ glUniform1i(sc->fragUniformSlot(mTextureUniformIndexStart + ct), ct);
rsc->checkError("ProgramFragment::setupGL2 uniforms");
}
@@ -177,12 +164,12 @@
mShader.append("uniform vec4 uni_Color;\n");
if (mUserShader.length() > 1) {
+ appendUserConstants();
for (uint32_t ct=0; ct < mTextureCount; ct++) {
char buf[256];
sprintf(buf, "uniform sampler2D uni_Tex%i;\n", ct);
mShader.append(buf);
}
- appendUserConstants();
mShader.append(mUserShader);
} else {
uint32_t mask = mTextureEnableMask;
@@ -275,11 +262,20 @@
void ProgramFragment::init(Context *rsc)
{
+ mUniformCount = 0;
+ //if (!mVaryingColor) {
+ mConstantColorUniformIndex = mUniformCount;
+ mUniformNames[mUniformCount++].setTo("uni_Color");
+ //}
+
if (mUserShader.size() > 0) {
for (uint32_t ct=0; ct < mConstantCount; ct++) {
initAddUserElement(mConstantTypes[ct]->getElement(), mUniformNames, &mUniformCount, "UNI_");
}
}
+ mTextureUniformIndexStart = mUniformCount;
+ mUniformNames[mUniformCount++].setTo("uni_Tex0");
+ mUniformNames[mUniformCount++].setTo("uni_Tex1");
createShader();
}
diff --git a/libs/rs/rsProgramFragment.h b/libs/rs/rsProgramFragment.h
index 7c1598e..f08bb25 100644
--- a/libs/rs/rsProgramFragment.h
+++ b/libs/rs/rsProgramFragment.h
@@ -57,6 +57,7 @@
float mConstantColor[4];
int32_t mConstantColorUniformIndex;
+ int32_t mTextureUniformIndexStart;
};
class ProgramFragmentState
diff --git a/media/libmedia/IOMX.cpp b/media/libmedia/IOMX.cpp
index f3804b8..40801a2 100644
--- a/media/libmedia/IOMX.cpp
+++ b/media/libmedia/IOMX.cpp
@@ -21,7 +21,9 @@
SET_PARAMETER,
GET_CONFIG,
SET_CONFIG,
+ ENABLE_GRAPHIC_BUFFERS,
USE_BUFFER,
+ USE_GRAPHIC_BUFFER,
ALLOC_BUFFER,
ALLOC_BUFFER_WITH_BACKUP,
FREE_BUFFER,
@@ -216,6 +218,19 @@
return reply.readInt32();
}
+ virtual status_t enableGraphicBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.writeInt32((uint32_t)enable);
+ remote()->transact(ENABLE_GRAPHIC_BUFFERS, data, &reply);
+
+ status_t err = reply.readInt32();
+ return err;
+ }
+
virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) {
@@ -238,6 +253,29 @@
return err;
}
+
+ virtual status_t useGraphicBuffer(
+ node_id node, OMX_U32 port_index,
+ const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IOMX::getInterfaceDescriptor());
+ data.writeIntPtr((intptr_t)node);
+ data.writeInt32(port_index);
+ data.write(*graphicBuffer);
+ remote()->transact(USE_GRAPHIC_BUFFER, data, &reply);
+
+ status_t err = reply.readInt32();
+ if (err != OK) {
+ *buffer = 0;
+
+ return err;
+ }
+
+ *buffer = (void*)reply.readIntPtr();
+
+ return err;
+ }
+
virtual status_t allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data) {
@@ -541,6 +579,20 @@
return NO_ERROR;
}
+ case ENABLE_GRAPHIC_BUFFERS:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ OMX_BOOL enable = (OMX_BOOL)data.readInt32();
+
+ status_t err = enableGraphicBuffers(node, port_index, enable);
+ reply->writeInt32(err);
+
+ return NO_ERROR;
+ }
+
case USE_BUFFER:
{
CHECK_INTERFACE(IOMX, data, reply);
@@ -561,6 +613,27 @@
return NO_ERROR;
}
+ case USE_GRAPHIC_BUFFER:
+ {
+ CHECK_INTERFACE(IOMX, data, reply);
+
+ node_id node = (void*)data.readIntPtr();
+ OMX_U32 port_index = data.readInt32();
+ sp<GraphicBuffer> graphicBuffer = new GraphicBuffer();
+ data.read(*graphicBuffer);
+
+ buffer_id buffer;
+ status_t err = useGraphicBuffer(
+ node, port_index, graphicBuffer, &buffer);
+ reply->writeInt32(err);
+
+ if (err == OK) {
+ reply->writeIntPtr((intptr_t)buffer);
+ }
+
+ return NO_ERROR;
+ }
+
case ALLOC_BUFFER:
{
CHECK_INTERFACE(IOMX, data, reply);
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index e78a616..fd5f30b 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -50,6 +50,9 @@
namespace android {
+static int64_t kLowWaterMarkUs = 2000000ll; // 2secs
+static int64_t kHighWaterMarkUs = 10000000ll; // 10secs
+
struct AwesomeEvent : public TimedEventQueue::Event {
AwesomeEvent(
AwesomePlayer *player,
@@ -330,6 +333,13 @@
} else if (!haveAudio && !strncasecmp(mime, "audio/", 6)) {
setAudioSource(extractor->getTrack(i));
haveAudio = true;
+
+ sp<MetaData> fileMeta = extractor->getMetaData();
+ int32_t loop;
+ if (fileMeta != NULL
+ && fileMeta->findInt32(kKeyAutoLoop, &loop) && loop != 0) {
+ mFlags |= AUTO_LOOPING;
+ }
}
if (haveAudio && haveVideo) {
@@ -453,6 +463,25 @@
}
}
+// Returns true iff cached duration is available/applicable.
+bool AwesomePlayer::getCachedDuration_l(int64_t *durationUs, bool *eos) {
+ off_t totalSize;
+
+ if (mRTSPController != NULL) {
+ *durationUs = mRTSPController->getQueueDurationUs(eos);
+ return true;
+ } else if (mCachedSource != NULL && mDurationUs >= 0
+ && mCachedSource->getSize(&totalSize) == OK) {
+ int64_t bitrate = totalSize * 8000000ll / mDurationUs; // in bits/sec
+
+ size_t cachedDataRemaining = mCachedSource->approxDataRemaining(eos);
+ *durationUs = cachedDataRemaining * 8000000ll / bitrate;
+ return true;
+ }
+
+ return false;
+}
+
void AwesomePlayer::onBufferingUpdate() {
Mutex::Autolock autoLock(mLock);
if (!mBufferingEventPending) {
@@ -460,78 +489,82 @@
}
mBufferingEventPending = false;
- int kLowWaterMarkSecs = 2;
- int kHighWaterMarkSecs = 10;
-
- if (mRTSPController != NULL) {
+ if (mCachedSource != NULL) {
bool eos;
- int64_t queueDurationUs = mRTSPController->getQueueDurationUs(&eos);
+ size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
- LOGV("queueDurationUs = %.2f secs", queueDurationUs / 1E6);
+ if (eos) {
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
+ } else {
+ off_t size;
+ if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
+ int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
+ size_t cachedSize = mCachedSource->cachedSize();
+ int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
+
+ int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
+ if (percentage > 100) {
+ percentage = 100;
+ }
+
+ notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
+ } else {
+ // We don't know the bitrate of the stream, use absolute size
+ // limits to maintain the cache.
+
+ const size_t kLowWaterMarkBytes = 400000;
+ const size_t kHighWaterMarkBytes = 1000000;
+
+ if ((mFlags & PLAYING) && !eos
+ && (cachedDataRemaining < kLowWaterMarkBytes)) {
+ LOGI("cache is running low (< %d) , pausing.",
+ kLowWaterMarkBytes);
+ mFlags |= CACHE_UNDERRUN;
+ pause_l();
+ notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
+ } else if (eos || cachedDataRemaining > kHighWaterMarkBytes) {
+ if (mFlags & CACHE_UNDERRUN) {
+ LOGI("cache has filled up (> %d), resuming.",
+ kHighWaterMarkBytes);
+ mFlags &= ~CACHE_UNDERRUN;
+ play_l();
+ notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+ } else if (mFlags & PREPARING) {
+ LOGV("cache has filled up (> %d), prepare is done",
+ kHighWaterMarkBytes);
+ finishAsyncPrepare_l();
+ }
+ }
+ }
+ }
+ }
+
+ int64_t cachedDurationUs;
+ bool eos;
+ if (getCachedDuration_l(&cachedDurationUs, &eos)) {
if ((mFlags & PLAYING) && !eos
- && (queueDurationUs < kLowWaterMarkSecs * 1000000ll)) {
- LOGI("rtsp cache is running low, pausing.");
+ && (cachedDurationUs < kLowWaterMarkUs)) {
+ LOGI("cache is running low (%.2f secs) , pausing.",
+ cachedDurationUs / 1E6);
mFlags |= CACHE_UNDERRUN;
pause_l();
notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if ((mFlags & CACHE_UNDERRUN)
- && (eos || queueDurationUs > kHighWaterMarkSecs * 1000000ll)) {
- LOGI("rtsp cache has filled up, resuming.");
- mFlags &= ~CACHE_UNDERRUN;
- play_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- }
-
- postBufferingEvent_l();
- return;
- }
-
- if (mCachedSource == NULL) {
- return;
- }
-
- bool eos;
- size_t cachedDataRemaining = mCachedSource->approxDataRemaining(&eos);
-
- size_t lowWatermark = 400000;
- size_t highWatermark = 1000000;
-
- if (eos) {
- notifyListener_l(MEDIA_BUFFERING_UPDATE, 100);
- } else {
- off_t size;
- if (mDurationUs >= 0 && mCachedSource->getSize(&size) == OK) {
- int64_t bitrate = size * 8000000ll / mDurationUs; // in bits/sec
-
- size_t cachedSize = mCachedSource->cachedSize();
- int64_t cachedDurationUs = cachedSize * 8000000ll / bitrate;
-
- int percentage = 100.0 * (double)cachedDurationUs / mDurationUs;
- if (percentage > 100) {
- percentage = 100;
+ } else if (eos || cachedDurationUs > kHighWaterMarkUs) {
+ if (mFlags & CACHE_UNDERRUN) {
+ LOGI("cache has filled up (%.2f secs), resuming.",
+ cachedDurationUs / 1E6);
+ mFlags &= ~CACHE_UNDERRUN;
+ play_l();
+ notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
+ } else if (mFlags & PREPARING) {
+ LOGV("cache has filled up (%.2f secs), prepare is done",
+ cachedDurationUs / 1E6);
+ finishAsyncPrepare_l();
}
-
- notifyListener_l(MEDIA_BUFFERING_UPDATE, percentage);
-
- lowWatermark = kLowWaterMarkSecs * bitrate / 8;
- highWatermark = kHighWaterMarkSecs * bitrate / 8;
}
}
- if ((mFlags & PLAYING) && !eos && (cachedDataRemaining < lowWatermark)) {
- LOGI("cache is running low (< %d) , pausing.", lowWatermark);
- mFlags |= CACHE_UNDERRUN;
- pause_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_START);
- } else if ((mFlags & CACHE_UNDERRUN)
- && (eos || cachedDataRemaining > highWatermark)) {
- LOGI("cache has filled up (> %d), resuming.", highWatermark);
- mFlags &= ~CACHE_UNDERRUN;
- play_l();
- notifyListener_l(MEDIA_INFO, MEDIA_INFO_BUFFERING_END);
- }
-
postBufferingEvent_l();
}
@@ -564,7 +597,7 @@
return;
}
- if (mFlags & LOOPING) {
+ if (mFlags & (LOOPING | AUTO_LOOPING)) {
seekTo_l(0);
if (mVideoSource != NULL) {
@@ -1459,45 +1492,49 @@
}
void AwesomePlayer::onPrepareAsyncEvent() {
- {
- Mutex::Autolock autoLock(mLock);
+ Mutex::Autolock autoLock(mLock);
- if (mFlags & PREPARE_CANCELLED) {
- LOGI("prepare was cancelled before doing anything");
- abortPrepare(UNKNOWN_ERROR);
+ if (mFlags & PREPARE_CANCELLED) {
+ LOGI("prepare was cancelled before doing anything");
+ abortPrepare(UNKNOWN_ERROR);
+ return;
+ }
+
+ if (mUri.size() > 0) {
+ status_t err = finishSetDataSource_l();
+
+ if (err != OK) {
+ abortPrepare(err);
return;
}
-
- if (mUri.size() > 0) {
- status_t err = finishSetDataSource_l();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- if (mVideoTrack != NULL && mVideoSource == NULL) {
- status_t err = initVideoDecoder();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
-
- if (mAudioTrack != NULL && mAudioSource == NULL) {
- status_t err = initAudioDecoder();
-
- if (err != OK) {
- abortPrepare(err);
- return;
- }
- }
}
- Mutex::Autolock autoLock(mLock);
+ if (mVideoTrack != NULL && mVideoSource == NULL) {
+ status_t err = initVideoDecoder();
+ if (err != OK) {
+ abortPrepare(err);
+ return;
+ }
+ }
+
+ if (mAudioTrack != NULL && mAudioSource == NULL) {
+ status_t err = initAudioDecoder();
+
+ if (err != OK) {
+ abortPrepare(err);
+ return;
+ }
+ }
+
+ if (mCachedSource != NULL || mRTSPController != NULL) {
+ postBufferingEvent_l();
+ } else {
+ finishAsyncPrepare_l();
+ }
+}
+
+void AwesomePlayer::finishAsyncPrepare_l() {
if (mIsAsyncPrepare) {
if (mVideoSource == NULL) {
notifyListener_l(MEDIA_SET_VIDEO_SIZE, 0, 0);
@@ -1513,8 +1550,6 @@
mFlags |= PREPARED;
mAsyncPrepareEvent = NULL;
mPreparedCondition.broadcast();
-
- postBufferingEvent_l();
}
status_t AwesomePlayer::suspend() {
@@ -1554,7 +1589,7 @@
state->mUriHeaders = mUriHeaders;
state->mFileSource = mFileSource;
- state->mFlags = mFlags & (PLAYING | LOOPING | AT_EOS);
+ state->mFlags = mFlags & (PLAYING | AUTO_LOOPING | LOOPING | AT_EOS);
getPosition(&state->mPositionUs);
if (mLastVideoBuffer) {
@@ -1615,7 +1650,7 @@
seekTo_l(state->mPositionUs);
- mFlags = state->mFlags & (LOOPING | AT_EOS);
+ mFlags = state->mFlags & (AUTO_LOOPING | LOOPING | AT_EOS);
if (state->mLastVideoFrame && (mSurface != NULL || mISurface != NULL)) {
mVideoRenderer =
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/media/libstagefright/OggExtractor.cpp b/media/libstagefright/OggExtractor.cpp
index 2c1311a..7a8cf32 100644
--- a/media/libstagefright/OggExtractor.cpp
+++ b/media/libstagefright/OggExtractor.cpp
@@ -592,6 +592,7 @@
{ "DATE", kKeyDate },
{ "LYRICIST", kKeyWriter },
{ "METADATA_BLOCK_PICTURE", kKeyAlbumArt },
+ { "ANDROID_LOOP", kKeyAutoLoop },
};
for (int i = 0; i < mVc.comments; ++i) {
@@ -605,12 +606,15 @@
extractAlbumArt(
&comment[tagLen + 1],
mVc.comment_lengths[i] - tagLen - 1);
+ } else if (kMap[j].mKey == kKeyAutoLoop) {
+ if (!strcasecmp(&comment[tagLen + 1], "true")) {
+ mFileMeta->setInt32(kKeyAutoLoop, true);
+ }
} else {
mFileMeta->setCString(kMap[j].mKey, &comment[tagLen + 1]);
}
}
}
-
}
#if 0
diff --git a/media/libstagefright/include/AwesomePlayer.h b/media/libstagefright/include/AwesomePlayer.h
index f34eb45..ea2f7d5 100644
--- a/media/libstagefright/include/AwesomePlayer.h
+++ b/media/libstagefright/include/AwesomePlayer.h
@@ -107,6 +107,7 @@
CACHE_UNDERRUN = 128,
AUDIO_AT_EOS = 256,
VIDEO_AT_EOS = 512,
+ AUTO_LOOPING = 1024,
};
mutable Mutex mLock;
@@ -241,6 +242,9 @@
void onCheckAudioStatus();
void onPrepareAsyncEvent();
void abortPrepare(status_t err);
+ void finishAsyncPrepare_l();
+
+ bool getCachedDuration_l(int64_t *durationUs, bool *eos);
status_t finishSetDataSource_l();
diff --git a/media/libstagefright/include/OMX.h b/media/libstagefright/include/OMX.h
index c99da59..83b75ad 100644
--- a/media/libstagefright/include/OMX.h
+++ b/media/libstagefright/include/OMX.h
@@ -59,10 +59,17 @@
node_id node, OMX_INDEXTYPE index,
const void *params, size_t size);
+ virtual status_t enableGraphicBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable);
+
virtual status_t useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer);
+ virtual status_t useGraphicBuffer(
+ node_id node, OMX_U32 port_index,
+ const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer);
+
virtual status_t allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data);
diff --git a/media/libstagefright/include/OMXNodeInstance.h b/media/libstagefright/include/OMXNodeInstance.h
index b5b31ac..8c7c562 100644
--- a/media/libstagefright/include/OMXNodeInstance.h
+++ b/media/libstagefright/include/OMXNodeInstance.h
@@ -49,10 +49,16 @@
status_t getConfig(OMX_INDEXTYPE index, void *params, size_t size);
status_t setConfig(OMX_INDEXTYPE index, const void *params, size_t size);
+ status_t enableGraphicBuffers(OMX_U32 portIndex, OMX_BOOL enable);
+
status_t useBuffer(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer);
+ status_t useGraphicBuffer(
+ OMX_U32 portIndex, const sp<GraphicBuffer> &graphicBuffer,
+ OMX::buffer_id *buffer);
+
status_t allocateBuffer(
OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
void **buffer_data);
@@ -125,4 +131,3 @@
} // namespace android
#endif // OMX_NODE_INSTANCE_H_
-
diff --git a/media/libstagefright/omx/OMX.cpp b/media/libstagefright/omx/OMX.cpp
index 88b9605..37243ad 100644
--- a/media/libstagefright/omx/OMX.cpp
+++ b/media/libstagefright/omx/OMX.cpp
@@ -287,6 +287,11 @@
index, params, size);
}
+status_t OMX::enableGraphicBuffers(
+ node_id node, OMX_U32 port_index, OMX_BOOL enable) {
+ return findInstance(node)->enableGraphicBuffers(port_index, enable);
+}
+
status_t OMX::useBuffer(
node_id node, OMX_U32 port_index, const sp<IMemory> ¶ms,
buffer_id *buffer) {
@@ -294,6 +299,13 @@
port_index, params, buffer);
}
+status_t OMX::useGraphicBuffer(
+ node_id node, OMX_U32 port_index,
+ const sp<GraphicBuffer> &graphicBuffer, buffer_id *buffer) {
+ return findInstance(node)->useGraphicBuffer(
+ port_index, graphicBuffer, buffer);
+}
+
status_t OMX::allocateBuffer(
node_id node, OMX_U32 port_index, size_t size,
buffer_id *buffer, void **buffer_data) {
@@ -530,4 +542,3 @@
}
} // namespace android
-
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 5db516e..ba4d765 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -24,6 +24,7 @@
#include <OMX_Component.h>
#include <binder/IMemory.h>
+#include <media/stagefright/HardwareAPI.h>
#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaErrors.h>
@@ -40,6 +41,11 @@
mIsBackup(false) {
}
+ BufferMeta(const sp<GraphicBuffer> &graphicBuffer)
+ : mGraphicBuffer(graphicBuffer),
+ mIsBackup(false) {
+ }
+
void CopyFromOMX(const OMX_BUFFERHEADERTYPE *header) {
if (!mIsBackup) {
return;
@@ -61,6 +67,7 @@
}
private:
+ sp<GraphicBuffer> mGraphicBuffer;
sp<IMemory> mMem;
size_t mSize;
bool mIsBackup;
@@ -240,6 +247,43 @@
return StatusFromOMXError(err);
}
+status_t OMXNodeInstance::enableGraphicBuffers(
+ OMX_U32 portIndex, OMX_BOOL enable) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_INDEXTYPE index;
+ OMX_ERRORTYPE err = OMX_GetExtensionIndex(
+ mHandle,
+ const_cast<OMX_STRING>("OMX.google.android.index.enableAndroidNativeBuffers"),
+ &index);
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_GetExtensionIndex failed");
+
+ return StatusFromOMXError(err);
+ }
+
+ OMX_VERSIONTYPE ver;
+ ver.s.nVersionMajor = 1;
+ ver.s.nVersionMinor = 0;
+ ver.s.nRevision = 0;
+ ver.s.nStep = 0;
+ EnableAndroidNativeBuffersParams params = {
+ sizeof(EnableAndroidNativeBuffersParams), ver, portIndex, enable,
+ };
+
+ err = OMX_SetParameter(mHandle, index, ¶ms);
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_EnableAndroidNativeBuffers failed with error %d (0x%08x)",
+ err, err);
+
+ return UNKNOWN_ERROR;
+ }
+
+ return OK;
+}
+
status_t OMXNodeInstance::useBuffer(
OMX_U32 portIndex, const sp<IMemory> ¶ms,
OMX::buffer_id *buffer) {
@@ -273,6 +317,60 @@
return OK;
}
+status_t OMXNodeInstance::useGraphicBuffer(
+ OMX_U32 portIndex, const sp<GraphicBuffer>& graphicBuffer,
+ OMX::buffer_id *buffer) {
+ Mutex::Autolock autoLock(mLock);
+
+ OMX_INDEXTYPE index;
+ OMX_ERRORTYPE err = OMX_GetExtensionIndex(
+ mHandle,
+ const_cast<OMX_STRING>("OMX.google.android.index.useAndroidNativeBuffer"),
+ &index);
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_GetExtensionIndex failed");
+
+ return StatusFromOMXError(err);
+ }
+
+ BufferMeta *bufferMeta = new BufferMeta(graphicBuffer);
+
+ OMX_BUFFERHEADERTYPE *header;
+
+ OMX_VERSIONTYPE ver;
+ ver.s.nVersionMajor = 1;
+ ver.s.nVersionMinor = 0;
+ ver.s.nRevision = 0;
+ ver.s.nStep = 0;
+ UseAndroidNativeBufferParams params = {
+ sizeof(UseAndroidNativeBufferParams), ver, portIndex, bufferMeta,
+ &header, graphicBuffer,
+ };
+
+ err = OMX_SetParameter(mHandle, index, ¶ms);
+
+ if (err != OMX_ErrorNone) {
+ LOGE("OMX_UseAndroidNativeBuffer failed with error %d (0x%08x)", err,
+ err);
+
+ delete bufferMeta;
+ bufferMeta = NULL;
+
+ *buffer = 0;
+
+ return UNKNOWN_ERROR;
+ }
+
+ CHECK_EQ(header->pAppPrivate, bufferMeta);
+
+ *buffer = header;
+
+ addActiveBuffer(portIndex, *buffer);
+
+ return OK;
+}
+
status_t OMXNodeInstance::allocateBuffer(
OMX_U32 portIndex, size_t size, OMX::buffer_id *buffer,
void **buffer_data) {
@@ -498,4 +596,3 @@
}
} // namespace android
-
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++) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 3cc60da..2ce8c08 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6858,7 +6858,7 @@
app.pid, app.getPackageList());
currApp.uid = app.info.uid;
if (mHeavyWeightProcess == app) {
- currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_HEAVY_WEIGHT;
+ currApp.flags |= ActivityManager.RunningAppProcessInfo.FLAG_CANT_SAVE_STATE;
}
int adj = app.curAdj;
if (adj >= EMPTY_APP_ADJ) {
diff --git a/telephony/java/com/android/internal/telephony/CallManager.java b/telephony/java/com/android/internal/telephony/CallManager.java
index 12df44e..c1232e8 100644
--- a/telephony/java/com/android/internal/telephony/CallManager.java
+++ b/telephony/java/com/android/internal/telephony/CallManager.java
@@ -1108,14 +1108,21 @@
*/
/**
- * @return list of ringing calls
+ * @return list of all ringing calls
*/
public ArrayList<Call> getRingingCalls() {
return mRingingCalls;
}
/**
- * @return list of background calls
+ * @return list of all foreground calls
+ */
+ public ArrayList<Call> getForegroundCalls() {
+ return mForegroundCalls;
+ }
+
+ /**
+ * @return list of all background calls
*/
public ArrayList<Call> getBackgroundCalls() {
return mBackgroundCalls;
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 36a2fcf..78ce473 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -285,7 +285,7 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putBoolean(DNS_SERVER_CHECK_DISABLED_KEY, b);
- editor.commit();
+ editor.apply();
}
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 8d77f76..47a170a 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -1406,7 +1406,7 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(VM_NUMBER_CDMA, number);
- editor.commit();
+ editor.apply();
}
/**
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
index 53d0f20..37a33bc 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaSMSDispatcher.java
@@ -129,7 +129,7 @@
mPhone.getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putInt(CDMAPhone.VM_COUNT_CDMA, voicemailCount);
- editor.commit();
+ editor.apply();
((CDMAPhone) mPhone).updateMessageWaitingIndicator(voicemailCount);
handled = true;
} else if (((SmsEnvelope.TELESERVICE_WMT == teleService) ||
diff --git a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
index 7331e05..d64541b 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GSMPhone.java
@@ -809,7 +809,7 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(VM_NUMBER, number);
- editor.commit();
+ editor.apply();
setVmSimImsi(getSubscriberId());
}
@@ -832,7 +832,7 @@
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
SharedPreferences.Editor editor = sp.edit();
editor.putString(VM_SIM_IMSI, imsi);
- editor.commit();
+ editor.apply();
}
public String getVoiceMailAlphaTag() {