Example usage for android.support.v4.view MotionEventCompat getPointerId

List of usage examples for android.support.v4.view MotionEventCompat getPointerId

Introduction

In this page you can find the example usage for android.support.v4.view MotionEventCompat getPointerId.

Prototype

public static int getPointerId(MotionEvent event, int pointerIndex) 

Source Link

Document

Call MotionEvent#getPointerId(int) .

Usage

From source file:com.mde.potdroid.helpers.ptr.SwipyRefreshLayout.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    try {//from w w w.  ja  va 2  s  . c  o  m
        final int action = MotionEventCompat.getActionMasked(ev);

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

        switch (mDirection) {
        case BOTTOM:
            if (!isEnabled() || mReturningToStart || canChildScrollDown() || mRefreshing) {
                // Fail fast if we're not in a state where a swipe is possible
                return false;
            }
            break;
        case TOP:
        default:
            if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing) {
                // Fail fast if we're not in a state where a swipe is possible
                return false;
            }
            break;
        }

        switch (action) {
        case MotionEvent.ACTION_DOWN:
            mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
            mIsBeingDragged = false;
            break;

        case MotionEvent.ACTION_MOVE: {
            final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
            if (pointerIndex < 0) {
                return false;
            }

            final float y = MotionEventCompat.getY(ev, pointerIndex);

            float overscrollTop;
            switch (mDirection) {
            case BOTTOM:
                overscrollTop = (mInitialMotionY - y) * DRAG_RATE;
                break;
            case TOP:
            default:
                overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
                break;
            }
            if (mIsBeingDragged) {
                mProgress.showArrow(true);
                float originalDragPercent = overscrollTop / mTotalDragDistance;
                if (originalDragPercent < 0) {
                    return false;
                }
                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);
                /*int targetY;
                if (mDirection == SwipyRefreshLayoutDirection.TOP) {
                    targetY = mOriginalOffsetTop + (int) ((slingshotDist * dragPercent) + extraMove);
                } else {
                    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 = (float) (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 */);
            }
            break;
        }
        case MotionEventCompat.ACTION_POINTER_DOWN: {
            final int index = MotionEventCompat.getActionIndex(ev);
            mActivePointerId = MotionEventCompat.getPointerId(ev, index);
            break;
        }

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

        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL: {
            if (mActivePointerId == INVALID_POINTER) {
                if (action == MotionEvent.ACTION_UP) {
                }
                return false;
            }
            final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
            final float y = MotionEventCompat.getY(ev, pointerIndex);

            float overscrollTop;
            switch (mDirection) {
            case BOTTOM:
                overscrollTop = (mInitialMotionY - y) * DRAG_RATE;
                break;
            case TOP:
            default:
                overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
                break;
            }
            mIsBeingDragged = false;
            if (overscrollTop > mTotalDragDistance) {
                setRefreshing(true, true /* notify */);
            } else {
                // cancel refresh
                mRefreshing = false;
                mProgress.setStartEndTrim(0f, 0f);
                AnimationListener listener = null;
                if (!mScale) {
                    listener = new AnimationListener() {

                        @Override
                        public void onAnimationStart(Animation animation) {
                        }

                        @Override
                        public void onAnimationEnd(Animation animation) {
                            if (!mScale) {
                                startScaleDownAnimation(null);
                            }
                        }

                        @Override
                        public void onAnimationRepeat(Animation animation) {
                        }

                    };
                }
                animateOffsetToStartPosition(mCurrentTargetOffsetTop, listener);
                mProgress.showArrow(false);
            }
            mActivePointerId = INVALID_POINTER;
            return false;
        }
        }
    } catch (Exception e) {
        Log.e(TAG, "An exception occured during SwipyRefreshLayout onTouchEvent " + e.toString());
    }

    return true;
}

