* Add a dependency to this Node. The dependency includes information about the node that this
  * node is dependency upon and the nature of the dependency.
  * @param dependency
 public void addDependency(Dependency dependency) {
   if (dependencies == null) {
     dependencies = new ArrayList<Dependency>();
     nodeDependencies = new ArrayList<Node>();
   if (!nodeDependencies.contains(dependency.node)) {
   Node dependencyNode = dependency.node;
   if (dependencyNode.nodeDependents == null) {
     dependencyNode.nodeDependents = new ArrayList<Node>();
  public AnimatorSet clone() {
    final AnimatorSet anim = (AnimatorSet) super.clone();
     * The basic clone() operation copies all items. This doesn't work very well for
     * AnimatorSet, 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.mTerminated = false;
    anim.mStarted = false;
    anim.mPlayingSet = new ArrayList<Animator>();
    anim.mNodeMap = new HashMap<Animator, Node>();
    anim.mNodes = new ArrayList<Node>();
    anim.mSortedNodes = new ArrayList<Node>();

    // 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 AnimatorSet.
    // We need to track the old/new nodes in order to reconstruct the dependencies in the clone.
    HashMap<Node, Node> nodeCloneMap = new HashMap<Node, Node>(); // <old, new>
    for (Node node : mNodes) {
      Node nodeClone = node.clone();
      nodeCloneMap.put(node, 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 AnimatorSet; these will
      // be set up when the clone's nodes are sorted
      ArrayList<AnimatorListener> cloneListeners = nodeClone.animation.getListeners();
      if (cloneListeners != null) {
        ArrayList<AnimatorListener> listenersToRemove = null;
        for (AnimatorListener listener : cloneListeners) {
          if (listener instanceof AnimatorSetListener) {
            if (listenersToRemove == null) {
              listenersToRemove = new ArrayList<AnimatorListener>();
        if (listenersToRemove != null) {
          for (AnimatorListener listener : listenersToRemove) {
    // 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);

    return anim;