Example usage for android.view VelocityTracker getXVelocity

List of usage examples for android.view VelocityTracker getXVelocity

Introduction

In this page you can find the example usage for android.view VelocityTracker getXVelocity.

Prototype

public float getXVelocity(int id) 

Source Link

Document

Retrieve the last computed X velocity.

Usage

From source file:Main.java

public static void velocityTrackerPointerUpCleanUpIfNecessary(MotionEvent ev, VelocityTracker tracker) {

    // Check the dot product of current velocities.
    // If the pointer that left was opposing another velocity vector, clear.
    tracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
    final int upIndex = ev.getActionIndex();
    final int id1 = ev.getPointerId(upIndex);
    final float x1 = tracker.getXVelocity(id1);
    final float y1 = tracker.getYVelocity(id1);
    for (int i = 0, count = ev.getPointerCount(); i < count; i++) {
        if (i == upIndex)
            continue;

        final int id2 = ev.getPointerId(i);
        final float x = x1 * tracker.getXVelocity(id2);
        final float y = y1 * tracker.getYVelocity(id2);

        final float dot = x + y;
        if (dot < 0) {
            tracker.clear();/*ww w . ja v  a2s .c  o m*/
            break;
        }
    }
}

From source file:com.aviary.android.feather.sdk.widget.AviaryWorkspace.java

@Override
public boolean onTouchEvent(MotionEvent ev) {

    final int action = ev.getAction();

    if (!isEnabled()) {
        if (!mScroller.isFinished()) {
            mScroller.abortAnimation();//ww w.jav  a  2s  . c  o m
        }
        snapToScreen(mCurrentScreen);
        return false; // We don't want the events. Let them fall through to the all
                      // apps view.
    }

    acquireVelocityTrackerAndAddMovement(ev);

    switch (action & MotionEvent.ACTION_MASK) {
    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
        mLastMotionX = ev.getX();
        mLastMotionX2 = ev.getX();
        mActivePointerId = ev.getPointerId(0);
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            enableChildrenCache(mCurrentScreen - 1, mCurrentScreen + 1);
        }
        break;
    case MotionEvent.ACTION_MOVE:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            // Scroll to follow the motion event
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(pointerIndex);
            final float deltaX = mLastMotionX - x;
            final float deltaX2 = mLastMotionX2 - x;
            final int mode = mOverScrollMode;

            mLastMotionX = x;

            if (deltaX < 0) {
                mTouchX += deltaX;
                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;

                if (mTouchX < 0 && mode != OVER_SCROLL_NEVER) {
                    mTouchX = mLastMotionX = 0;
                    // mLastMotionX = x;

                    if (mEdgeGlowLeft != null && deltaX2 < 0) {
                        mEdgeGlowLeft.onPull((float) deltaX / getWidth());
                        if (!mEdgeGlowRight.isFinished()) {
                            mEdgeGlowRight.onRelease();
                        }
                    }
                }

                invalidate();

            } else if (deltaX > 0) {
                final int totalWidth = getScreenScrollPositionX(mItemCount - 1);
                final float availableToScroll = getScreenScrollPositionX(mItemCount) - mTouchX;
                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;

                mTouchX += Math.min(availableToScroll, deltaX);

                if (availableToScroll <= getWidth() && mode != OVER_SCROLL_NEVER) {
                    mTouchX = mLastMotionX = totalWidth;
                    // mLastMotionX = x;

                    if (mEdgeGlowLeft != null && deltaX2 > 0) {
                        mEdgeGlowRight.onPull((float) deltaX / getWidth());
                        if (!mEdgeGlowLeft.isFinished()) {
                            mEdgeGlowLeft.onRelease();
                        }
                    }
                }
                invalidate();

            } else {
                awakenScrollBars();
            }
        }
        break;
    case MotionEvent.ACTION_UP:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            final int velocityX = (int) velocityTracker.getXVelocity(mActivePointerId);

            final int screenWidth = getWidth();
            final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
            final float scrolledPos = (float) getScrollX() / screenWidth;

            if (velocityX > SNAP_VELOCITY && mCurrentScreen > 0) {
                // Fling hard enough to move left.
                // Don't fling across more than one screen at a time.
                final int bound = scrolledPos < whichScreen ? mCurrentScreen - 1 : mCurrentScreen;
                snapToScreen(Math.min(whichScreen, bound), velocityX, true);
            } else if (velocityX < -SNAP_VELOCITY && mCurrentScreen < mItemCount - 1) {
                // Fling hard enough to move right
                // Don't fling across more than one screen at a time.
                final int bound = scrolledPos > whichScreen ? mCurrentScreen + 1 : mCurrentScreen;
                snapToScreen(Math.max(whichScreen, bound), velocityX, true);
            } else {
                snapToScreen(whichScreen, 0, true);
            }

            if (mEdgeGlowLeft != null) {
                mEdgeGlowLeft.onRelease();
                mEdgeGlowRight.onRelease();
            }
        }
        mTouchState = TOUCH_STATE_REST;
        mActivePointerId = INVALID_POINTER;
        releaseVelocityTracker();
        break;
    case MotionEvent.ACTION_CANCEL:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            final int screenWidth = getWidth();
            final int whichScreen = (getScrollX() + (screenWidth / 2)) / screenWidth;
            snapToScreen(whichScreen, 0, true);
        }
        mTouchState = TOUCH_STATE_REST;
        mActivePointerId = INVALID_POINTER;
        releaseVelocityTracker();

        if (mEdgeGlowLeft != null) {
            mEdgeGlowLeft.onRelease();
            mEdgeGlowRight.onRelease();
        }

        break;
    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        break;
    }

    return true;
}

From source file:com.android.launcher2.PagedView.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    // Skip touch handling if there are no pages to swipe
    if (getChildCount() <= 0)
        return super.onTouchEvent(ev);

    acquireVelocityTrackerAndAddMovement(ev);

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN:
        /*/*from  w w  w.ja va  2 s  .c  o  m*/
         * 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
        mDownMotionX = mLastMotionX = ev.getX();
        mLastMotionXRemainder = 0;
        mTotalMotionX = 0;
        mActivePointerId = ev.getPointerId(0);
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            pageBeginMoving();
        }
        break;

    case MotionEvent.ACTION_MOVE:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            // Scroll to follow the motion event
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(pointerIndex);
            final float deltaX = mLastMotionX + mLastMotionXRemainder - x;

            mTotalMotionX += Math.abs(deltaX);

            // Only scroll and update mLastMotionX if we have moved some discrete amount.  We
            // keep the remainder because we are actually testing if we've moved from the last
            // scrolled position (which is discrete).
            if (Math.abs(deltaX) >= 1.0f) {
                mTouchX += deltaX;
                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                if (!mDeferScrollUpdate) {
                    scrollBy((int) deltaX, 0);
                    if (DEBUG)
                        Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
                } else {
                    invalidate();
                }
                mLastMotionX = x;
                mLastMotionXRemainder = deltaX - (int) deltaX;
            } else {
                awakenScrollBars();
            }
        } else {
            determineScrollingStart(ev);
        }
        break;

    case MotionEvent.ACTION_UP:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            final int activePointerId = mActivePointerId;
            final int pointerIndex = ev.findPointerIndex(activePointerId);
            final float x = ev.getX(pointerIndex);
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
            final int deltaX = (int) (x - mDownMotionX);
            final int pageWidth = getScaledMeasuredWidth(getPageAt(mCurrentPage));
            boolean isSignificantMove = Math.abs(deltaX) > pageWidth * SIGNIFICANT_MOVE_THRESHOLD;

            mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);

            boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING
                    && Math.abs(velocityX) > mFlingThresholdVelocity;

            // In the case that the page is moved far to one direction and then is flung
            // in the opposite direction, we use a threshold to determine whether we should
            // just return to the starting page, or if we should skip one further.
            boolean returnToOriginalPage = false;
            if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD
                    && Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
                returnToOriginalPage = true;
            }

            int finalPage;
            // We give flings precedence over large moves, which is why we short-circuit our
            // test for a large move if a fling has been registered. That is, a large
            // move to the left and fling to the right will register as a fling to the right.
            if (((isSignificantMove && deltaX > 0 && !isFling) || (isFling && velocityX > 0))
                    && mCurrentPage > 0) {
                finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
                snapToPageWithVelocity(finalPage, velocityX);
            } else if (((isSignificantMove && deltaX < 0 && !isFling) || (isFling && velocityX < 0))
                    && mCurrentPage < getChildCount() - 1) {
                finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
                snapToPageWithVelocity(finalPage, velocityX);
            } else {
                snapToDestination();
            }
        } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
            // at this point we have not moved beyond the touch slop
            // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
            // we can just page
            int nextPage = Math.max(0, mCurrentPage - 1);
            if (nextPage != mCurrentPage) {
                snapToPage(nextPage);
            } else {
                snapToDestination();
            }
        } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
            // at this point we have not moved beyond the touch slop
            // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
            // we can just page
            int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
            if (nextPage != mCurrentPage) {
                snapToPage(nextPage);
            } else {
                snapToDestination();
            }
        } else {
            onUnhandledTap(ev);
        }
        mTouchState = TOUCH_STATE_REST;
        mActivePointerId = INVALID_POINTER;
        releaseVelocityTracker();
        break;

    case MotionEvent.ACTION_CANCEL:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            snapToDestination();
        }
        mTouchState = TOUCH_STATE_REST;
        mActivePointerId = INVALID_POINTER;
        releaseVelocityTracker();
        break;

    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        break;
    }

    return true;
}

