docs: private void setupAnimations() {
      mRotationAnimator = ValueAnimator.ofFloat(0f, 360f);
      mRotationAnimator.setInterpolator(mAngleInterpolator);
      mRotationAnimator.setDuration((long) (ROTATION_ANIMATOR_DURATION / mRotationSpeed));
      mRotationAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
          float angle = getAnimatedFraction(animation) * 360f;
          setCurrentRotationAngle(angle);
        }
      });
      mRotationAnimator.setRepeatCount(ValueAnimator.INFINITE);
      mRotationAnimator.setRepeatMode(ValueAnimator.RESTART);
  
      mSweepAppearingAnimator = ValueAnimator.ofFloat(mMinSweepAngle, mMaxSweepAngle);
      mSweepAppearingAnimator.setInterpolator(mSweepInterpolator);
      mSweepAppearingAnimator.setDuration((long) (SWEEP_ANIMATOR_DURATION / mSweepSpeed));
      mSweepAppearingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
          float animatedFraction = getAnimatedFraction(animation);
          float angle;
          if (mFirstSweepAnimation) {
            angle = animatedFraction * mMaxSweepAngle;
          } else {
            angle = mMinSweepAngle + animatedFraction * (mMaxSweepAngle - mMinSweepAngle);
          }
          setCurrentSweepAngle(angle);
        }
      });
      mSweepAppearingAnimator.addListener(new SimpleAnimatorListener() {
        @Override
        public void onAnimationStart(Animator animation) {
          super.onAnimationStart(animation);
          mModeAppearing = true;
        }
  
        @Override
        protected void onPreAnimationEnd(Animator animation) {
          if (isStartedAndNotCancelled()) {
            mFirstSweepAnimation = false;
            setDisappearing();
            mSweepDisappearingAnimator.start();
          }
        }
      });
  
      mSweepDisappearingAnimator = ValueAnimator.ofFloat(mMaxSweepAngle, mMinSweepAngle);
      mSweepDisappearingAnimator.setInterpolator(mSweepInterpolator);
      mSweepDisappearingAnimator.setDuration((long) (SWEEP_ANIMATOR_DURATION / mSweepSpeed));
      mSweepDisappearingAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
          float animatedFraction = getAnimatedFraction(animation);
          setCurrentSweepAngle(mMaxSweepAngle - animatedFraction * (mMaxSweepAngle - mMinSweepAngle));
  
          long duration = animation.getDuration();
          long played = animation.getCurrentPlayTime();
          float fraction = (float) played / duration;
          if (mColors.length > 1 && fraction > .7f) { //because
            int prevColor = mCurrentColor;
            int nextColor = mColors[(mCurrentIndexColor + 1) % mColors.length];
            int newColor = (Integer) COLOR_EVALUATOR.evaluate((fraction - .7f) / (1 - .7f), prevColor, nextColor);
            mParent.getCurrentPaint().setColor(newColor);
          }
        }
      });
      mSweepDisappearingAnimator.addListener(new SimpleAnimatorListener() {
        @Override
        protected void onPreAnimationEnd(Animator animation) {
          if (isStartedAndNotCancelled()) {
            setAppearing();
            mCurrentIndexColor = (mCurrentIndexColor + 1) % mColors.length;
            mCurrentColor = mColors[mCurrentIndexColor];
            mParent.getCurrentPaint().setColor(mCurrentColor);
            mSweepAppearingAnimator.start();
          }
        }
      });
      mEndAnimator = ValueAnimator.ofFloat(1f, 0f);
      mEndAnimator.setInterpolator(END_INTERPOLATOR);
      mEndAnimator.setDuration(END_ANIMATOR_DURATION);
      mEndAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
          setEndRatio(1f - getAnimatedFraction(animation));
  
        }
      });
    }