@Override
 public void onAnimationEnd(Animation animation) {
   if (mRefreshing) {
     // Make sure the progress view is fully visible
     mProgress.setAlpha(MAX_ALPHA);
     mProgress.start();
     if (mNotify) {
       if (mListener != null) {
         mListener.onRefresh();
       }
     }
   } else {
     mProgress.stop();
     mCircleView.setVisibility(View.GONE);
     setColorViewAlpha(MAX_ALPHA);
     // Return the circle to its start position
     if (mScale) {
       setAnimationProgress(0 /* animation complete and view is hidden */);
     } else {
       setTargetOffsetTopAndBottom(
           mOriginalOffsetTop - mCurrentTargetOffsetTop, true /* requires update */);
     }
   }
   mCurrentTargetOffsetTop = mCircleView.getTop();
 }
 private void setTargetOffsetTopAndBottom(int offset, boolean requiresUpdate) {
   mCircleView.bringToFront();
   mCircleView.offsetTopAndBottom(offset);
   mCurrentTargetOffsetTop = mCircleView.getTop();
   if (requiresUpdate && android.os.Build.VERSION.SDK_INT < 11) {
     invalidate();
   }
 }
  @Override
  public boolean onInterceptTouchEvent(MotionEvent ev) {
    ensureTarget();

    final int action = MotionEventCompat.getActionMasked(ev);

    if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
      mReturningToStart = false;
    }

    if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing) {
      // Fail fast if we're not in a state where a swipe is possible
      return false;
    }

    switch (action) {
      case MotionEvent.ACTION_DOWN:
        setTargetOffsetTopAndBottom(mOriginalOffsetTop - mCircleView.getTop(), true);
        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
        mIsBeingDragged = false;
        final float initialDownY = getMotionEventY(ev, mActivePointerId);
        if (initialDownY == -1) {
          return false;
        }
        mInitialDownY = initialDownY;
        break;

      case MotionEvent.ACTION_MOVE:
        if (mActivePointerId == INVALID_POINTER) {
          Log.e(LOG_TAG, "Got ACTION_MOVE event but don't have an active pointer id.");
          return false;
        }

        final float y = getMotionEventY(ev, mActivePointerId);
        if (y == -1) {
          return false;
        }
        final float yDiff = y - mInitialDownY;
        if (yDiff > mTouchSlop && !mIsBeingDragged) {
          mInitialMotionY = mInitialDownY + mTouchSlop;
          mIsBeingDragged = true;
          mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
        }
        break;

      case MotionEventCompat.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        break;

      case MotionEvent.ACTION_UP:
      case MotionEvent.ACTION_CANCEL:
        mIsBeingDragged = false;
        mActivePointerId = INVALID_POINTER;
        break;
    }

    return mIsBeingDragged;
  }
 @Override
 public void applyTransformation(float interpolatedTime, Transformation t) {
   int targetTop = 0;
   int endTarget = 0;
   if (!mUsingCustomStart) {
     endTarget = (int) (mSpinnerFinalOffset - Math.abs(mOriginalOffsetTop));
   } else {
     endTarget = (int) mSpinnerFinalOffset; // mSpinnerFinalOffset;
   }
   targetTop = (mFrom + (int) ((endTarget - mFrom) * interpolatedTime));
   int offset = targetTop - mCircleView.getTop();
   setTargetOffsetTopAndBottom(offset, false /* requires update */);
   mProgress.setArrowScale(1 - interpolatedTime);
 }
 private void moveToStart(float interpolatedTime) {
   int targetTop = 0;
   targetTop = (mFrom + (int) ((mOriginalOffsetTop - mFrom) * interpolatedTime));
   int offset = targetTop - mCircleView.getTop();
   setTargetOffsetTopAndBottom(offset, false /* requires update */);
 }