From source file:com.hippo.widget.BothScrollView.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    initVelocityTrackerIfNotExists();/* w w  w .ja  v a 2 s.  com*/
    mVelocityTracker.addMovement(ev);

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: {
        if (getChildCount() == 0) {
            return false;
        }
        if ((mIsBeingDragged = !mScroller.isFinished())) {
            final ViewParent parent = getParent();
            if (parent != null) {
                parent.requestDisallowInterceptTouchEvent(true);
            }
        }

        /*
         * 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
        mLastMotionX = (int) ev.getX();
        mLastMotionY = (int) ev.getY();
        mActivePointerId = ev.getPointerId(0);
        break;
    }
    case MotionEvent.ACTION_MOVE:
        final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
        if (activePointerIndex == -1) {
            Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");
            break;
        }
        final int x = (int) ev.getX(activePointerIndex);
        final int y = (int) ev.getY(activePointerIndex);
        int deltaX = mLastMotionX - x;
        int deltaY = mLastMotionY - y;
        if (!mIsBeingDragged && (Math.abs(deltaX) > mTouchSlop || Math.abs(deltaY) > mTouchSlop)) {
            final ViewParent parent = getParent();
            if (parent != null) {
                parent.requestDisallowInterceptTouchEvent(true);
            }
            mIsBeingDragged = true;
            if (deltaX > 0) {
                deltaX -= mTouchSlop;
                deltaX = Math.max(0, deltaX);
            } else {
                deltaX += mTouchSlop;
                deltaX = Math.min(0, deltaX);
            }
            if (deltaY > 0) {
                deltaY -= mTouchSlop;
                deltaY = Math.max(0, deltaY);
            } else {
                deltaY += mTouchSlop;
                deltaY = Math.min(0, deltaY);
            }
        }
        if (mIsBeingDragged) {
            // Scroll to follow the motion event
            mLastMotionX = x;
            mLastMotionY = y;

            final int oldX = getScrollX();
            final int oldY = getScrollY();
            final int horizontalRange = getHorizontalScrollRange();
            final int verticalRange = getVerticalScrollRange();
            final int overscrollMode = getOverScrollMode();
            final boolean canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS
                    || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS
                            && (horizontalRange > 0 || verticalRange > 0));

            // Calling overScrollBy will call onOverScrolled, which
            // calls onScrollChanged if applicable.
            overScrollBy(deltaX, deltaY, oldX, oldY, horizontalRange, verticalRange, mOverscrollDistance,
                    mOverscrollDistance, true);

            if (canOverscroll) {
                final int pulledToX = oldX + deltaX;
                final int pulledToY = oldY + deltaY;
                if (pulledToX < 0) {
                    mEdgeGlowLeft.onPull((float) deltaX / getWidth());
                    if (!mEdgeGlowRight.isFinished()) {
                        mEdgeGlowRight.onRelease();
                    }
                } else if (pulledToX > horizontalRange) {
                    mEdgeGlowRight.onPull((float) deltaX / getWidth());
                    if (!mEdgeGlowLeft.isFinished()) {
                        mEdgeGlowLeft.onRelease();
                    }
                }
                if (pulledToY < 0) {
                    mEdgeGlowTop.onPull((float) deltaY / getHeight());
                    if (!mEdgeGlowBottom.isFinished()) {
                        mEdgeGlowBottom.onRelease();
                    }
                } else if (pulledToY > verticalRange) {
                    mEdgeGlowBottom.onPull((float) deltaY / getHeight());
                    if (!mEdgeGlowTop.isFinished()) {
                        mEdgeGlowTop.onRelease();
                    }
                }
                if (mEdgeGlowLeft != null && (!mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished()
                        || !mEdgeGlowTop.isFinished() || !mEdgeGlowBottom.isFinished())) {
                    ViewCompat.postInvalidateOnAnimation(this);
                }
            }
        }
        break;
    case MotionEvent.ACTION_UP:
        if (mIsBeingDragged) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            int initialVelocityX = (int) velocityTracker.getXVelocity(mActivePointerId);
            int initialVelocityY = (int) velocityTracker.getYVelocity(mActivePointerId);

            if (getChildCount() > 0) {
                if (Math.abs(initialVelocityX) > mMinimumVelocity
                        || Math.abs(initialVelocityY) > mMinimumVelocity) {
                    fling(-initialVelocityX, -initialVelocityY);
                } else {
                    if (mScroller.springBack(getScrollX(), getScrollY(), 0, getHorizontalScrollRange(), 0,
                            getVerticalScrollRange())) {
                        ViewCompat.postInvalidateOnAnimation(this);
                    }
                }
            }

            mActivePointerId = INVALID_POINTER;
            endDrag();
        }
        break;
    case MotionEvent.ACTION_CANCEL:
        if (mIsBeingDragged && getChildCount() > 0) {
            if (mScroller.springBack(getScrollX(), getScrollY(), 0, getHorizontalScrollRange(), 0,
                    getVerticalScrollRange())) {
                ViewCompat.postInvalidateOnAnimation(this);
            }
            mActivePointerId = INVALID_POINTER;
            endDrag();
        }
        break;
    case MotionEvent.ACTION_POINTER_DOWN: {
        final int index = ev.getActionIndex();
        mLastMotionX = (int) ev.getX(index);
        mLastMotionY = (int) ev.getY(index);
        mActivePointerId = ev.getPointerId(index);
        break;
    }
    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        final int index = ev.findPointerIndex(mActivePointerId);
        mLastMotionX = (int) ev.getX(index);
        mLastMotionY = (int) ev.getY(index);
        break;
    }
    return true;
}

From source file:com.android.internal.widget.ViewPager.java

@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;
    }/*  www.  j a v a2s .co  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();
    boolean needsInvalidate = false;

    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: {
        mScroller.abortAnimation();
        mPopulatePending = false;
        populate();

        // Remember where the motion event started
        mLastMotionX = mInitialMotionX = ev.getX();
        mLastMotionY = mInitialMotionY = ev.getY();
        mActivePointerId = ev.getPointerId(0);
        break;
    }
    case MotionEvent.ACTION_MOVE:
        if (!mIsBeingDragged) {
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(pointerIndex);
            final float xDiff = Math.abs(x - mLastMotionX);
            final float y = ev.getY(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;
                requestParentDisallowInterceptTouchEvent(true);
                mLastMotionX = x - mInitialMotionX > 0 ? mInitialMotionX + mTouchSlop
                        : mInitialMotionX - mTouchSlop;
                mLastMotionY = y;
                setScrollState(SCROLL_STATE_DRAGGING);
                setScrollingCacheEnabled(true);

                // Disallow Parent Intercept, just in case
                ViewParent parent = getParent();
                if (parent != null) {
                    parent.requestDisallowInterceptTouchEvent(true);
                }
            }
        }
        // Not else! Note that mIsBeingDragged can be set above.
        if (mIsBeingDragged) {
            // Scroll to follow the motion event
            final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(activePointerIndex);
            needsInvalidate |= performDrag(x);
        }
        break;
    case MotionEvent.ACTION_UP:
        if (mIsBeingDragged) {
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            final int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);

            mPopulatePending = true;

            final float scrollStart = getScrollStart();
            final float scrolledPages = scrollStart / getPaddedWidth();
            final ItemInfo ii = infoForFirstVisiblePage();
            final int currentPage = ii.position;
            final float nextPageOffset;
            if (isLayoutRtl()) {
                nextPageOffset = (ii.offset - scrolledPages) / ii.widthFactor;
            } else {
                nextPageOffset = (scrolledPages - ii.offset) / ii.widthFactor;
            }

            final int activePointerIndex = ev.findPointerIndex(mActivePointerId);
            final float x = ev.getX(activePointerIndex);
            final int totalDelta = (int) (x - mInitialMotionX);
            final int nextPage = determineTargetPage(currentPage, nextPageOffset, initialVelocity, totalDelta);
            setCurrentItemInternal(nextPage, true, true, initialVelocity);

            mActivePointerId = INVALID_POINTER;
            endDrag();
            mLeftEdge.onRelease();
            mRightEdge.onRelease();
            needsInvalidate = true;
        }
        break;
    case MotionEvent.ACTION_CANCEL:
        if (mIsBeingDragged) {
            scrollToItem(mCurItem, true, 0, false);
            mActivePointerId = INVALID_POINTER;
            endDrag();
            mLeftEdge.onRelease();
            mRightEdge.onRelease();
            needsInvalidate = true;
        }
        break;
    case MotionEvent.ACTION_POINTER_DOWN: {
        final int index = ev.getActionIndex();
        final float x = ev.getX(index);
        mLastMotionX = x;
        mActivePointerId = ev.getPointerId(index);
        break;
    }
    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId));
        break;
    }
    if (needsInvalidate) {
        postInvalidateOnAnimation();
    }
    return true;
}

From source file:cc.flydev.launcher.Page.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (DISABLE_TOUCH_INTERACTION) {
        return false;
    }/*from w  w w  .  j a va  2s. co  m*/

    super.onTouchEvent(ev);

    // Skip touch handling if there are no pages to swipe
    if (getChildCount() <= 0)
        return super.onTouchEvent(ev);

    acquireVelocityTrackerAndAddMovement(ev);

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {
    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
        mDownMotionX = mLastMotionX = ev.getX();
        mDownMotionY = mLastMotionY = ev.getY();
        mDownScrollX = getScrollX();
        float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
        mParentDownMotionX = p[0];
        mParentDownMotionY = p[1];
        mLastMotionXRemainder = 0;
        mTotalMotionX = 0;
        mActivePointerId = ev.getPointerId(0);

        if (mTouchState == TOUCH_STATE_SCROLLING) {
            pageBeginMoving();
        }
        break;

    case MotionEvent.ACTION_MOVE:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            // Scroll to follow the motion event
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);

            if (pointerIndex == -1)
                return true;

            final float x = ev.getX(pointerIndex);
            final float deltaX = mLastMotionX + mLastMotionXRemainder - x;

            mTotalMotionX += Math.abs(deltaX);

            // Only scroll and update mLastMotionX if we have moved some discrete amount.  We
            // keep the remainder because we are actually testing if we've moved from the last
            // scrolled position (which is discrete).
            if (Math.abs(deltaX) >= 1.0f) {
                mTouchX += deltaX;
                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                if (!mDeferScrollUpdate) {
                    scrollBy((int) deltaX, 0);
                    if (DEBUG)
                        Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
                } else {
                    invalidate();
                }
                mLastMotionX = x;
                mLastMotionXRemainder = deltaX - (int) deltaX;
            } else {
                awakenScrollBars();
            }
        } else if (mTouchState == TOUCH_STATE_REORDERING) {
            // Update the last motion position
            mLastMotionX = ev.getX();
            mLastMotionY = ev.getY();

            // Update the parent down so that our zoom animations take this new movement into
            // account
            float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
            mParentDownMotionX = pt[0];
            mParentDownMotionY = pt[1];
            updateDragViewTranslationDuringDrag();

            // Find the closest page to the touch point
            final int dragViewIndex = indexOfChild(mDragView);

            // Change the drag view if we are hovering over the drop target
            boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
                    (int) mParentDownMotionY);
            setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);

            if (DEBUG)
                Log.d(TAG, "mLastMotionX: " + mLastMotionX);
            if (DEBUG)
                Log.d(TAG, "mLastMotionY: " + mLastMotionY);
            if (DEBUG)
                Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
            if (DEBUG)
                Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);

            final int pageUnderPointIndex = getNearestHoverOverPageIndex();
            if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView)
                    && !isHoveringOverDelete) {
                mTempVisiblePagesRange[0] = 0;
                mTempVisiblePagesRange[1] = getPageCount() - 1;
                getOverviewModePages(mTempVisiblePagesRange);
                if (mTempVisiblePagesRange[0] <= pageUnderPointIndex
                        && pageUnderPointIndex <= mTempVisiblePagesRange[1]
                        && pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
                    mSidePageHoverIndex = pageUnderPointIndex;
                    mSidePageHoverRunnable = new Runnable() {
                        @Override
                        public void run() {
                            // Setup the scroll to the correct page before we swap the views
                            snapToPage(pageUnderPointIndex);

                            // For each of the pages between the paged view and the drag view,
                            // animate them from the previous position to the new position in
                            // the layout (as a result of the drag view moving in the layout)
                            int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
                            int lowerIndex = (dragViewIndex < pageUnderPointIndex) ? dragViewIndex + 1
                                    : pageUnderPointIndex;
                            int upperIndex = (dragViewIndex > pageUnderPointIndex) ? dragViewIndex - 1
                                    : pageUnderPointIndex;
                            for (int i = lowerIndex; i <= upperIndex; ++i) {
                                View v = getChildAt(i);
                                // dragViewIndex < pageUnderPointIndex, so after we remove the
                                // drag view all subsequent views to pageUnderPointIndex will
                                // shift down.
                                int oldX = getViewportOffsetX() + getChildOffset(i);
                                int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);

                                // Animate the view translation from its old position to its new
                                // position
                                AnimatorSet anim = (AnimatorSet) v.getTag(ANIM_TAG_KEY);
                                if (anim != null) {
                                    anim.cancel();
                                }

                                v.setTranslationX(oldX - newX);
                                anim = new AnimatorSet();
                                anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
                                anim.playTogether(ObjectAnimator.ofFloat(v, "translationX", 0f));
                                anim.start();
                                v.setTag(anim);
                            }

                            removeView(mDragView);
                            onRemoveView(mDragView, false);
                            addView(mDragView, pageUnderPointIndex);
                            onAddView(mDragView, pageUnderPointIndex);
                            mSidePageHoverIndex = -1;
                            mPageIndicator.setActiveMarker(getNextPage());
                        }
                    };
                    postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
                }
            } else {
                removeCallbacks(mSidePageHoverRunnable);
                mSidePageHoverIndex = -1;
            }
        } else {
            determineScrollingStart(ev);
        }
        break;

    case MotionEvent.ACTION_UP:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            final int activePointerId = mActivePointerId;
            final int pointerIndex = ev.findPointerIndex(activePointerId);
            final float x = ev.getX(pointerIndex);
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
            final int deltaX = (int) (x - mDownMotionX);
            final int pageWidth = getPageAt(mCurrentPage).getMeasuredWidth();
            boolean isSignificantMove = Math.abs(deltaX) > pageWidth * SIGNIFICANT_MOVE_THRESHOLD;

            mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);

            boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING
                    && Math.abs(velocityX) > mFlingThresholdVelocity;

            if (!mFreeScroll) {
                // In the case that the page is moved far to one direction and then is flung
                // in the opposite direction, we use a threshold to determine whether we should
                // just return to the starting page, or if we should skip one further.
                boolean returnToOriginalPage = false;
                if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD
                        && Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
                    returnToOriginalPage = true;
                }

                int finalPage;
                // We give flings precedence over large moves, which is why we short-circuit our
                // test for a large move if a fling has been registered. That is, a large
                // move to the left and fling to the right will register as a fling to the right.
                final boolean isRtl = isLayoutRtl();
                boolean isDeltaXLeft = isRtl ? deltaX > 0 : deltaX < 0;
                boolean isVelocityXLeft = isRtl ? velocityX > 0 : velocityX < 0;
                if (((isSignificantMove && !isDeltaXLeft && !isFling) || (isFling && !isVelocityXLeft))
                        && mCurrentPage > 0) {
                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
                    snapToPageWithVelocity(finalPage, velocityX);
                } else if (((isSignificantMove && isDeltaXLeft && !isFling) || (isFling && isVelocityXLeft))
                        && mCurrentPage < getChildCount() - 1) {
                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
                    snapToPageWithVelocity(finalPage, velocityX);
                } else {
                    snapToDestination();
                }
            } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
                // at this point we have not moved beyond the touch slop
                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
                // we can just page
                int nextPage = Math.max(0, mCurrentPage - 1);
                if (nextPage != mCurrentPage) {
                    snapToPage(nextPage);
                } else {
                    snapToDestination();
                }
            } else {
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }

                float scaleX = getScaleX();
                int vX = (int) (-velocityX * scaleX);
                int initialScrollX = (int) (getScrollX() * scaleX);

                mScroller.fling(initialScrollX, getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0,
                        0);
                invalidate();
            }
        } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
            // at this point we have not moved beyond the touch slop
            // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
            // we can just page
            int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
            if (nextPage != mCurrentPage) {
                snapToPage(nextPage);
            } else {
                snapToDestination();
            }
        } else if (mTouchState == TOUCH_STATE_REORDERING) {
            // Update the last motion position
            mLastMotionX = ev.getX();
            mLastMotionY = ev.getY();

            // Update the parent down so that our zoom animations take this new movement into
            // account
            float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
            mParentDownMotionX = pt[0];
            mParentDownMotionY = pt[1];
            updateDragViewTranslationDuringDrag();
            boolean handledFling = false;
            if (!DISABLE_FLING_TO_DELETE) {
                // Check the velocity and see if we are flinging-to-delete
                PointF flingToDeleteVector = isFlingingToDelete();
                if (flingToDeleteVector != null) {
                    onFlingToDelete(flingToDeleteVector);
                    handledFling = true;
                }
            }
            if (!handledFling
                    && isHoveringOverDeleteDropTarget((int) mParentDownMotionX, (int) mParentDownMotionY)) {
                onDropToDelete();
            }
        } else {
            if (!mCancelTap) {
                onUnhandledTap(ev);
            }
        }

        // Remove the callback to wait for the side page hover timeout
        removeCallbacks(mSidePageHoverRunnable);
        // End any intermediate reordering states
        resetTouchState();
        break;

    case MotionEvent.ACTION_CANCEL:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            snapToDestination();
        }
        resetTouchState();
        break;

    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        releaseVelocityTracker();
        break;
    }

    return true;
}