From source file:com.open.ui.viewpager.view.TabViewPager.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    //Log.d(TAG,"onTouchEvent getAction: "+ ev.getAction());
    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;
    }/*from ww w  . ja v  a2  s.c  o  m*/

    if (mAdapter == null || mAdapter.getCount() == 0) {
        // Nothing to present or scroll; nothing to touch.
        return false;
    }

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

    final int action = ev.getAction();

    switch (action & MotionEventCompat.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: {
        /*
         * If being flinged and user touches, stop the fling. isFinished
         * will be false if being flinged.
         */
        completeScroll();

        // Remember where the motion event started
        mLastMotionX = mInitialMotionX = ev.getX();
        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
        break;
    }
    case MotionEvent.ACTION_MOVE:
        if (!mIsBeingDragged) {
            final int pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
            final float x = MotionEventCompat.getX(ev, pointerIndex);
            final float xDiff = Math.abs(x - mLastMotionX);
            final float y = MotionEventCompat.getY(ev, pointerIndex);
            final float yDiff = Math.abs(y - mLastMotionY);
            //if (DEBUG) Log.v(TAG, "Moved x to " + x + "," + y + " diff=" + xDiff + "," + yDiff);
            if (xDiff > mTouchSlop && xDiff > yDiff) {
                //if (DEBUG) Log.v(TAG, "Starting drag!");
                mIsBeingDragged = true;
                mLastMotionX = x;
                setScrollState(SCROLL_STATE_DRAGGING);
                setScrollingCacheEnabled(true);
            }
        }
        if (mIsBeingDragged) {
            // Scroll to follow the motion event
            final int activePointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
            final float x = MotionEventCompat.getX(ev, activePointerIndex);
            final float deltaX = mLastMotionX - x;
            mLastMotionX = x;
            float scrollX = getScrollX() + deltaX;
            final int width = getWidth();

            final float leftBound = Math.max(0, (mCurItem - 1) * width);
            final float rightBound = Math.min(mCurItem + 1, mAdapter.getCount() - 1) * width;
            if (scrollX < leftBound) {
                scrollX = leftBound;
            } else if (scrollX > rightBound) {
                scrollX = rightBound;
            }
            // Don't lose the rounded component
            mLastMotionX += scrollX - (int) scrollX;

            if (!mHasTrulyChangeX && getScrollX() != (int) scrollX) {
                mHasTrulyChangeX = true;
                getParent().requestDisallowInterceptTouchEvent(true);
            }
            scrollTo((int) scrollX, getScrollY());
            if (mOnPageChangeListener != null) {
                final int position = (int) scrollX / width;
                final int positionOffsetPixels = (int) scrollX % width;
                final float positionOffset = (float) positionOffsetPixels / width;

                mOnPageChangeListener.onPageScrollDeltaX(deltaX);
                mOnPageChangeListener.onPageScrolled(position, positionOffset, positionOffsetPixels);

            }
            //if (DEBUG) Log.v(TAG, "Moved mIsBeingDragged " +  "deltaX  " + deltaX+" scrollX  " + scrollX+ "width  " + width );
        }
        break;
    case MotionEvent.ACTION_UP:
        if (mIsBeingDragged) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            int initialVelocity = (int) VelocityTrackerCompat.getYVelocity(velocityTracker, mActivePointerId);
            mPopulatePending = true;
            if ((Math.abs(initialVelocity) > mMinimumVelocity)
                    || Math.abs(mInitialMotionX - mLastMotionX) >= (getWidth() / 3)) {
                if (mLastMotionX > mInitialMotionX) {
                    setCurrentItemInternal(mCurItem - 1, true, true);
                } else {
                    setCurrentItemInternal(mCurItem + 1, true, true);
                }
            } else {
                setCurrentItemInternal(mCurItem, true, true);
            }

            mActivePointerId = INVALID_POINTER;
            endDrag();
        }
        break;
    case MotionEvent.ACTION_CANCEL:
        if (mIsBeingDragged) {
            setCurrentItemInternal(mCurItem, true, true);
            mActivePointerId = INVALID_POINTER;
            endDrag();
        }
        break;
    case MotionEventCompat.ACTION_POINTER_DOWN: {
        final int index = MotionEventCompat.getActionIndex(ev);
        final float x = MotionEventCompat.getX(ev, index);
        mLastMotionX = x;
        mActivePointerId = MotionEventCompat.getPointerId(ev, index);
        break;
    }
    case MotionEventCompat.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        mLastMotionX = MotionEventCompat.getX(ev, MotionEventCompat.findPointerIndex(ev, mActivePointerId));
        break;
    }
    return true;
}

From source file:atownsend.swipeopenhelper.SwipeOpenItemTouchHelper.java

/**
 * Checks whether we should select a View for swiping.
 *///from  w  ww.j a  v  a  2s .com
