private void setCurrentPlayTimeByStateAndPlay(long[] tab, State mState) {
   switch (mState) {
     case ANIMATING_LINE_TO_DOT:
       mArrowToLineAnimatorSet.start();
       for (int i = 0; i < mArrowToLineAnimatorSet.getChildAnimations().size(); i++) {
         ((ValueAnimator) mArrowToLineAnimatorSet.getChildAnimations().get(i))
             .setCurrentPlayTime(tab[i]);
       }
       break;
     case ANIMATING_PROGRESS:
       mProgressAnimationSet.start();
       for (int i = 0; i < mProgressAnimationSet.getChildAnimations().size(); i++) {
         ((ValueAnimator) mProgressAnimationSet.getChildAnimations().get(i))
             .setCurrentPlayTime(tab[i]);
       }
       break;
     case ANIMATING_ERROR:
       mErrorAnimation.start();
       mErrorAnimation.setCurrentPlayTime(tab[0]);
       break;
     case ANIMATING_SUCCESS:
       mSuccessAnimation.start();
       mSuccessAnimation.setCurrentPlayTime(tab[0]);
       break;
   }
 }
  public void onAnimationUpdate(final ValueAnimator animation) {
    final long currentTime = System.currentTimeMillis();
    if (mStartTime == -1) {
      mStartFrame = sGlobalFrameCounter;
      mStartTime = currentTime;
    }

    final long currentPlayTime = animation.getCurrentPlayTime();
    boolean isFinalFrame = Float.compare(1f, animation.getAnimatedFraction()) == 0;

    if (!mHandlingOnAnimationUpdate
        && sVisible
        &&
        // If the current play time exceeds the duration, or the animated fraction is 1,
        // the animation will get finished, even if we call setCurrentPlayTime -- therefore
        // don't adjust the animation in that case
        currentPlayTime < animation.getDuration()
        && !isFinalFrame) {
      mHandlingOnAnimationUpdate = true;
      long frameNum = sGlobalFrameCounter - mStartFrame;
      // If we haven't drawn our first frame, reset the time to t = 0
      // (give up after MAX_DELAY ms of waiting though - might happen, for example, if we
      // are no longer in the foreground and no frames are being rendered ever)
      if (frameNum == 0 && currentTime < mStartTime + MAX_DELAY && currentPlayTime > 0) {
        // The first frame on animations doesn't always trigger an invalidate...
        // force an invalidate here to make sure the animation continues to advance
        mTarget.getRootView().invalidate();
        animation.setCurrentPlayTime(0);
        // For the second frame, if the first frame took more than 16ms,
        // adjust the start time and pretend it took only 16ms anyway. This
        // prevents a large jump in the animation due to an expensive first frame
      } else if (frameNum == 1
          && currentTime < mStartTime + MAX_DELAY
          && !mAdjustedSecondFrameTime
          && currentTime > mStartTime + IDEAL_FRAME_DURATION
          && currentPlayTime > IDEAL_FRAME_DURATION) {
        animation.setCurrentPlayTime(IDEAL_FRAME_DURATION);
        mAdjustedSecondFrameTime = true;
      } else {
        if (frameNum > 1) {
          mTarget.post(
              new Runnable() {
                public void run() {
                  animation.removeUpdateListener(FirstFrameAnimatorHelper.this);
                }
              });
        }
        if (DEBUG) print(animation);
      }
      mHandlingOnAnimationUpdate = false;
    } else {
      if (DEBUG) print(animation);
    }
  }
 public void setCurrentPlayTime(long playTime) {
   for (ValueAnimator valueAnimator : getAllAnimator()) {
     playTime -= valueAnimator.getStartDelay();
     if (playTime < 0) playTime = 0;
     valueAnimator.setCurrentPlayTime(playTime);
   }
 }
 @Override
 public void onAnimationUpdate(ValueAnimator animation) {
   // No need for synchronization as this always run on main thread anyway
   TextView v = textView.get();
   if (v != null) {
     if (isAttachedToHierarchy(v)) {
       shift = (Integer) animation.getAnimatedValue();
       v.invalidate();
     } else {
       animation.setCurrentPlayTime(0);
       animation.start();
     }
   } else {
     // The textview has been destroyed and teardown() hasn't been called
     teardown();
     if (BuildConfig.DEBUG) {
       Log.e(
           "JumpingBeans", "!!! Remember to call JumpingBeans.stopJumping() when appropriate !!!");
     }
   }
 }
 private void seek(long seekTime) {
   if (colorAnim == null) {
     createDefaultAnimation();
   }
   colorAnim.setCurrentPlayTime(seekTime);
 }