From source file:com.n2hsu.launcher.Page.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (DISABLE_TOUCH_INTERACTION) {
        return false;
    }//from w  ww . ja  v a 2 s.c  o m

    super.onTouchEvent(ev);

    // Skip touch handling if there are no pages to swipe
    if (getChildCount() <= 0)
        return super.onTouchEvent(ev);

    acquireVelocityTrackerAndAddMovement(ev);

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {
    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
        mDownMotionX = mLastMotionX = ev.getX();
        mDownMotionY = mLastMotionY = ev.getY();
        mDownScrollX = getScrollX();
        float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
        mParentDownMotionX = p[0];
        mParentDownMotionY = p[1];
        mLastMotionXRemainder = 0;
        mTotalMotionX = 0;
        mActivePointerId = ev.getPointerId(0);

        if (mTouchState == TOUCH_STATE_SCROLLING) {
            pageBeginMoving();
        }
        break;

    case MotionEvent.ACTION_MOVE:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            // Scroll to follow the motion event
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);

            if (pointerIndex == -1)
                return true;

            final float x = ev.getX(pointerIndex);
            final float deltaX = mLastMotionX + mLastMotionXRemainder - x;

            mTotalMotionX += Math.abs(deltaX);

            // Only scroll and update mLastMotionX if we have moved some
            // discrete amount. We
            // keep the remainder because we are actually testing if we've
            // moved from the last
            // scrolled position (which is discrete).
            if (Math.abs(deltaX) >= 1.0f) {
                mTouchX += deltaX;
                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                if (!mDeferScrollUpdate) {
                    scrollBy((int) deltaX, 0);
                    if (DEBUG)
                        Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
                } else {
                    invalidate();
                }
                mLastMotionX = x;
                mLastMotionXRemainder = deltaX - (int) deltaX;
            } else {
                awakenScrollBars();
            }
        } else if (mTouchState == TOUCH_STATE_REORDERING) {
            // Update the last motion position
            mLastMotionX = ev.getX();
            mLastMotionY = ev.getY();

            // Update the parent down so that our zoom animations take this
            // new movement into
            // account
            float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
            mParentDownMotionX = pt[0];
            mParentDownMotionY = pt[1];
            updateDragViewTranslationDuringDrag();

            // Find the closest page to the touch point
            final int dragViewIndex = indexOfChild(mDragView);

            // Change the drag view if we are hovering over the drop target
            boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
                    (int) mParentDownMotionY);
            setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);

            if (DEBUG)
                Log.d(TAG, "mLastMotionX: " + mLastMotionX);
            if (DEBUG)
                Log.d(TAG, "mLastMotionY: " + mLastMotionY);
            if (DEBUG)
                Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
            if (DEBUG)
                Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);

            final int pageUnderPointIndex = getNearestHoverOverPageIndex();
            if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView)
                    && !isHoveringOverDelete) {
                mTempVisiblePagesRange[0] = 0;
                mTempVisiblePagesRange[1] = getPageCount() - 1;
                getOverviewModePages(mTempVisiblePagesRange);
                if (mTempVisiblePagesRange[0] <= pageUnderPointIndex
                        && pageUnderPointIndex <= mTempVisiblePagesRange[1]
                        && pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
                    mSidePageHoverIndex = pageUnderPointIndex;
                    mSidePageHoverRunnable = new Runnable() {
                        @Override
                        public void run() {
                            // Setup the scroll to the correct page before
                            // we swap the views
                            snapToPage(pageUnderPointIndex);

                            // For each of the pages between the paged view
                            // and the drag view,
                            // animate them from the previous position to
                            // the new position in
                            // the layout (as a result of the drag view
                            // moving in the layout)
                            int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
                            int lowerIndex = (dragViewIndex < pageUnderPointIndex) ? dragViewIndex + 1
                                    : pageUnderPointIndex;
                            int upperIndex = (dragViewIndex > pageUnderPointIndex) ? dragViewIndex - 1
                                    : pageUnderPointIndex;
                            for (int i = lowerIndex; i <= upperIndex; ++i) {
                                View v = getChildAt(i);
                                // dragViewIndex < pageUnderPointIndex, so
                                // after we remove the
                                // drag view all subsequent views to
                                // pageUnderPointIndex will
                                // shift down.
                                int oldX = getViewportOffsetX() + getChildOffset(i);
                                int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);

                                // Animate the view translation from its old
                                // position to its new
                                // position
                                AnimatorSet anim = (AnimatorSet) v.getTag(ANIM_TAG_KEY);
                                if (anim != null) {
                                    anim.cancel();
                                }

                                v.setTranslationX(oldX - newX);
                                anim = new AnimatorSet();
                                anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
                                anim.playTogether(ObjectAnimator.ofFloat(v, "translationX", 0f));
                                anim.start();
                                v.setTag(anim);
                            }

                            removeView(mDragView);
                            onRemoveView(mDragView, false);
                            addView(mDragView, pageUnderPointIndex);
                            onAddView(mDragView, pageUnderPointIndex);
                            mSidePageHoverIndex = -1;
                            mPageIndicator.setActiveMarker(getNextPage());
                        }
                    };
                    postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
                }
            } else {
                removeCallbacks(mSidePageHoverRunnable);
                mSidePageHoverIndex = -1;
            }
        } else {
            determineScrollingStart(ev);
        }
        break;

    case MotionEvent.ACTION_UP:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            final int activePointerId = mActivePointerId;
            final int pointerIndex = ev.findPointerIndex(activePointerId);
            final float x = ev.getX(pointerIndex);
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
            final int deltaX = (int) (x - mDownMotionX);
            final int pageWidth = getPageAt(mCurrentPage).getMeasuredWidth();
            boolean isSignificantMove = Math.abs(deltaX) > pageWidth * SIGNIFICANT_MOVE_THRESHOLD;

            mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);

            boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING
                    && Math.abs(velocityX) > mFlingThresholdVelocity;

            if (!mFreeScroll) {
                // In the case that the page is moved far to one direction
                // and then is flung
                // in the opposite direction, we use a threshold to
                // determine whether we should
                // just return to the starting page, or if we should skip
                // one further.
                boolean returnToOriginalPage = false;
                if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD
                        && Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
                    returnToOriginalPage = true;
                }

                int finalPage;
                // We give flings precedence over large moves, which is why
                // we short-circuit our
                // test for a large move if a fling has been registered.
                // That is, a large
                // move to the left and fling to the right will register as
                // a fling to the right.
                final boolean isRtl = isLayoutRtl();
                boolean isDeltaXLeft = isRtl ? deltaX > 0 : deltaX < 0;
                boolean isVelocityXLeft = isRtl ? velocityX > 0 : velocityX < 0;
                if (((isSignificantMove && !isDeltaXLeft && !isFling) || (isFling && !isVelocityXLeft))
                        && mCurrentPage > 0) {
                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
                    snapToPageWithVelocity(finalPage, velocityX);
                } else if (((isSignificantMove && isDeltaXLeft && !isFling) || (isFling && isVelocityXLeft))
                        && mCurrentPage < getChildCount() - 1) {
                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
                    snapToPageWithVelocity(finalPage, velocityX);
                } else {
                    snapToDestination();
                }
            } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
                // at this point we have not moved beyond the touch slop
                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING),
                // so
                // we can just page
                int nextPage = Math.max(0, mCurrentPage - 1);
                if (nextPage != mCurrentPage) {
                    snapToPage(nextPage);
                } else {
                    snapToDestination();
                }
            } else {
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }

                float scaleX = getScaleX();
                int vX = (int) (-velocityX * scaleX);
                int initialScrollX = (int) (getScrollX() * scaleX);

                mScroller.fling(initialScrollX, getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0,
                        0);
                invalidate();
            }
        } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
            // at this point we have not moved beyond the touch slop
            // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
            // we can just page
            int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
            if (nextPage != mCurrentPage) {
                snapToPage(nextPage);
            } else {
                snapToDestination();
            }
        } else if (mTouchState == TOUCH_STATE_REORDERING) {
            // Update the last motion position
            mLastMotionX = ev.getX();
            mLastMotionY = ev.getY();

            // Update the parent down so that our zoom animations take this
            // new movement into
            // account
            float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
            mParentDownMotionX = pt[0];
            mParentDownMotionY = pt[1];
            updateDragViewTranslationDuringDrag();
            boolean handledFling = false;
            if (!DISABLE_FLING_TO_DELETE) {
                // Check the velocity and see if we are flinging-to-delete
                PointF flingToDeleteVector = isFlingingToDelete();
                if (flingToDeleteVector != null) {
                    onFlingToDelete(flingToDeleteVector);
                    handledFling = true;
                }
            }
            if (!handledFling
                    && isHoveringOverDeleteDropTarget((int) mParentDownMotionX, (int) mParentDownMotionY)) {
                onDropToDelete();
            }
        } else {
            if (!mCancelTap) {
                onUnhandledTap(ev);
            }
        }

        // Remove the callback to wait for the side page hover timeout
        removeCallbacks(mSidePageHoverRunnable);
        // End any intermediate reordering states
        resetTouchState();
        break;

    case MotionEvent.ACTION_CANCEL:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            snapToDestination();
        }
        resetTouchState();
        break;

    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        releaseVelocityTracker();
        break;
    }

    return true;
}

