@Override
  public boolean onTouchEvent(MotionEvent event) {
    final int y = (int) event.getY();
    mBounceHack = false;

    switch (event.getAction()) {
      case MotionEvent.ACTION_UP:
        if (!isVerticalScrollBarEnabled()) {
          setVerticalScrollBarEnabled(true);
        }
        if (getFirstVisiblePosition() == 0 && mRefreshState != REFRESHING) {
          if ((mRefreshView.getBottom() >= mRefreshViewHeight || mRefreshView.getTop() >= 0)
              && mRefreshState == RELEASE_TO_REFRESH) {
            // Initiate the refresh
            mRefreshState = REFRESHING;
            prepareForRefresh();
            onRefresh();
          } else if (mRefreshView.getBottom() < mRefreshViewHeight || mRefreshView.getTop() <= 0) {
            // Abort refresh and scroll down below the refresh view
            resetHeader();
            setSelection(1);
          }
        }
        break;
      case MotionEvent.ACTION_DOWN:
        mLastMotionY = y;
        break;
      case MotionEvent.ACTION_MOVE:
        applyHeaderPadding(event);
        break;
    }
    return super.onTouchEvent(event);
  }
  /** drop down complete, restore view status */
  public void onDropDownComplete() {
    if (isDropDownStyle) {
      setHeaderStatusClickToLoad();

      if (headerLayout.getBottom() > 0) {
        invalidateViews();
        setSecondPositionVisible();
      }
    }
  }
  @Override
  public void onScroll(
      AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    // When the refresh view is completely visible, change the text to say
    // "Release to refresh..." and flip the arrow drawable.
    if (refreshOn) {

      if (mCurrentScrollState == SCROLL_STATE_TOUCH_SCROLL && mRefreshState != REFRESHING) {
        if (firstVisibleItem == 0) {
          mRefreshViewImage.setVisibility(View.VISIBLE);
          if ((mRefreshView.getBottom() >= mRefreshViewHeight + 20 || mRefreshView.getTop() >= 0)
              && mRefreshState != RELEASE_TO_REFRESH) {
            mRefreshViewText.setText("Release to refresh...");
            mRefreshViewImage.clearAnimation();
            mRefreshViewImage.startAnimation(mFlipAnimation);
            mRefreshState = RELEASE_TO_REFRESH;
          } else if (mRefreshView.getBottom() < mRefreshViewHeight + 20
              && mRefreshState != PULL_TO_REFRESH) {
            mRefreshViewText.setText("Pull to refresh...");
            if (mRefreshState != TAP_TO_REFRESH) {
              mRefreshViewImage.clearAnimation();
              mRefreshViewImage.startAnimation(mReverseFlipAnimation);
            }
            mRefreshState = PULL_TO_REFRESH;
          }
        } else {
          mRefreshViewImage.setVisibility(View.GONE);
          resetHeader();
        }
      } else if (mCurrentScrollState == SCROLL_STATE_FLING
          && firstVisibleItem == 0
          && mRefreshState != REFRESHING) {
        setSelection(1);
        mBounceHack = true;
      } else if (mBounceHack && mCurrentScrollState == SCROLL_STATE_FLING) {
        setSelection(1);
      }
    }

    if (mOnScrollListener != null) {
      mOnScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
    }
  }
  /** Resets the list to a normal state after a refresh. */
  public void onRefreshComplete() {
    Log.d(TAG, "onRefreshComplete");

    resetHeader();

    // If refresh view is visible when loading completes, scroll down to
    // the next item.
    if (mRefreshView.getBottom() > 0) {
      invalidateViews();
      setSelection(1);
    }
  }
  @Override
  public void onScroll(
      AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    if (isDropDownStyle) {
      if (currentScrollState == SCROLL_STATE_TOUCH_SCROLL
          && currentHeaderStatus != HEADER_STATUS_LOADING) {
        /**
         * when state of ListView is SCROLL_STATE_TOUCH_SCROLL(ListView is scrolling and finger is
         * on screen) and header status is not HEADER_STATUS_LOADING
         *
         * <ul>
         *   if header layout is visiable,
         *   <li>if height of header is higher than a fixed value, then set header status to
         *       HEADER_STATUS_RELEASE_TO_LOAD.
         *   <li>else set header status to HEADER_STATUS_DROP_DOWN_TO_LOAD.
         * </ul>
         *
         * <ul>
         *   if header layout is not visiable,
         *   <li>set header status to HEADER_STATUS_CLICK_TO_LOAD.
         * </ul>
         */
        if (firstVisibleItem == 0) {
          headerImage.setVisibility(View.VISIBLE);
          int pointBottom = headerOriginalHeight + headerReleaseMinDistance;
          if (headerLayout.getBottom() >= pointBottom) {
            setHeaderStatusReleaseToLoad();
          } else if (headerLayout.getBottom() < pointBottom) {
            setHeaderStatusDropDownToLoad();
          }
        } else {
          setHeaderStatusClickToLoad();
        }
      } else if (currentScrollState == SCROLL_STATE_FLING
          && firstVisibleItem == 0
          && currentHeaderStatus != HEADER_STATUS_LOADING) {
        /**
         * when state of ListView is SCROLL_STATE_FLING(ListView is scrolling but finger has leave
         * screen) and first item(header layout) is visible and header status is not
         * HEADER_STATUS_LOADING, then hide first item, set second item visible and set
         * hasReachedTop true.
         */
        setSecondPositionVisible();
        hasReachedTop = true;
      } else if (currentScrollState == SCROLL_STATE_FLING && hasReachedTop) {
        /**
         * when state of ListView is SCROLL_STATE_FLING(ListView is scrolling but finger has leave
         * screen) and hasReachedTop is true(it's because flick back), then hide first item, set
         * second item visible.
         */
        setSecondPositionVisible();
      }
    }

    // if isOnBottomStyle and isAutoLoadOnBottom and hasMore, then call
    // onBottom function auto
    if (isOnBottomStyle && isAutoLoadOnBottom && hasMore) {
      if (firstVisibleItem > 0
          && totalItemCount > 0
          && (firstVisibleItem + visibleItemCount == totalItemCount)) {
        onBottom();
      }
    }
    if (onScrollListener != null) {
      onScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
    }
  }