private boolean checkSelectForSwipe(int action, MotionEvent motionEvent, int pointerIndex) {
    if (selected != null || action != MotionEvent.ACTION_MOVE) {
        return false;
    }
    if (recyclerView.getScrollState() == RecyclerView.SCROLL_STATE_DRAGGING) {
        return false;
    }
    final RecyclerView.ViewHolder vh = findSwipedView(motionEvent);
    if (vh == null || !(vh instanceof SwipeOpenViewHolder)) {
        return false;
    }

    final int movementFlags = callback.getAbsoluteMovementFlags(recyclerView, vh);

    final int swipeFlags = (movementFlags & ACTION_MODE_SWIPE_MASK) >> (DIRECTION_FLAG_COUNT
            * ACTION_STATE_SWIPE);

    if (swipeFlags == 0) {
        return false;
    }

    // dX and dY are only set in allowed directions. We use custom x/y here instead of
    // updateDxDy to avoid swiping if user moves more in the other direction
    final float x = MotionEventCompat.getX(motionEvent, pointerIndex);
    final float y = MotionEventCompat.getY(motionEvent, pointerIndex);

    // Calculate the distance moved
    final float dx = x - initialTouchX;
    final float dy = y - initialTouchY;
    // swipe target is chose w/o applying flags so it does not really check if swiping in that
    // direction is allowed. This why here, we use dX dY to check slope value again.
    final float absDx = Math.abs(dx);
    final float absDy = Math.abs(dy);

    if (absDx < slop && absDy < slop) {
        return false;
    }
    if (absDx > absDy) {
        if (dx < 0 && (swipeFlags & LEFT) == 0) {
            return false;
        }
        if (dx > 0 && (swipeFlags & RIGHT) == 0) {
            return false;
        }
    } else {
        if (dy < 0 && (swipeFlags & UP) == 0) {
            return false;
        }
        if (dy > 0 && (swipeFlags & DOWN) == 0) {
            return false;
        }
    }
    dX = dY = 0f;
    activePointerId = MotionEventCompat.getPointerId(motionEvent, 0);
    select((SwipeOpenViewHolder) vh, ACTION_STATE_SWIPE);
    return true;
}

From source file:com.chauthai.swipereveallayout.ViewDragHelper.java

private void saveLastMotion(MotionEvent ev) {
    final int pointerCount = MotionEventCompat.getPointerCount(ev);
    for (int i = 0; i < pointerCount; i++) {
        final int pointerId = MotionEventCompat.getPointerId(ev, i);
        // If pointer is invalid then skip saving on ACTION_MOVE.
        if (!isValidPointerForActionMove(pointerId)) {
            continue;
        }/*from   w  w  w.  j av  a2s . co m*/
        final float x = MotionEventCompat.getX(ev, i);
        final float y = MotionEventCompat.getY(ev, i);
        mLastMotionX[pointerId] = x;
        mLastMotionY[pointerId] = y;
    }
}

From source file:com.callba.phone.widget.refreshlayout.RefreshLayout.java

private boolean headerInterceptTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);
    switch (action) {
    case MotionEvent.ACTION_DOWN:
        setHeaderTargetOffsetTopAndBottom(mHeaderOriginalOffsetTop - mCircleView.getTop(), true);
        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
        mIsHeaderBeingDragged = false;/*from ww  w .  java  2 s .  c  om*/
        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 && !mIsHeaderBeingDragged) {
            mInitialMotionY = mInitialDownY + mTouchSlop;
            mIsHeaderBeingDragged = true;
            mProgress.setAlpha(STARTING_PROGRESS_ALPHA);
        }
        break;

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

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

    return mIsHeaderBeingDragged;
}

From source file:com.learn.mobile.customview.DSwipeRefreshLayout.java

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
    ensureTarget();//  w ww  . j  av  a  2  s .  co  m

    final int action = MotionEventCompat.getActionMasked(ev);

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

    if (!isEnabled() || mReturningToStart || canChildScrollUp() || mRefreshing
            || !canRefreshWithAppBarLayout()) {
        // 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;
}

From source file:bk.vinhdo.taxiads.utils.view.SlidingLayer.java

private void onSecondaryPointerUp(MotionEvent ev) {
    final int pointerIndex = MotionEventCompat.getActionIndex(ev);
    final int pointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
    if (pointerId == mActivePointerId) {
        // This was our active pointer going up. Choose a new
        // active pointer and adjust accordingly.
        final int newPointerIndex = pointerIndex == 0 ? 1 : 0;
        mLastX = MotionEventCompat.getX(ev, newPointerIndex);
        mActivePointerId = MotionEventCompat.getPointerId(ev, newPointerIndex);
        if (mVelocityTracker != null) {
            mVelocityTracker.clear();/*  ww w  .  j  a va2s  . c  om*/
        }
    }
}