From source file:com.wb.launcher3.Page.java

public boolean handleMotionEvent(MotionEvent ev) {
    if (getChildCount() <= 0) {
        return false;
    }/*  w  w  w .j a  va2 s  .c o  m*/
    acquireVelocityTrackerAndAddMovement(ev);
    switch (MotionEvent.ACTION_MASK & ev.getAction()) {
    case MotionEvent.ACTION_POINTER_DOWN:
        if (ev.getPointerCount() <= 2) {
            if (!this.mScroller.isFinished()) {
                this.mScroller.abortAnimation();
            }
            int index = (ev.getAction()
                    & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
            float px = ev.getX(index);
            mLastMotionX = px;
            mDownMotionX = px;
            mLastMotionY = ev.getY(index);
            mLastMotionXRemainder = 0.0F;
            mTotalMotionX = 0.0F;
            mActivePointerId = ev.getPointerId(index);
            mTouchState = TOUCH_STATE_SCROLLING;
            pageBeginMoving();
        }
        break;
    case MotionEvent.ACTION_MOVE:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            int pointerIndex = ev.findPointerIndex(mActivePointerId);
            if (pointerIndex >= 0) {
                float x = ev.getX(pointerIndex);
                float deltaX = mLastMotionX + mLastMotionXRemainder - x;
                mTotalMotionX += Math.abs(deltaX);
                if (Math.abs(deltaX) >= 1.0F) {
                    mTouchX += deltaX;
                    mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                    if (!mDeferScrollUpdate) {
                        scrollBy((int) deltaX, 0);
                        if (DEBUG)
                            Log.d(TAG, "handleMotionEvent().Scrolling: " + deltaX);
                    } else {
                        invalidate();
                    }
                    mLastMotionX = x;
                    mLastMotionXRemainder = deltaX - (int) deltaX;
                } else {
                    awakenScrollBars();
                }
            }
        } else {
            determineScrollingStart(ev);
        }
        break;

    case MotionEvent.ACTION_POINTER_UP:
        if (ev.getPointerCount() > 2) {
            onOtherPointerUp(ev);
            break;
        }

        if (mTouchState == TOUCH_STATE_SCROLLING) {
            final int activePointerId = mActivePointerId;
            final int pointerIndex = ev.findPointerIndex(activePointerId);
            final float x = ev.getX(pointerIndex);
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
            final int deltaX = (int) (x - mDownMotionX);
            final int pageWidth = getPageAt(mCurrentPage).getMeasuredWidth();
            boolean isSignificantMove = Math.abs(deltaX) > pageWidth * SIGNIFICANT_MOVE_THRESHOLD;

            mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);

            boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING
                    && Math.abs(velocityX) > mFlingThresholdVelocity;
            boolean returnToOriginalPage = false;
            if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD
                    && Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
                returnToOriginalPage = true;
            }

            if (TydtechConfig.CYCLE_ROLL_PAGES_ENABLED) {
                m_moveNextDeltaX = deltaX;
                m_isSignificantMoveNext = (!returnToOriginalPage && (isSignificantMove || isFling));
            }

            int finalPage;
            if (((isSignificantMove && deltaX > 0 && !isFling) || (isFling && velocityX > 0))
                    && mCurrentPage > 0) {
                finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
                snapToPageWithVelocity(finalPage, velocityX);
            } else if (((isSignificantMove && deltaX < 0 && !isFling) || (isFling && velocityX < 0))
                    && mCurrentPage < getChildCount() - 1) {
                finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
                snapToPageWithVelocity(finalPage, velocityX);
            } else {
                snapToDestination();
            }
        } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
            int nextPage = Math.max(0, mCurrentPage - 1);
            if (nextPage != mCurrentPage) {
                snapToPage(nextPage);
            } else {
                snapToDestination();
            }
        } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
            int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
            if (nextPage != mCurrentPage) {
                snapToPage(nextPage);
            } else {
                snapToDestination();
            }
        } else {
            snapToDestination();
            onUnhandledTap(ev);
        }
        mTouchState = TOUCH_STATE_REST;
        mActivePointerId = INVALID_POINTER;
        releaseVelocityTracker();
        break;

    case MotionEvent.ACTION_CANCEL:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            snapToDestination();
        }
        mTouchState = TOUCH_STATE_REST;
        mActivePointerId = INVALID_POINTER;
        releaseVelocityTracker();
        break;
    }

    return true;
}

