private void moveSpinner(float overscrollTop) {
    mProgress.showArrow(true);
    float originalDragPercent = overscrollTop / mTotalDragDistance;

    float dragPercent = Math.min(1f, Math.abs(originalDragPercent));
    float adjustedPercent = (float) Math.max(dragPercent - .4, 0) * 5 / 3;
    float extraOS = Math.abs(overscrollTop) - mTotalDragDistance;
    float slingshotDist =
        mUsingCustomStart ? mSpinnerFinalOffset - mOriginalOffsetTop : mSpinnerFinalOffset;
    float tensionSlingshotPercent =
        Math.max(0, Math.min(extraOS, slingshotDist * 2) / slingshotDist);
    float tensionPercent =
        (float) ((tensionSlingshotPercent / 4) - Math.pow((tensionSlingshotPercent / 4), 2)) * 2f;
    float extraMove = (slingshotDist) * tensionPercent * 2;

    int targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove);
    // where 1.0f is a full circle
    if (mCircleView.getVisibility() != View.VISIBLE) {
      mCircleView.setVisibility(View.VISIBLE);
    }
    if (!mScale) {
      ViewCompat.setScaleX(mCircleView, 1f);
      ViewCompat.setScaleY(mCircleView, 1f);
    }
    if (overscrollTop < mTotalDragDistance) {
      if (mScale) {
        setAnimationProgress(overscrollTop / mTotalDragDistance);
      }
      if (mProgress.getAlpha() > STARTING_PROGRESS_ALPHA
          && !isAnimationRunning(mAlphaStartAnimation)) {
        // Animate the alpha
        startProgressAlphaStartAnimation();
      }
      float strokeStart = adjustedPercent * .8f;
      mProgress.setStartEndTrim(0f, Math.min(MAX_PROGRESS_ANGLE, strokeStart));
      mProgress.setArrowScale(Math.min(1f, adjustedPercent));
    } else {
      if (mProgress.getAlpha() < MAX_ALPHA && !isAnimationRunning(mAlphaMaxAnimation)) {
        // Animate the alpha
        startProgressAlphaMaxAnimation();
      }
    }
    float rotation = (-0.25f + .4f * adjustedPercent + tensionPercent * 2) * .5f;
    mProgress.setProgressRotation(rotation);
    setTargetOffsetTopAndBottom(targetY - mCurrentTargetOffsetTop, true /* requires update */);
  }
 private void startScaleDownReturnToStartAnimation(
     int from, Animation.AnimationListener listener) {
   mFrom = from;
   if (isAlphaUsedForScale()) {
     mStartingScale = mProgress.getAlpha();
   } else {
     mStartingScale = ViewCompat.getScaleX(mCircleView);
   }
   mScaleDownToStartAnimation =
       new Animation() {
         @Override
         public void applyTransformation(float interpolatedTime, Transformation t) {
           float targetScale = (mStartingScale + (-mStartingScale * interpolatedTime));
           setAnimationProgress(targetScale);
           moveToStart(interpolatedTime);
         }
       };
   mScaleDownToStartAnimation.setDuration(SCALE_DOWN_DURATION);
   if (listener != null) {
     mCircleView.setAnimationListener(listener);
   }
   mCircleView.clearAnimation();
   mCircleView.startAnimation(mScaleDownToStartAnimation);
 }
 private void startProgressAlphaMaxAnimation() {
   mAlphaMaxAnimation = startAlphaAnimation(mProgress.getAlpha(), MAX_ALPHA);
 }
 private void startProgressAlphaStartAnimation() {
   mAlphaStartAnimation = startAlphaAnimation(mProgress.getAlpha(), STARTING_PROGRESS_ALPHA);
 }