@Override
  public boolean onTouchEvent(MotionEvent event) {
    // Avoid short-circuit logic evaluation - ensure all gesture detectors see all events so
    // that they generate correct notifications.
    boolean handled = mScroller.onTouchEvent(event);
    handled |= mZoomer.onTouchEvent(event);
    handled |= mTapDetector.onTouchEvent(event);
    mSwipePinchDetector.onTouchEvent(event);

    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
        mViewer.setAnimationEnabled(false);
        mSuppressCursorMovement = false;
        mSuppressFling = false;
        mSwipeCompleted = false;
        break;

      case MotionEvent.ACTION_POINTER_DOWN:
        mTotalMotionY = 0;
        break;

      case MotionEvent.ACTION_UP:
        releaseAnyHeldButton();
        break;

      default:
        break;
    }
    return handled;
  }
  @Override
  public void processAnimation() {
    int previousX = mFlingScroller.getCurrX();
    int previousY = mFlingScroller.getCurrY();
    if (!mFlingScroller.computeScrollOffset()) {
      mViewer.setAnimationEnabled(false);
      return;
    }
    int deltaX = mFlingScroller.getCurrX() - previousX;
    int deltaY = mFlingScroller.getCurrY() - previousY;
    float[] delta = {deltaX, deltaY};
    synchronized (mRenderData) {
      Matrix canvasToImage = new Matrix();
      mRenderData.transform.invert(canvasToImage);
      canvasToImage.mapVectors(delta);
    }

    moveCursor(mCursorPosition.x + delta[0], mCursorPosition.y + delta[1]);
  }