From source file:com.wb.launcher3.Page.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (DISABLE_TOUCH_INTERACTION) {
        return false;
    }//from   w ww.j a  v a 2  s.com

    super.onTouchEvent(ev);

    // Skip touch handling if there are no pages to swipe
    if (getChildCount() <= 0)
        return super.onTouchEvent(ev);

    acquireVelocityTrackerAndAddMovement(ev);

    final int action = ev.getAction();

    switch (action & MotionEvent.ACTION_MASK) {
    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
        mDownMotionX = mLastMotionX = ev.getX();
        mDownMotionY = mLastMotionY = ev.getY();
        mDownScrollX = getScrollX();
        float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
        mParentDownMotionX = p[0];
        mParentDownMotionY = p[1];
        mLastMotionXRemainder = 0;
        mTotalMotionX = 0;
        mActivePointerId = ev.getPointerId(0);

        if (mTouchState == TOUCH_STATE_SCROLLING) {
            pageBeginMoving();
        }
        break;

    case MotionEvent.ACTION_MOVE:
        //*/zhangwuba add 2014-5-8
        if (getLauncherDeleteAppSate()) {
            return true;
        }
        //*/
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            // Scroll to follow the motion event
            final int pointerIndex = ev.findPointerIndex(mActivePointerId);

            if (pointerIndex == -1)
                return true;

            final float x = ev.getX(pointerIndex);
            final float deltaX = mLastMotionX + mLastMotionXRemainder - x;

            mTotalMotionX += Math.abs(deltaX);

            // Only scroll and update mLastMotionX if we have moved some discrete amount.  We
            // keep the remainder because we are actually testing if we've moved from the last
            // scrolled position (which is discrete).
            if (Math.abs(deltaX) >= 1.0f) {
                mTouchX += deltaX;
                mSmoothingTime = System.nanoTime() / NANOTIME_DIV;
                if (!mDeferScrollUpdate) {
                    scrollBy((int) deltaX, 0);
                    if (DEBUG)
                        Log.d(TAG, "onTouchEvent().Scrolling: " + deltaX);
                } else {
                    invalidate();
                }
                mLastMotionX = x;
                mLastMotionXRemainder = deltaX - (int) deltaX;
            } else {
                awakenScrollBars();
            }
        } else if (mTouchState == TOUCH_STATE_REORDERING) {
            // Update the last motion position
            mLastMotionX = ev.getX();
            mLastMotionY = ev.getY();

            // Update the parent down so that our zoom animations take this new movement into
            // account
            float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
            mParentDownMotionX = pt[0];
            mParentDownMotionY = pt[1];
            updateDragViewTranslationDuringDrag();

            // Find the closest page to the touch point
            final int dragViewIndex = indexOfChild(mDragView);

            // Change the drag view if we are hovering over the drop target
            boolean isHoveringOverDelete = isHoveringOverDeleteDropTarget((int) mParentDownMotionX,
                    (int) mParentDownMotionY);
            setPageHoveringOverDeleteDropTarget(dragViewIndex, isHoveringOverDelete);

            if (DEBUG)
                Log.d(TAG, "mLastMotionX: " + mLastMotionX);
            if (DEBUG)
                Log.d(TAG, "mLastMotionY: " + mLastMotionY);
            if (DEBUG)
                Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX);
            if (DEBUG)
                Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY);

            final int pageUnderPointIndex = getNearestHoverOverPageIndex();
            if (pageUnderPointIndex > -1 && pageUnderPointIndex != indexOfChild(mDragView)
                    && !isHoveringOverDelete) {
                mTempVisiblePagesRange[0] = 0;
                mTempVisiblePagesRange[1] = getPageCount() - 1;
                getOverviewModePages(mTempVisiblePagesRange);
                if (mTempVisiblePagesRange[0] <= pageUnderPointIndex
                        && pageUnderPointIndex <= mTempVisiblePagesRange[1]
                        && pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) {
                    mSidePageHoverIndex = pageUnderPointIndex;
                    mSidePageHoverRunnable = new Runnable() {
                        @Override
                        public void run() {
                            // Setup the scroll to the correct page before we swap the views
                            snapToPage(pageUnderPointIndex);

                            // For each of the pages between the paged view and the drag view,
                            // animate them from the previous position to the new position in
                            // the layout (as a result of the drag view moving in the layout)
                            int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1;
                            int lowerIndex = (dragViewIndex < pageUnderPointIndex) ? dragViewIndex + 1
                                    : pageUnderPointIndex;
                            int upperIndex = (dragViewIndex > pageUnderPointIndex) ? dragViewIndex - 1
                                    : pageUnderPointIndex;
                            for (int i = lowerIndex; i <= upperIndex; ++i) {
                                View v = getChildAt(i);
                                // dragViewIndex < pageUnderPointIndex, so after we remove the
                                // drag view all subsequent views to pageUnderPointIndex will
                                // shift down.
                                int oldX = getViewportOffsetX() + getChildOffset(i);
                                int newX = getViewportOffsetX() + getChildOffset(i + shiftDelta);

                                // Animate the view translation from its old position to its new
                                // position
                                AnimatorSet anim = (AnimatorSet) v.getTag(ANIM_TAG_KEY);
                                if (anim != null) {
                                    anim.cancel();
                                }

                                v.setTranslationX(oldX - newX);
                                anim = new AnimatorSet();
                                anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION);
                                anim.playTogether(ObjectAnimator.ofFloat(v, "translationX", 0f));
                                anim.start();
                                v.setTag(anim);
                            }

                            removeView(mDragView);
                            onRemoveView(mDragView, false);
                            addView(mDragView, pageUnderPointIndex);
                            onAddView(mDragView, pageUnderPointIndex);
                            mSidePageHoverIndex = -1;
                            mPageIndicator.setActiveMarker(getNextPage());
                        }
                    };
                    postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT);
                }
            } else {
                removeCallbacks(mSidePageHoverRunnable);
                mSidePageHoverIndex = -1;
            }
        } else {
            determineScrollingStart(ev);
        }
        break;

    case MotionEvent.ACTION_UP:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            final int activePointerId = mActivePointerId;
            final int pointerIndex = ev.findPointerIndex(activePointerId);
            final float x = ev.getX(pointerIndex);
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
            final int deltaX = (int) (x - mDownMotionX);
            final int pageWidth = getPageAt(mCurrentPage).getMeasuredWidth();
            boolean isSignificantMove = Math.abs(deltaX) > pageWidth * SIGNIFICANT_MOVE_THRESHOLD;

            mTotalMotionX += Math.abs(mLastMotionX + mLastMotionXRemainder - x);

            boolean isFling = mTotalMotionX > MIN_LENGTH_FOR_FLING
                    && Math.abs(velocityX) > mFlingThresholdVelocity;

            if (!mFreeScroll) {
                // In the case that the page is moved far to one direction and then is flung
                // in the opposite direction, we use a threshold to determine whether we should
                // just return to the starting page, or if we should skip one further.
                boolean returnToOriginalPage = false;
                if (Math.abs(deltaX) > pageWidth * RETURN_TO_ORIGINAL_PAGE_THRESHOLD
                        && Math.signum(velocityX) != Math.signum(deltaX) && isFling) {
                    returnToOriginalPage = true;
                }

                //*/Added by tyd Greg 2014-03-20,for transition effect
                if (TydtechConfig.CYCLE_ROLL_PAGES_ENABLED) {
                    m_moveNextDeltaX = deltaX;
                    m_isSignificantMoveNext = (!returnToOriginalPage && (isSignificantMove || isFling));
                }
                //*/

                int finalPage;
                // We give flings precedence over large moves, which is why we short-circuit our
                // test for a large move if a fling has been registered. That is, a large
                // move to the left and fling to the right will register as a fling to the right.
                final boolean isRtl = isLayoutRtl();
                boolean isDeltaXLeft = isRtl ? deltaX > 0 : deltaX < 0;
                boolean isVelocityXLeft = isRtl ? velocityX > 0 : velocityX < 0;
                if (((isSignificantMove && !isDeltaXLeft && !isFling) || (isFling && !isVelocityXLeft))
                        && mCurrentPage > 0) {
                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage - 1;
                    snapToPageWithVelocity(finalPage, velocityX);
                } else if (((isSignificantMove && isDeltaXLeft && !isFling) || (isFling && isVelocityXLeft))
                        && mCurrentPage < getChildCount() - 1) {
                    finalPage = returnToOriginalPage ? mCurrentPage : mCurrentPage + 1;
                    snapToPageWithVelocity(finalPage, velocityX);
                } else {
                    snapToDestination();
                }
            } else if (mTouchState == TOUCH_STATE_PREV_PAGE) {
                // at this point we have not moved beyond the touch slop
                // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
                // we can just page
                int nextPage = Math.max(0, mCurrentPage - 1);
                if (nextPage != mCurrentPage) {
                    snapToPage(nextPage);
                } else {
                    snapToDestination();
                }
            } else {
                if (!mScroller.isFinished()) {
                    mScroller.abortAnimation();
                }

                float scaleX = getScaleX();
                int vX = (int) (-velocityX * scaleX);
                int initialScrollX = (int) (getScrollX() * scaleX);

                mScroller.fling(initialScrollX, getScrollY(), vX, 0, Integer.MIN_VALUE, Integer.MAX_VALUE, 0,
                        0);
                invalidate();
            }
        } else if (mTouchState == TOUCH_STATE_NEXT_PAGE) {
            // at this point we have not moved beyond the touch slop
            // (otherwise mTouchState would be TOUCH_STATE_SCROLLING), so
            // we can just page
            int nextPage = Math.min(getChildCount() - 1, mCurrentPage + 1);
            if (nextPage != mCurrentPage) {
                snapToPage(nextPage);
            } else {
                snapToDestination();
            }
        } else if (mTouchState == TOUCH_STATE_REORDERING) {
            // Update the last motion position
            mLastMotionX = ev.getX();
            mLastMotionY = ev.getY();

            // Update the parent down so that our zoom animations take this new movement into
            // account
            float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY);
            mParentDownMotionX = pt[0];
            mParentDownMotionY = pt[1];
            updateDragViewTranslationDuringDrag();
            boolean handledFling = false;
            if (!DISABLE_FLING_TO_DELETE) {
                // Check the velocity and see if we are flinging-to-delete
                PointF flingToDeleteVector = isFlingingToDelete();
                if (flingToDeleteVector != null) {
                    onFlingToDelete(flingToDeleteVector);
                    handledFling = true;
                }
            }
            if (!handledFling
                    && isHoveringOverDeleteDropTarget((int) mParentDownMotionX, (int) mParentDownMotionY)) {
                onDropToDelete();
            }
        }
        //*/Added by tyd Greg 2014-03-21,for support the touch swipe gesture
        else if (mTouchState == TOUCH_SWIPE_DOWN_GESTURE) {
            if (mOnTouchSwipeGestureListener != null) {
                mOnTouchSwipeGestureListener.fireSwipeDownAction();
            }
        } else if (mTouchState == TOUCH_SWIPE_UP_GESTURE) {
            if (mOnTouchSwipeGestureListener != null) {
                mOnTouchSwipeGestureListener.fireSwipeUpAction();
            }
        }
        //*/

        else {
            if (!mCancelTap) {
                onUnhandledTap(ev);
            }
        }

        // Remove the callback to wait for the side page hover timeout
        removeCallbacks(mSidePageHoverRunnable);
        // End any intermediate reordering states
        resetTouchState();
        break;

    case MotionEvent.ACTION_CANCEL:
        if (mTouchState == TOUCH_STATE_SCROLLING) {
            snapToDestination();
        }
        resetTouchState();
        break;

    case MotionEvent.ACTION_POINTER_UP:
        onSecondaryPointerUp(ev);
        releaseVelocityTracker();
        break;
    }

    return true;
}

