();
+ int numListeners = oldListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ anim.mListeners.add(oldListeners.get(i));
+ }
+ }
+ return anim;
+ }
+
/**
* An animation listener receives notifications from an animation.
* Notifications indicate animation related events, such as the end or the
diff --git a/core/java/android/animation/Animator.java b/core/java/android/animation/Animator.java
index 385e75deef18f..eca5f0d29601a 100755
--- a/core/java/android/animation/Animator.java
+++ b/core/java/android/animation/Animator.java
@@ -80,9 +80,11 @@ public class Animator extends Animatable {
/**
* Internal variables
+ * NOTE: This object implements the clone() method, making a deep copy of any referenced
+ * objects. As other non-trivial fields are added to this class, make sure to add logic
+ * to clone() to make deep copies of them.
*/
-
// The first time that the animation's animateFrame() method is called. This time is used to
// determine elapsed time (and therefore the elapsed fraction) in subsequent calls
// to animateFrame()
@@ -402,7 +404,7 @@ public class Animator extends Animatable {
* @return The current position in time of the animation.
*/
public long getCurrentPlayTime() {
- if (!mInitialized) {
+ if (!mInitialized || mPlayingState == STOPPED) {
return 0;
}
return AnimationUtils.currentAnimationTimeMillis() - mStartTime;
@@ -954,6 +956,39 @@ public class Animator extends Animatable {
}
}
+ @Override
+ public Animator clone() throws CloneNotSupportedException {
+ final Animator anim = (Animator) super.clone();
+ if (mUpdateListeners != null) {
+ ArrayList oldListeners = mUpdateListeners;
+ anim.mUpdateListeners = new ArrayList();
+ int numListeners = oldListeners.size();
+ for (int i = 0; i < numListeners; ++i) {
+ anim.mUpdateListeners.add(oldListeners.get(i));
+ }
+ }
+ anim.mSeekTime = -1;
+ anim.mPlayingBackwards = false;
+ anim.mCurrentIteration = 0;
+ anim.mInitialized = false;
+ anim.mPlayingState = STOPPED;
+ anim.mStartedDelay = false;
+ PropertyValuesHolder[] oldValues = mValues;
+ if (oldValues != null) {
+ int numValues = oldValues.length;
+ anim.mValues = new PropertyValuesHolder[numValues];
+ for (int i = 0; i < numValues; ++i) {
+ anim.mValues[i] = oldValues[i];
+ }
+ anim.mValuesMap = new HashMap(numValues);
+ for (int i = 0; i < numValues; ++i) {
+ PropertyValuesHolder valuesHolder = mValues[i];
+ anim.mValuesMap.put(valuesHolder.getPropertyName(), valuesHolder);
+ }
+ }
+ return anim;
+ }
+
/**
* Implementors of this interface can add themselves as update listeners
* to an Animator instance to receive callbacks on every animation
diff --git a/core/java/android/animation/PropertyAnimator.java b/core/java/android/animation/PropertyAnimator.java
index 1a010a982920c..022ca7ddc999c 100644
--- a/core/java/android/animation/PropertyAnimator.java
+++ b/core/java/android/animation/PropertyAnimator.java
@@ -228,4 +228,10 @@ public final class PropertyAnimator extends Animator {
mValues[i].setAnimatedValue(mTarget);
}
}
+
+ @Override
+ public PropertyAnimator clone() throws CloneNotSupportedException {
+ final PropertyAnimator anim = (PropertyAnimator) super.clone();
+ return anim;
+ }
}
diff --git a/core/java/android/animation/Sequencer.java b/core/java/android/animation/Sequencer.java
index 2406d8af57220..77494290f9e4b 100644
--- a/core/java/android/animation/Sequencer.java
+++ b/core/java/android/animation/Sequencer.java
@@ -45,11 +45,18 @@ import java.util.HashMap;
*/
public final class Sequencer extends Animatable {
+ /**
+ * Internal variables
+ * NOTE: This object implements the clone() method, making a deep copy of any referenced
+ * objects. As other non-trivial fields are added to this class, make sure to add logic
+ * to clone() to make deep copies of them.
+ */
+
/**
* Tracks animations currently being played, so that we know what to
* cancel or end when cancel() or end() is called on this Sequencer
*/
- private final ArrayList mPlayingSet = new ArrayList();
+ private ArrayList mPlayingSet = new ArrayList();
/**
* Contains all nodes, mapped to their respective Animatables. When new
@@ -57,21 +64,21 @@ public final class Sequencer extends Animatable {
* to a single node representing that Animatable, not create a new Node
* if one already exists.
*/
- private final HashMap mNodeMap = new HashMap();
+ private HashMap mNodeMap = new HashMap();
/**
* Set of all nodes created for this Sequencer. This list is used upon
* starting the sequencer, and the nodes are placed in sorted order into the
* sortedNodes collection.
*/
- private final ArrayList mNodes = new ArrayList();
+ private ArrayList mNodes = new ArrayList();
/**
* The sorted list of nodes. This is the order in which the animations will
* be played. The details about when exactly they will be played depend
* on the dependency relationships of the nodes.
*/
- private final ArrayList mSortedNodes = new ArrayList();
+ private ArrayList mSortedNodes = new ArrayList();
/**
* Flag indicating whether the nodes should be sorted prior to playing. This
@@ -283,6 +290,75 @@ public final class Sequencer extends Animatable {
}
}
+ @Override
+ public Sequencer clone() throws CloneNotSupportedException {
+ final Sequencer anim = (Sequencer) super.clone();
+ /*
+ * The basic clone() operation copies all items. This doesn't work very well for
+ * Sequencer, because it will copy references that need to be recreated and state
+ * that may not apply. What we need to do now is put the clone in an uninitialized
+ * state, with fresh, empty data structures. Then we will build up the nodes list
+ * manually, as we clone each Node (and its animation). The clone will then be sorted,
+ * and will populate any appropriate lists, when it is started.
+ */
+ anim.mNeedsSort = true;
+ anim.mCanceled = false;
+ anim.mPlayingSet = new ArrayList();
+ anim.mNodeMap = new HashMap();
+ anim.mNodes = new ArrayList();
+ anim.mSortedNodes = new ArrayList();
+
+ // Walk through the old nodes list, cloning each node and adding it to the new nodemap.
+ // One problem is that the old node dependencies point to nodes in the old sequencer.
+ // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
+ HashMap nodeCloneMap = new HashMap(); //
+ for (Node node : mNodes) {
+ Node nodeClone = node.clone();
+ nodeCloneMap.put(node, nodeClone);
+ anim.mNodes.add(nodeClone);
+ anim.mNodeMap.put(nodeClone.animation, nodeClone);
+ // Clear out the dependencies in the clone; we'll set these up manually later
+ nodeClone.dependencies = null;
+ nodeClone.tmpDependencies = null;
+ nodeClone.nodeDependents = null;
+ nodeClone.nodeDependencies = null;
+ // clear out any listeners that were set up by the sequencer; these will
+ // be set up when the clone's nodes are sorted
+ ArrayList cloneListeners = nodeClone.animation.getListeners();
+ if (cloneListeners != null) {
+ ArrayList listenersToRemove = null;
+ for (AnimatableListener listener : cloneListeners) {
+ if (listener instanceof SequencerAnimatableListener) {
+ if (listenersToRemove == null) {
+ listenersToRemove = new ArrayList();
+ }
+ listenersToRemove.add(listener);
+ }
+ }
+ if (listenersToRemove != null) {
+ for (AnimatableListener listener : listenersToRemove) {
+ cloneListeners.remove(listener);
+ }
+ }
+ }
+ }
+ // Now that we've cloned all of the nodes, we're ready to walk through their
+ // dependencies, mapping the old dependencies to the new nodes
+ for (Node node : mNodes) {
+ Node nodeClone = nodeCloneMap.get(node);
+ if (node.dependencies != null) {
+ for (Dependency dependency : node.dependencies) {
+ Node clonedDependencyNode = nodeCloneMap.get(dependency.node);
+ Dependency cloneDependency = new Dependency(clonedDependencyNode,
+ dependency.rule);
+ nodeClone.addDependency(cloneDependency);
+ }
+ }
+ }
+
+ return anim;
+ }
+
/**
* This class is the mechanism by which animations are started based on events in other
* animations. If an animation has multiple dependencies on other animations, then
@@ -514,7 +590,7 @@ public final class Sequencer extends Animatable {
* both dependencies upon other nodes (in the dependencies list) as
* well as dependencies of other nodes upon this (in the nodeDependents list).
*/
- private static class Node {
+ private static class Node implements Cloneable {
public Animatable animation;
/**
@@ -587,6 +663,13 @@ public final class Sequencer extends Animatable {
}
dependencyNode.nodeDependents.add(this);
}
+
+ @Override
+ public Node clone() throws CloneNotSupportedException {
+ Node node = (Node) super.clone();
+ node.animation = (Animatable) animation.clone();
+ return node;
+ }
}
/**
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 274a2664a2e88..a0be0cde1f5d0 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -330,7 +330,7 @@ public class Dialog implements DialogInterface, Window.Callback,
}
/**
- * Similar to {@link Activity#onCreate}, you should initialized your dialog
+ * Similar to {@link Activity#onCreate}, you should initialize your dialog
* in this method, including calling {@link #setContentView}.
* @param savedInstanceState If this dialog is being reinitalized after a
* the hosting activity was previously shut down, holds the result from
diff --git a/core/java/android/util/TimingLogger.java b/core/java/android/util/TimingLogger.java
index 0f39c974a4d98..be442dac630af 100644
--- a/core/java/android/util/TimingLogger.java
+++ b/core/java/android/util/TimingLogger.java
@@ -24,22 +24,26 @@ import android.os.SystemClock;
* A utility class to help log timings splits throughout a method call.
* Typical usage is:
*
- * TimingLogger timings = new TimingLogger(TAG, "methodA");
- * ... do some work A ...
- * timings.addSplit("work A");
- * ... do some work B ...
- * timings.addSplit("work B");
- * ... do some work C ...
- * timings.addSplit("work C");
- * timings.dumpToLog();
+ *
+ * TimingLogger timings = new TimingLogger(TAG, "methodA");
+ * // ... do some work A ...
+ * timings.addSplit("work A");
+ * // ... do some work B ...
+ * timings.addSplit("work B");
+ * // ... do some work C ...
+ * timings.addSplit("work C");
+ * timings.dumpToLog();
+ *
*
- * The dumpToLog call would add the following to the log:
+ * The dumpToLog call would add the following to the log:
*
- * D/TAG ( 3459): methodA: begin
- * D/TAG ( 3459): methodA: 9 ms, work A
- * D/TAG ( 3459): methodA: 1 ms, work B
- * D/TAG ( 3459): methodA: 6 ms, work C
- * D/TAG ( 3459): methodA: end, 16 ms
+ *
+ * D/TAG ( 3459): methodA: begin
+ * D/TAG ( 3459): methodA: 9 ms, work A
+ * D/TAG ( 3459): methodA: 1 ms, work B
+ * D/TAG ( 3459): methodA: 6 ms, work C
+ * D/TAG ( 3459): methodA: end, 16 ms
+ *
*/
public class TimingLogger {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c13bb8c70fde7..b565fc61f9e55 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3438,7 +3438,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback, Accessibility
}
/**
- * Sets the pressed that for this view.
+ * Sets the pressed state for this view.
*
* @see #isClickable()
* @see #setClickable(boolean)
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index f3392d9617c00..9a1e41cb2bb93 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -307,7 +307,7 @@ public abstract class Animation implements Cloneable {
* animated as well as the objects parents. (This is to support animation
* sizes being specifed relative to these dimensions.)
*
- * Objects that interpret a Animations should call this method when
+ *
Objects that interpret Animations should call this method when
* the sizes of the object being animated and its parent are known, and
* before calling {@link #getTransformation}.
*