From source file:co.codecrunch.musicplayerlite.slidinguppanelhelper.ViewDragHelper.java

private void saveLastMotion(MotionEvent ev) {
    final int pointerCount = MotionEventCompat.getPointerCount(ev);
    for (int i = 0; i < pointerCount; i++) {
        final int pointerId = MotionEventCompat.getPointerId(ev, i);
        final float x = MotionEventCompat.getX(ev, i);
        final float y = MotionEventCompat.getY(ev, i);
        if (mLastMotionX != null && mLastMotionY != null) {
            mLastMotionX[pointerId] = x;
            mLastMotionY[pointerId] = y;
        }/*from w  w  w.j a  va  2  s .  c  o m*/
    }
}

From source file:bhav.swipeaction.SwipeAction.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);
    int pointerIndex;
    if (mReturningToStart && action == MotionEvent.ACTION_DOWN) {
        mReturningToStart = false;/*from ww w.j av  a2  s  . co  m*/
    }
    if (!isEnabled() || mReturningToStart || canChildScrollUp() || mNestedScrollInProgress) {
        // Fail fast if we're not in a state where a swipe is possible
        return false;
    }
    switch (action) {
    case MotionEvent.ACTION_DOWN:
        mActivePointerId = MotionEventCompat.getPointerId(ev, 0);
        mIsBeingDragged = false;
        break;
    case MotionEvent.ACTION_MOVE: {
        pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
        if (pointerIndex < 0) {
            Log.e(TAG, "Got ACTION_MOVE event but have an invalid active pointer id.");
            return false;
        }
        final float y = MotionEventCompat.getY(ev, pointerIndex);
        final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
        if (mIsBeingDragged) {
            if (overscrollTop > 0) {
                moveSpinner(overscrollTop);
            } else {
                return false;
            }
        }
        break;
    }
    case MotionEventCompat.ACTION_POINTER_DOWN: {
        pointerIndex = MotionEventCompat.getActionIndex(ev);
        if (pointerIndex < 0) {
            Log.e(TAG, "Got ACTION_POINTER_DOWN event but have an invalid action index.");
            return false;
        }
        mActivePointerId = MotionEventCompat.getPointerId(ev, pointerIndex);
        break;
    }
    case MotionEventCompat.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        break;
    case MotionEvent.ACTION_UP: {
        pointerIndex = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
        if (pointerIndex < 0) {
            Log.e(TAG, "Got ACTION_UP event but don't have an active pointer id.");
            return false;
        }
        final float y = MotionEventCompat.getY(ev, pointerIndex);
        final float overscrollTop = (y - mInitialMotionY) * DRAG_RATE;
        mIsBeingDragged = false;
        finishSpinner(overscrollTop);
        mActivePointerId = INVALID_POINTER;
        return false;
    }
    case MotionEvent.ACTION_CANCEL:
        return false;
    }
    return true;
}

From source file:com.mmt.widget.ViewDragHelper.java

/**
 * Process a touch event received by the parent view. This method will
 * dispatch callback events as needed before returning. The parent view's
 * onTouchEvent implementation should call this.
 *
 * @param ev The touch event received by the parent view
 *///from   w  w  w . java2 s .c o  m