From source file:com.appunite.list.AbsHorizontalListView.java

@Override
public boolean onTouchEvent(MotionEvent ev) {
    if (!isEnabled()) {
        // A disabled view that is clickable still consumes the touch
        // events, it just doesn't respond to them.
        return isClickable() || isLongClickable();
    }/*from  w w w . j a  v  a2s.  c om*/

    if (mPositionScroller != null) {
        mPositionScroller.stop();
    }

    if (!mIsAttached) {
        // Something isn't right.
        // Since we rely on being attached to get data set change notifications,
        // don't risk doing anything where we might try to resync and find things
        // in a bogus state.
        return false;
    }

    final int action = ev.getAction();

    View v;

    initVelocityTrackerIfNotExists();
    mVelocityTracker.addMovement(ev);

    switch (action & MotionEvent.ACTION_MASK) {
    case MotionEvent.ACTION_DOWN: {
        switch (mTouchMode) {
        case TOUCH_MODE_OVERFLING: {
            mFlingRunnable.endFling();
            if (mPositionScroller != null) {
                mPositionScroller.stop();
            }
            mTouchMode = TOUCH_MODE_OVERSCROLL;
            mMotionX = mLastX = (int) ev.getX();
            mMotionY = (int) ev.getY();
            mMotionCorrection = 0;
            mActivePointerId = ev.getPointerId(0);
            mDirection = 0;
            break;
        }

        default: {
            mActivePointerId = ev.getPointerId(0);
            final int x = (int) ev.getX();
            final int y = (int) ev.getY();
            int motionPosition = pointToPosition(x, y);
            if (!mDataChanged) {
                if ((mTouchMode != TOUCH_MODE_FLING) && (motionPosition >= 0)
                        && (getAdapter().isEnabled(motionPosition))) {
                    // User clicked on an actual view (and was not stopping a fling).
                    // It might be a click or a scroll. Assume it is a click until
                    // proven otherwise
                    mTouchMode = TOUCH_MODE_DOWN;
                    // FIXME Debounce
                    if (mPendingCheckForTap == null) {
                        mPendingCheckForTap = new CheckForTap();
                    }
                    postDelayed(mPendingCheckForTap, ViewConfiguration.getTapTimeout());
                } else {
                    if (mTouchMode == TOUCH_MODE_FLING) {
                        // Stopped a fling. It is a scroll.
                        createScrollingCache();
                        mTouchMode = TOUCH_MODE_SCROLL;
                        mMotionCorrection = 0;
                        motionPosition = findMotionCol(x);
                        mFlingRunnable.flywheelTouch();
                    }
                }
            }

            if (motionPosition >= 0) {
                // Remember where the motion event started
                v = getChildAt(motionPosition - mFirstPosition);
                mMotionViewOriginalLeft = v.getLeft();
            }
            mMotionX = x;
            mMotionY = y;
            mMotionPosition = motionPosition;
            mLastX = Integer.MIN_VALUE;
            break;
        }
        }

        if (performButtonActionOnTouchDownUnhide(ev)) {
            if (mTouchMode == TOUCH_MODE_DOWN) {
                removeCallbacks(mPendingCheckForTap);
            }
        }
        break;
    }

    case MotionEvent.ACTION_MOVE: {
        int pointerIndex = ev.findPointerIndex(mActivePointerId);
        if (pointerIndex == -1) {
            pointerIndex = 0;
            mActivePointerId = ev.getPointerId(pointerIndex);
        }
        final int x = (int) ev.getX(pointerIndex);

        if (mDataChanged) {
            // Re-sync everything if data has been changed
            // since the scroll operation can query the adapter.
            layoutChildren();
        }

        switch (mTouchMode) {
        case TOUCH_MODE_DOWN:
        case TOUCH_MODE_TAP:
        case TOUCH_MODE_DONE_WAITING:
            // Check if we have moved far enough that it looks more like a
            // scroll than a tap
            startScrollIfNeeded(x);
            break;
        case TOUCH_MODE_SCROLL:
        case TOUCH_MODE_OVERSCROLL:
            scrollIfNeeded(x);
            break;
        }
        break;
    }

    case MotionEvent.ACTION_UP: {
        switch (mTouchMode) {
        case TOUCH_MODE_DOWN:
        case TOUCH_MODE_TAP:
        case TOUCH_MODE_DONE_WAITING:
            final int motionPosition = mMotionPosition;
            final View child = getChildAt(motionPosition - mFirstPosition);

            final float y = ev.getY();
            final boolean inList = y > mListPadding.top && y < getHeight() - mListPadding.bottom;

            if (child != null && !child.hasFocusable() && inList) {
                if (mTouchMode != TOUCH_MODE_DOWN) {
                    child.setPressed(false);
                }

                if (mPerformClick == null) {
                    mPerformClick = new PerformClick();
                }

                final AbsHorizontalListView.PerformClick performClick = mPerformClick;
                performClick.mClickMotionPosition = motionPosition;
                performClick.rememberWindowAttachCount();

                mResurrectToPosition = motionPosition;

                if (mTouchMode == TOUCH_MODE_DOWN || mTouchMode == TOUCH_MODE_TAP) {
                    final Handler handler = getHandler();
                    if (handler != null) {
                        handler.removeCallbacks(mTouchMode == TOUCH_MODE_DOWN ? mPendingCheckForTap
                                : mPendingCheckForLongPress);
                    }
                    mLayoutMode = LAYOUT_NORMAL;
                    if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
                        mTouchMode = TOUCH_MODE_TAP;
                        setSelectedPositionInt(mMotionPosition);
                        layoutChildren();
                        child.setPressed(true);
                        positionSelector(mMotionPosition, child);
                        setPressed(true);
                        if (mSelector != null) {
                            Drawable d = mSelector.getCurrent();
                            if (d != null && d instanceof TransitionDrawable) {
                                ((TransitionDrawable) d).resetTransition();
                            }
                        }
                        if (mTouchModeReset != null) {
                            removeCallbacks(mTouchModeReset);
                        }
                        mTouchModeReset = new Runnable() {
                            @Override
                            public void run() {
                                mTouchModeReset = null;
                                mTouchMode = TOUCH_MODE_REST;
                                child.setPressed(false);
                                setPressed(false);
                                if (!mDataChanged) {
                                    performClick.run();
                                }
                            }
                        };
                        postDelayed(mTouchModeReset, ViewConfiguration.getPressedStateDuration());
                    } else {
                        mTouchMode = TOUCH_MODE_REST;
                        updateSelectorState();
                    }
                    return true;
                } else if (!mDataChanged && mAdapter.isEnabled(motionPosition)) {
                    performClick.run();
                }
            }
            mTouchMode = TOUCH_MODE_REST;
            updateSelectorState();
            break;
        case TOUCH_MODE_SCROLL:
            final int childCount = getChildCount();
            if (childCount > 0) {
                final int firstChildLeft = getChildAt(0).getLeft();
                final int lastChildRight = getChildAt(childCount - 1).getRight();
                final int contentLeft = mListPadding.left;
                final int contentRight = getWidth() - mListPadding.right;
                if (mFirstPosition == 0 && firstChildLeft >= contentLeft
                        && mFirstPosition + childCount < mItemCount
                        && lastChildRight <= getWidth() - contentRight) {
                    mTouchMode = TOUCH_MODE_REST;
                    reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                } else {
                    final VelocityTracker velocityTracker = mVelocityTracker;
                    velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);

                    final int initialVelocity = (int) (velocityTracker.getXVelocity(mActivePointerId)
                            * mVelocityScale);
                    // Fling if we have enough velocity and we aren't at a boundary.
                    // Since we can potentially overfling more than we can overscroll, don't
                    // allow the weird behavior where you can scroll to a boundary then
                    // fling further.
                    if (Math.abs(initialVelocity) > mMinimumVelocity
                            && !((mFirstPosition == 0 && firstChildLeft == contentLeft - mOverscrollDistance)
                                    || (mFirstPosition + childCount == mItemCount
                                            && lastChildRight == contentRight + mOverscrollDistance))) {
                        if (mFlingRunnable == null) {
                            mFlingRunnable = new FlingRunnable();
                        }
                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);

                        mFlingRunnable.start(-initialVelocity);
                    } else {
                        mTouchMode = TOUCH_MODE_REST;
                        reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
                        if (mFlingRunnable != null) {
                            mFlingRunnable.endFling();
                        }
                        if (mPositionScroller != null) {
                            mPositionScroller.stop();
                        }
                    }
                }
            } else {
                mTouchMode = TOUCH_MODE_REST;
                reportScrollStateChange(OnScrollListener.SCROLL_STATE_IDLE);
            }
            break;

        case TOUCH_MODE_OVERSCROLL:
            if (mFlingRunnable == null) {
                mFlingRunnable = new FlingRunnable();
            }
            final VelocityTracker velocityTracker = mVelocityTracker;
            velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
            final int initialVelocity = (int) velocityTracker.getXVelocity(mActivePointerId);

            reportScrollStateChange(OnScrollListener.SCROLL_STATE_FLING);
            if (Math.abs(initialVelocity) > mMinimumVelocity) {
                mFlingRunnable.startOverfling(-initialVelocity);
            } else {
                mFlingRunnable.startSpringback();
            }

            break;
        }

        setPressed(false);

        if (mEdgeGlowLeft != null) {
            mEdgeGlowLeft.onRelease();
            mEdgeGlowRight.onRelease();
        }

        // Need to redraw since we probably aren't drawing the selector anymore
        invalidate();

        final Handler handler = getHandler();
        if (handler != null) {
            handler.removeCallbacks(mPendingCheckForLongPress);
        }

        recycleVelocityTracker();

        mActivePointerId = INVALID_POINTER;

        if (PROFILE_SCROLLING) {
            if (mScrollProfilingStarted) {
                Debug.stopMethodTracing();
                mScrollProfilingStarted = false;
            }
        }

        // FIXME not needed bacaues we could not implement strict span (j.m.)
        //            if (mScrollStrictSpan != null) {
        //                mScrollStrictSpan.finish();
        //                mScrollStrictSpan = null;
        //            }
        break;
    }

    case MotionEvent.ACTION_CANCEL: {
        switch (mTouchMode) {
        case TOUCH_MODE_OVERSCROLL:
            if (mFlingRunnable == null) {
                mFlingRunnable = new FlingRunnable();
            }
            mFlingRunnable.startSpringback();
            break;

        case TOUCH_MODE_OVERFLING:
            // Do nothing - let it play out.
            break;

        default:
            mTouchMode = TOUCH_MODE_REST;
            setPressed(false);
            View motionView = this.getChildAt(mMotionPosition - mFirstPosition);
            if (motionView != null) {
                motionView.setPressed(false);
            }
            clearScrollingCache();

            final Handler handler = getHandler();
            if (handler != null) {
                handler.removeCallbacks(mPendingCheckForLongPress);
            }

            recycleVelocityTracker();
        }

        if (mEdgeGlowLeft != null) {
            mEdgeGlowLeft.onRelease();
            mEdgeGlowRight.onRelease();
        }
        mActivePointerId = INVALID_POINTER;
        break;
    }

    case MotionEvent.ACTION_POINTER_UP: {
        onSecondaryPointerUp(ev);
        final int x = mMotionX;
        final int y = mMotionY;
        final int motionPosition = pointToPosition(x, y);
        if (motionPosition >= 0) {
            // Remember where the motion event started
            v = getChildAt(motionPosition - mFirstPosition);
            mMotionViewOriginalLeft = v.getLeft();
            mMotionPosition = motionPosition;
        }
        mLastX = x;
        break;
    }

    case MotionEvent.ACTION_POINTER_DOWN: {
        // New pointers take over dragging duties
        final int index = ev.getActionIndex();
        final int id = ev.getPointerId(index);
        final int x = (int) ev.getX(index);
        final int y = (int) ev.getY(index);
        mMotionCorrection = 0;
        mActivePointerId = id;
        mMotionX = x;
        mMotionY = y;
        final int motionPosition = pointToPosition(x, y);
        if (motionPosition >= 0) {
            // Remember where the motion event started
            v = getChildAt(motionPosition - mFirstPosition);
            mMotionViewOriginalLeft = v.getLeft();
            mMotionPosition = motionPosition;
        }
        mLastX = x;
        break;
    }
    }

    return true;
}