private static MotionEvent transformEventOld(MotionEvent paramMotionEvent, Matrix paramMatrix) {
   long l1 = paramMotionEvent.getDownTime();
   long l2 = paramMotionEvent.getEventTime();
   int i = paramMotionEvent.getAction();
   int j = paramMotionEvent.getPointerCount();
   int[] arrayOfInt = getPointerIds(paramMotionEvent);
   MotionEvent.PointerCoords[] arrayOfPointerCoords = getPointerCoords(paramMotionEvent);
   int k = paramMotionEvent.getMetaState();
   float f1 = paramMotionEvent.getXPrecision();
   float f2 = paramMotionEvent.getYPrecision();
   int l = paramMotionEvent.getDeviceId();
   int i1 = paramMotionEvent.getEdgeFlags();
   int i2 = paramMotionEvent.getSource();
   int i3 = paramMotionEvent.getFlags();
   float[] arrayOfFloat = new float[2 * arrayOfPointerCoords.length];
   for (int i4 = 0; i4 < j; ++i4) {
     arrayOfFloat[(i4 * 2)] = arrayOfPointerCoords[i4].x;
     arrayOfFloat[(1 + i4 * 2)] = arrayOfPointerCoords[i4].y;
   }
   paramMatrix.mapPoints(arrayOfFloat);
   for (int i5 = 0; i5 < j; ++i5) {
     arrayOfPointerCoords[i5].x = arrayOfFloat[(i5 * 2)];
     arrayOfPointerCoords[i5].y = arrayOfFloat[(1 + i5 * 2)];
     arrayOfPointerCoords[i5].orientation =
         transformAngle(paramMatrix, arrayOfPointerCoords[i5].orientation);
   }
   return MotionEvent.obtain(
       l1, l2, i, j, arrayOfInt, arrayOfPointerCoords, k, f1, f2, l, i1, i2, i3);
 }
  @Override
  public boolean dispatchTouchEvent(MotionEvent ev) {

    for (int i = getChildCount() - 1; i >= 0; i--) {
      View v = getChildAt(i);
      if (v.getVisibility() != View.VISIBLE) continue;
      Matrix m = getViewMatrix(v);
      if (m != null) {
        float[] points = new float[] {ev.getX(), ev.getY()};
        RectF rect = new RectF(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());

        Matrix realM = new Matrix(m);
        realM.preTranslate(-rect.left, -rect.top);
        realM.postTranslate(rect.left, rect.top);
        realM.mapRect(rect);
        if (rect.contains((int) points[0], (int) points[1])) {
          Matrix mi = new Matrix();
          realM.invert(mi);
          if (mi != null) {
            mi.mapPoints(points);
            ev.setEdgeFlags(
                ev.getEdgeFlags() | FLAG_TRANSFORMED); // a trick to mark the event as transformed
            ev.setLocation(
                points[0], points[1]); // without the transform point the view wont receive it
            return super.dispatchTouchEvent(ev);
          }
        }
      }
    }
    Matrix m = getMyViewMatrix();
    int flag = ev.getEdgeFlags();
    if (m != null && ((flag & FLAG_TRANSFORMED) != FLAG_TRANSFORMED)) {
      float[] points = new float[] {ev.getX(), ev.getY()}; // untransformed point
      RectF rect = new RectF(getLeft(), getTop(), getRight(), getBottom()); // untransformed rect
      Matrix realM = new Matrix(m);
      realM.preTranslate(-rect.left, -rect.top);
      realM.postTranslate(rect.left, rect.top);
      realM.mapRect(rect);
      points[0] += getLeft();
      points[1] += getTop();
      if (!rect.contains(points[0], points[1]) && ev.getAction() == MotionEvent.ACTION_DOWN) {
        Log.d("FreeLayout", this + "not dispatching");
        return false;
      }
    }
    return super.dispatchTouchEvent(ev);
  }
  private MotionEvent transformEvent(MotionEvent e, int headerPosition) {
    if (headerPosition == MATCHED_STICKIED_HEADER) {
      return e;
    }

    long downTime = e.getDownTime();
    long eventTime = e.getEventTime();
    int action = e.getAction();
    int pointerCount = e.getPointerCount();
    int[] pointerIds = getPointerIds(e);
    MotionEvent.PointerCoords[] pointerCoords = getPointerCoords(e);
    int metaState = e.getMetaState();
    float xPrecision = e.getXPrecision();
    float yPrecision = e.getYPrecision();
    int deviceId = e.getDeviceId();
    int edgeFlags = e.getEdgeFlags();
    int source = e.getSource();
    int flags = e.getFlags();

    View headerHolder = getChildAt(headerPosition);
    for (int i = 0; i < pointerCount; i++) {
      pointerCoords[i].y -= headerHolder.getTop();
    }
    MotionEvent n =
        MotionEvent.obtain(
            downTime,
            eventTime,
            action,
            pointerCount,
            pointerIds,
            pointerCoords,
            metaState,
            xPrecision,
            yPrecision,
            deviceId,
            edgeFlags,
            source,
            flags);
    return n;
  }
  /**
   * Strips the last pointer from a {@link MotionEvent} and returns the modified event. Does not
   * modify the original event.
   *
   * @param ev The MotionEvent to modify.
   * @return The modified MotionEvent.
   */
  private MotionEvent stripLastPointer(MotionEvent ev) {
    ev.getPointerCount();

    int removePointer = ev.getPointerCount() - 1;
    int removePointerId = ev.getPointerId(removePointer);

    long downTime = ev.getDownTime();
    long eventTime = ev.getEventTime();
    int action = ev.getAction();
    int pointers = ev.getPointerCount() - 1;
    int[] pointerIds = new int[pointers];
    int metaState = ev.getMetaState();
    float xPrecision = ev.getXPrecision();
    float yPrecision = ev.getYPrecision();
    int deviceId = ev.getDeviceId();
    int edgeFlags = ev.getEdgeFlags();

    switch (ev.getActionMasked()) {
      case MotionEvent.ACTION_POINTER_DOWN:
      case MotionEvent.ACTION_POINTER_UP:
        action -= 0x100;
        if (pointers == 1) {
          action -= 0x5;
        }
        break;
    }

    MotionEvent event = null;

    if (mCompatibilityMode) {
      float x = ev.getX();
      float y = ev.getY();
      float pressure = ev.getPressure();
      float size = ev.getSize();

      event =
          MotionEvent.obtain(
              downTime,
              eventTime,
              action,
              pointers,
              x,
              y,
              pressure,
              size,
              metaState,
              xPrecision,
              yPrecision,
              deviceId,
              edgeFlags);
    }

    // XXX commented out to get this to compile !
    /*
    else {
        PointerCoords[] pointerCoords = new PointerCoords[pointers];
        int source = ev.getSource();
        int flags = ev.getFlags();

        for (int i = 0; i < pointers; i++) {
            pointerIds[i] = ev.getPointerId(i);
            pointerCoords[i] = new PointerCoords();

            ev.getPointerCoords(i, pointerCoords[i]);
        }

        event = MotionEvent.obtain(downTime, eventTime, action, pointers, pointerIds,
                pointerCoords, metaState, xPrecision, yPrecision, deviceId, edgeFlags, source,
                flags);
    }
    */

    return event;
  }
  @Override
  public final boolean onTouchEvent(MotionEvent event) {

    if (!isPullToRefreshEnabled()) {
      return false;
    }

    // If we're refreshing, and the flag is set. Eat the event
    if (mDisableScrollingWhileRefreshing && isRefreshing()) {
      return true;
    }

    if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
      return false;
    }

    switch (event.getAction()) {
      case MotionEvent.ACTION_MOVE:
        {
          if (mIsBeingDragged) {
            mLastMotionY = event.getY();
            pullEvent();
            return true;
          }
          break;
        }

      case MotionEvent.ACTION_DOWN:
        {
          if (isReadyForPull()) {
            mLastMotionY = mInitialMotionY = event.getY();
            return true;
          }
          break;
        }

      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
        {
          if (mIsBeingDragged) {
            mIsBeingDragged = false;

            if (mState == RELEASE_TO_REFRESH) {
              if (null != mOnRefreshListener) {
                setRefreshingInternal(true);
                mOnRefreshListener.onRefresh(this);
                return true;

              } else if (null != mOnRefreshListener2) {
                setRefreshingInternal(true);
                if (mCurrentMode == Mode.PULL_DOWN_TO_REFRESH) {
                  mOnRefreshListener2.onPullDownToRefresh(this);
                } else if (mCurrentMode == Mode.PULL_UP_TO_REFRESH) {
                  mOnRefreshListener2.onPullUpToRefresh(this);
                }
                return true;
              } else {
                // If we don't have a listener, just reset
                resetHeader();
                return true;
              }
            }

            smoothScrollTo(0);
            return true;
          }
          break;
        }
    }

    return false;
  }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {

    if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
      // Don't handle edge touches immediately -- they may actually belong
      // to one of our
      // descendants.
      return false;
    }

    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(ev);

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {
      case MotionEvent.ACTION_DOWN:
        {
          final float y = ev.getY();
          if (!(mIsBeingDragged = inChild((int) ev.getX(), (int) y))) {
            return false;
          }

          /*
           * If being flinged and user touches, stop the fling. isFinished
           * will be false if being flinged.
           */
          if (!mScroller.isFinished()) {
            mScroller.abortAnimation();
          }

          // Remember where the motion event started
          mLastMotionY = y;
          mActivePointerId = ev.getPointerId(0);
          break;
        }
      case MotionEvent.ACTION_MOVE:
        if (mIsBeingDragged) {
          // Scroll to follow the motion event
          final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
          final float y = ev.getY(activePointerIndex);
          final int deltaY = (int) (mLastMotionY - y);
          mLastMotionY = y;

          if (isOverScrolled()) {
            // when overscrolling, move the scroller just half of the
            // finger movement, to make it feel like a spring...
            scrollBy(0, deltaY / 2);
          } else {
            scrollBy(0, deltaY);
          }
        }
        break;
      case MotionEvent.ACTION_UP:
        if (mIsBeingDragged) {
          final VelocityTracker velocityTracker = mVelocityTracker;
          velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
          int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);

          if (getChildCount() > 0 && Math.abs(initialVelocity) > mMinimumVelocity) {
            fling(-initialVelocity);
          }

          mActivePointerId = INVALID_POINTER;
          mIsBeingDragged = false;

          if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
          }
        }
        break;
      case MotionEvent.ACTION_CANCEL:
        if (mIsBeingDragged && getChildCount() > 0) {
          mActivePointerId = INVALID_POINTER;
          mIsBeingDragged = false;
          if (mVelocityTracker != null) {
            mVelocityTracker.recycle();
            mVelocityTracker = null;
          }
        }
        break;
      case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        break;
    }
    return true;
  }
  @Override
  public final boolean onTouchEvent(MotionEvent event) {

    if (!isPullToRefreshEnabled()) {
      return false;
    }

    // If we're refreshing, and the flag is set. Eat the event
    if (!mScrollingWhileRefreshingEnabled && isRefreshing()) {
      return true;
    }

    if (event.getAction() == MotionEvent.ACTION_DOWN && event.getEdgeFlags() != 0) {
      return false;
    }

    switch (event.getAction()) {
      case MotionEvent.ACTION_MOVE:
        {
          if (mIsBeingDragged) {
            mLastMotionY = event.getY();
            mLastMotionX = event.getX();
            pullEvent();
            return true;
          }
          break;
        }

      case MotionEvent.ACTION_DOWN:
        {
          if (isReadyForPull()) {
            mLastMotionY = mInitialMotionY = event.getY();
            mLastMotionX = mInitialMotionX = event.getX();
            return true;
          }
          break;
        }

      case MotionEvent.ACTION_CANCEL:
      case MotionEvent.ACTION_UP:
        {
          if (mIsBeingDragged) {
            mIsBeingDragged = false;

            if (mState == State.RELEASE_TO_REFRESH
                && (null != mOnRefreshListener || null != mOnRefreshListener2)) {
              setState(State.REFRESHING, true);
              return true;
            }

            // If we're already refreshing, just scroll back to the top
            if (isRefreshing()) {
              smoothScrollTo(0);
              return true;
            }

            // If we haven't returned by here, then we're not in a state
            // to pull, so just reset
            setState(State.RESET);

            return true;
          }
          break;
        }
    }

    return false;
  }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {

    if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
      // Don't handle edge touches immediately -- they may actually belong to one of our
      // descendants.
      return false;
    }

    if (!canScroll()) {
      return false;
    }

    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(ev);

    final int action = ev.getAction();
    final float y = ev.getY();
    final float x = ev.getX();

    switch (action) {
      case MotionEvent.ACTION_DOWN:
        /*
         * If being flinged and user touches, stop the fling. isFinished
         * will be false if being flinged.
         */
        if (!mScroller.isFinished()) {
          mScroller.abortAnimation();
        }

        // Remember where the motion event started
        mLastMotionY = y;
        mLastMotionX = x;
        break;
      case MotionEvent.ACTION_MOVE:
        // Scroll to follow the motion event
        int deltaX = (int) (mLastMotionX - x);
        int deltaY = (int) (mLastMotionY - y);
        mLastMotionX = x;
        mLastMotionY = y;

        if (deltaX < 0) {
          if (getScrollX() < 0) {
            deltaX = 0;
          }
        } else if (deltaX > 0) {
          final int rightEdge = getWidth() - getPaddingRight();
          final int availableToScroll = getChildAt(0).getRight() - getScrollX() - rightEdge;
          if (availableToScroll > 0) {
            deltaX = Math.min(availableToScroll, deltaX);
          } else {
            deltaX = 0;
          }
        }
        if (deltaY < 0) {
          if (getScrollY() < 0) {
            deltaY = 0;
          }
        } else if (deltaY > 0) {
          final int bottomEdge = getHeight() - getPaddingBottom();
          final int availableToScroll = getChildAt(0).getBottom() - getScrollY() - bottomEdge;
          if (availableToScroll > 0) {
            deltaY = Math.min(availableToScroll, deltaY);
          } else {
            deltaY = 0;
          }
        }
        if (deltaY != 0 || deltaX != 0) scrollBy(deltaX, deltaY);
        break;
      case MotionEvent.ACTION_UP:
        final VelocityTracker velocityTracker = mVelocityTracker;
        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
        int initialXVelocity = (int) velocityTracker.getXVelocity();
        int initialYVelocity = (int) velocityTracker.getYVelocity();
        if ((Math.abs(initialXVelocity) + Math.abs(initialYVelocity) > mMinimumVelocity)
            && getChildCount() > 0) {
          fling(-initialXVelocity, -initialYVelocity);
        }
        if (mVelocityTracker != null) {
          mVelocityTracker.recycle();
          mVelocityTracker = null;
        }
    }
    return true;
  }
  @Override
  public boolean onTouchEvent(MotionEvent ev) {

    if (ev.getAction() == MotionEvent.ACTION_DOWN && ev.getEdgeFlags() != 0) {
      // Don't handle edge touches immediately -- they may actually belong to one of our
      // descendants.
      return false;
    }

    if (mVelocityTracker == null) {
      mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(ev);

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {
      case MotionEvent.ACTION_DOWN:
        {
          final float x = ev.getX();
          final float y = ev.getY();
          if (!(mIsBeingDragged = inChild((int) x, (int) y))) {
            return false;
          }

          /*
           * If being flinged and user touches, stop the fling. isFinished
           * will be false if being flinged.
           */
          if (!mScroller.isFinished()) {
            mScroller.abortAnimation();
          }

          // Remember where the motion event started
          mLastMotionY = y;
          mLastMotionX = x;
          mActivePointerId = ev.getPointerId(0);
          break;
        }
      case MotionEvent.ACTION_MOVE:
        if (mIsBeingDragged) {
          // Scroll to follow the motion event
          final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
          final float y = ev.getY(activePointerIndex);
          final int deltaY = (int) (mLastMotionY - y);
          mLastMotionY = y;

          final float x = ev.getX(activePointerIndex);
          final int deltaX = (int) (mLastMotionX - x);
          mLastMotionX = x;

          scrollBy(deltaX, deltaY);
        }
        break;
      case MotionEvent.ACTION_UP:
        if (mIsBeingDragged) {
          if (mFlingEnabled) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            @SuppressWarnings("unused")
            int initialVelocitx = (int) velocityTracker.getXVelocity(mActivePointerId);
            @SuppressWarnings("unused")
            int initialVelocity = (int) velocityTracker.getYVelocity(mActivePointerId);

            //       if (getChildCount() > 0) {
            //     if(Math.abs(initialVelocitx) > initialVelocitx || Math.abs(initialVelocity) >
            // mMinimumVelocity) {
            //    fling(-initialVelocitx, -initialVelocity);
          }
        }
    }

    mActivePointerId = INVALID_POINTER;
    mIsBeingDragged = false;

    if (mVelocityTracker != null) {
      mVelocityTracker.recycle();
      mVelocityTracker = null;
    }
    //       }
    //   break;
    //        case MotionEvent.ACTION_CANCEL:
    //            if (mIsBeingDragged && getChildCount() > 0) {
    //                mActivePointerId = INVALID_POINTER;
    //                mIsBeingDragged = false;
    //                if (mVelocityTracker != null) {
    //                    mVelocityTracker.recycle();
    //                    mVelocityTracker = null;
    //                }
    //         }
    //          break;
    //       case MotionEvent.ACTION_POINTER_UP:
    //           onSecondaryPointerUp(ev);
    //          break;
    //   }
    return true;
  }