/**
   * Adds an animation to be played after the current or last queued animation for a track. If the
   * track is empty, it is equivalent to calling {@link #setAnimation(int, Animation, boolean)}.
   *
   * @param delay Seconds to begin this animation after the start of the previous animation. May be
   *     <= 0 to use the animation duration of the previous track minus any mix duration plus the
   *     <code>delay</code>.
   * @return A track entry to allow further customization of animation playback. References to the
   *     track entry must not be kept after the {@link AnimationStateListener#dispose(TrackEntry)}
   *     event occurs.
   */
  public TrackEntry addAnimation(int trackIndex, Animation animation, boolean loop, float delay) {
    if (animation == null) throw new IllegalArgumentException("animation cannot be null.");

    TrackEntry last = expandToIndex(trackIndex);
    if (last != null) {
      while (last.next != null) last = last.next;
    }

    TrackEntry entry = trackEntry(trackIndex, animation, loop, last);

    if (last == null) {
      setCurrent(trackIndex, entry, true);
      queue.drain();
    } else {
      last.next = entry;
      if (delay <= 0) {
        float duration = last.animationEnd - last.animationStart;
        if (duration != 0)
          delay +=
              duration * (1 + (int) (last.trackTime / duration))
                  - data.getMix(last.animation, animation);
        else delay = 0;
      }
    }

    entry.delay = delay;
    return entry;
  }
 private void disposeNext(TrackEntry entry) {
   TrackEntry next = entry.next;
   while (next != null) {
     queue.dispose(next);
     next = next.next;
   }
   entry.next = null;
 }