public void processTouchEvent(MotionEvent ev) {
    final int action = MotionEventCompat.getActionMasked(ev);
    final int actionIndex = MotionEventCompat.getActionIndex(ev);

    if (action == MotionEvent.ACTION_DOWN) {
        // Reset things for a new event stream, just in case we didn't get
        // the whole previous stream.
        cancel();
    }

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

    switch (action) {
    case MotionEvent.ACTION_DOWN: {
        final float x = ev.getX();
        final float y = ev.getY();
        final int pointerId = MotionEventCompat.getPointerId(ev, 0);
        final View toCapture = findTopChildUnder((int) x, (int) y);

        saveInitialMotion(x, y, pointerId);

        // Since the parent is already directly processing this touch
        // event,
        // there is no reason to delay for a slop before dragging.
        // Start immediately if possible.
        tryCaptureViewForDrag(toCapture, pointerId);

        final int edgesTouched = mInitialEdgesTouched[pointerId];
        if ((edgesTouched & mTrackingEdges) != 0) {
            mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
        }
        break;
    }

    case MotionEventCompat.ACTION_POINTER_DOWN: {
        final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
        final float x = MotionEventCompat.getX(ev, actionIndex);
        final float y = MotionEventCompat.getY(ev, actionIndex);

        saveInitialMotion(x, y, pointerId);

        // A ViewDragHelper can only manipulate one view at a time.
        if (mDragState == STATE_IDLE) {
            // If we're idle we can do anything! Treat it like a normal
            // down
            // event.

            final View toCapture = findTopChildUnder((int) x, (int) y);
            tryCaptureViewForDrag(toCapture, pointerId);

            final int edgesTouched = mInitialEdgesTouched[pointerId];
            if ((edgesTouched & mTrackingEdges) != 0) {
                mCallback.onEdgeTouched(edgesTouched & mTrackingEdges, pointerId);
            }
        } else if (isCapturedViewUnder((int) x, (int) y)) {
            // We're still tracking a captured view. If the same view is
            // under this
            // point, we'll swap to controlling it with this pointer
            // instead.
            // (This will still work if we're "catching" a settling
            // view.)

            tryCaptureViewForDrag(mCapturedView, pointerId);
        }
        break;
    }

    case MotionEvent.ACTION_MOVE: {
        if (mDragState == STATE_DRAGGING) {
            final int index = MotionEventCompat.findPointerIndex(ev, mActivePointerId);
            final float x = MotionEventCompat.getX(ev, index);
            final float y = MotionEventCompat.getY(ev, index);
            final int idx = (int) (x - mLastMotionX[mActivePointerId]);
            final int idy = (int) (y - mLastMotionY[mActivePointerId]);

            dragTo(mCapturedView.getLeft() + idx, mCapturedView.getTop() + idy, idx, idy);

            saveLastMotion(ev);
        } else {
            // Check to see if any pointer is now over a draggable view.
            final int pointerCount = MotionEventCompat.getPointerCount(ev);
            for (int i = 0; i < pointerCount; i++) {
                final int pointerId = MotionEventCompat.getPointerId(ev, i);
                final float x = MotionEventCompat.getX(ev, i);
                final float y = MotionEventCompat.getY(ev, i);
                final float dx = x - mInitialMotionX[pointerId];
                final float dy = y - mInitialMotionY[pointerId];

                reportNewEdgeDrags(dx, dy, pointerId);
                if (mDragState == STATE_DRAGGING) {
                    // Callback might have started an edge drag.
                    break;
                }

                final View toCapture = findTopChildUnder((int) x, (int) y);
                if (checkTouchSlop(toCapture, dx, dy) && tryCaptureViewForDrag(toCapture, pointerId)) {
                    break;
                }
            }
            saveLastMotion(ev);
        }
        break;
    }

    case MotionEventCompat.ACTION_POINTER_UP: {
        final int pointerId = MotionEventCompat.getPointerId(ev, actionIndex);
        if (mDragState == STATE_DRAGGING && pointerId == mActivePointerId) {
            // Try to find another pointer that's still holding on to
            // the
            // captured view.
            int newActivePointer = INVALID_POINTER;
            final int pointerCount = MotionEventCompat.getPointerCount(ev);
            for (int i = 0; i < pointerCount; i++) {
                final int id = MotionEventCompat.getPointerId(ev, i);
                if (id == mActivePointerId) {
                    // This one's going away, skip.
                    continue;
                }

                final float x = MotionEventCompat.getX(ev, i);
                final float y = MotionEventCompat.getY(ev, i);
                if (findTopChildUnder((int) x, (int) y) == mCapturedView
                        && tryCaptureViewForDrag(mCapturedView, id)) {
                    newActivePointer = mActivePointerId;
                    break;
                }
            }

            if (newActivePointer == INVALID_POINTER) {
                // We didn't find another pointer still touching the
                // view,
                // release it.
                releaseViewForPointerUp();
            }
        }
        clearMotionHistory(pointerId);
        break;
    }

    case MotionEvent.ACTION_UP: {
        if (mDragState == STATE_DRAGGING) {
            releaseViewForPointerUp();
        }
        cancel();
        break;
    }

    case MotionEvent.ACTION_CANCEL: {
        if (mDragState == STATE_DRAGGING) {
            dispatchViewReleased(0, 0);
        }
        cancel();
        break;
    }
    }
}