private int findNewActiveIndex(android.view.MotionEvent ev, int otherActiveId, int oldIndex) { int pointerCount = ev.getPointerCount(); // It's ok if this isn't found and returns -1, it simply won't match. int otherActiveIndex = ev.findPointerIndex(otherActiveId); int newActiveIndex = -1; { // Pick a new id and update tracking state. Only pick pointers not on the slop edges. for (int i = 0; i < pointerCount; i++) { if (i != oldIndex && i != otherActiveIndex) { float edgeSlop = mEdgeSlop; float rightSlop = mRightSlopEdge; float bottomSlop = mBottomSlopEdge; float x = getRawX(ev, i); float y = getRawY(ev, i); if (x >= edgeSlop && y >= edgeSlop && x <= rightSlop && y <= bottomSlop) { newActiveIndex = i; break; } } } } return newActiveIndex; }
private void setContext(android.view.MotionEvent curr) { if (mCurrEvent != null) { mCurrEvent.recycle(); } mCurrEvent = android.view.MotionEvent.obtain(curr); mCurrLen = -1; mPrevLen = -1; mScaleFactor = -1; android.view.MotionEvent prev = mPrevEvent; int prevIndex0 = prev.findPointerIndex(mActiveId0); int prevIndex1 = prev.findPointerIndex(mActiveId1); int currIndex0 = curr.findPointerIndex(mActiveId0); int currIndex1 = curr.findPointerIndex(mActiveId1); if (prevIndex0 < 0 || prevIndex1 < 0 || currIndex0 < 0 || currIndex1 < 0) { mInvalidGesture = true; android.util.Log.e(TAG, "Invalid MotionEvent stream detected.", new System.Exception ()); if (mGestureInProgress) { mListener.onScaleEnd(this); } return; } float px0 = prev.getX(prevIndex0); float py0 = prev.getY(prevIndex0); float px1 = prev.getX(prevIndex1); float py1 = prev.getY(prevIndex1); float cx0 = curr.getX(currIndex0); float cy0 = curr.getY(currIndex0); float cx1 = curr.getX(currIndex1); float cy1 = curr.getY(currIndex1); float pvx = px1 - px0; float pvy = py1 - py0; float cvx = cx1 - cx0; float cvy = cy1 - cy0; mPrevFingerDiffX = pvx; mPrevFingerDiffY = pvy; mCurrFingerDiffX = cvx; mCurrFingerDiffY = cvy; mFocusX = cx0 + cvx * 0.5f; mFocusY = cy0 + cvy * 0.5f; mTimeDelta = curr.getEventTime() - prev.getEventTime(); mCurrPressure = curr.getPressure(currIndex0) + curr.getPressure(currIndex1); mPrevPressure = prev.getPressure(prevIndex0) + prev.getPressure(prevIndex1); }
public override bool onTouchEvent(android.view.MotionEvent ev) { initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); int action = ev.getAction(); switch (action & android.view.MotionEvent.ACTION_MASK) { case android.view.MotionEvent.ACTION_DOWN: { mIsBeingDragged = getChildCount() != 0; if (!mIsBeingDragged) { return false; } if (!mScroller.isFinished()) { mScroller.abortAnimation(); } // Remember where the motion event started mLastMotionX = ev.getX(); mActivePointerId = ev.getPointerId(0); break; } case android.view.MotionEvent.ACTION_MOVE: { if (mIsBeingDragged) { // Scroll to follow the motion event int activePointerIndex = ev.findPointerIndex(mActivePointerId); float x = ev.getX(activePointerIndex); int deltaX = (int)(mLastMotionX - x); mLastMotionX = x; int oldX = mScrollX; int oldY = mScrollY; int range = getScrollRange(); int overscrollMode = getOverScrollMode(); bool canOverscroll = overscrollMode == OVER_SCROLL_ALWAYS || (overscrollMode == OVER_SCROLL_IF_CONTENT_SCROLLS && range > 0); if (overScrollBy(deltaX, 0, mScrollX, 0, range, 0, mOverscrollDistance, 0, true)) { // Break our velocity if we hit a scroll barrier. mVelocityTracker.clear(); } onScrollChanged(mScrollX, mScrollY, oldX, oldY); if (canOverscroll) { int pulledToX = oldX + deltaX; if (pulledToX < 0) { mEdgeGlowLeft.onPull((float)deltaX / getWidth()); if (!mEdgeGlowRight.isFinished()) { mEdgeGlowRight.onRelease(); } } else { if (pulledToX > range) { mEdgeGlowRight.onPull((float)deltaX / getWidth()); if (!mEdgeGlowLeft.isFinished()) { mEdgeGlowLeft.onRelease(); } } } if (mEdgeGlowLeft != null && (!mEdgeGlowLeft.isFinished() || !mEdgeGlowRight.isFinished ())) { invalidate(); } } } break; } case android.view.MotionEvent.ACTION_UP: { if (mIsBeingDragged) { android.view.VelocityTracker velocityTracker = mVelocityTracker; velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); int initialVelocity = (int)velocityTracker.getXVelocity(mActivePointerId); if (getChildCount() > 0) { if ((System.Math.Abs(initialVelocity) > mMinimumVelocity)) { fling(-initialVelocity); } else { if (mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) { invalidate(); } } } mActivePointerId = INVALID_POINTER; mIsBeingDragged = false; recycleVelocityTracker(); if (mEdgeGlowLeft != null) { mEdgeGlowLeft.onRelease(); mEdgeGlowRight.onRelease(); } } break; } case android.view.MotionEvent.ACTION_CANCEL: { if (mIsBeingDragged && getChildCount() > 0) { if (mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) { invalidate(); } mActivePointerId = INVALID_POINTER; mIsBeingDragged = false; recycleVelocityTracker(); if (mEdgeGlowLeft != null) { mEdgeGlowLeft.onRelease(); mEdgeGlowRight.onRelease(); } } break; } case android.view.MotionEvent.ACTION_POINTER_UP: { onSecondaryPointerUp(ev); break; } } return true; }
public virtual bool onTouchEvent(android.view.MotionEvent @event) { if (mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onTouchEvent(@event, 0); } int action = @event.getActionMasked(); if (action == android.view.MotionEvent.ACTION_DOWN) { reset(); } // Start fresh bool handled = true; if (mInvalidGesture) { handled = false; } else { if (!mGestureInProgress) { switch (action) { case android.view.MotionEvent.ACTION_DOWN: { mActiveId0 = @event.getPointerId(0); mActive0MostRecent = true; break; } case android.view.MotionEvent.ACTION_UP: { reset(); break; } case android.view.MotionEvent.ACTION_POINTER_DOWN: { // We have a new multi-finger gesture // as orientation can change, query the metrics in touch down android.util.DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); mRightSlopEdge = metrics.widthPixels - mEdgeSlop; mBottomSlopEdge = metrics.heightPixels - mEdgeSlop; if (mPrevEvent != null) { mPrevEvent.recycle(); } mPrevEvent = android.view.MotionEvent.obtain(@event); mTimeDelta = 0; int index1 = @event.getActionIndex(); int index0 = @event.findPointerIndex(mActiveId0); mActiveId1 = @event.getPointerId(index1); if (index0 < 0 || index0 == index1) { // Probably someone sending us a broken event stream. index0 = findNewActiveIndex(@event, index0 == index1 ? -1 : mActiveId1, index0); mActiveId0 = @event.getPointerId(index0); } mActive0MostRecent = false; setContext(@event); // Check if we have a sloppy gesture. If so, delay // the beginning of the gesture until we're sure that's // what the user wanted. Sloppy gestures can happen if the // edge of the user's hand is touching the screen, for example. float edgeSlop = mEdgeSlop; float rightSlop = mRightSlopEdge; float bottomSlop = mBottomSlopEdge; float x0 = getRawX(@event, index0); float y0 = getRawY(@event, index0); float x1 = getRawX(@event, index1); float y1 = getRawY(@event, index1); bool p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop; bool p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop; if (p0sloppy && p1sloppy) { mFocusX = -1; mFocusY = -1; mSloppyGesture = true; } else { if (p0sloppy) { mFocusX = @event.getX(index1); mFocusY = @event.getY(index1); mSloppyGesture = true; } else { if (p1sloppy) { mFocusX = @event.getX(index0); mFocusY = @event.getY(index0); mSloppyGesture = true; } else { mSloppyGesture = false; mGestureInProgress = mListener.onScaleBegin(this); } } } break; } case android.view.MotionEvent.ACTION_MOVE: { if (mSloppyGesture) { // Initiate sloppy gestures if we've moved outside of the slop area. float edgeSlop = mEdgeSlop; float rightSlop = mRightSlopEdge; float bottomSlop = mBottomSlopEdge; int index0 = @event.findPointerIndex(mActiveId0); int index1 = @event.findPointerIndex(mActiveId1); float x0 = getRawX(@event, index0); float y0 = getRawY(@event, index0); float x1 = getRawX(@event, index1); float y1 = getRawY(@event, index1); bool p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop; bool p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop; if (p0sloppy) { // Do we have a different pointer that isn't sloppy? int index = findNewActiveIndex(@event, mActiveId1, index0); if (index >= 0) { index0 = index; mActiveId0 = @event.getPointerId(index); x0 = getRawX(@event, index); y0 = getRawY(@event, index); p0sloppy = false; } } if (p1sloppy) { // Do we have a different pointer that isn't sloppy? int index = findNewActiveIndex(@event, mActiveId0, index1); if (index >= 0) { index1 = index; mActiveId1 = @event.getPointerId(index); x1 = getRawX(@event, index); y1 = getRawY(@event, index); p1sloppy = false; } } if (p0sloppy && p1sloppy) { mFocusX = -1; mFocusY = -1; } else { if (p0sloppy) { mFocusX = @event.getX(index1); mFocusY = @event.getY(index1); } else { if (p1sloppy) { mFocusX = @event.getX(index0); mFocusY = @event.getY(index0); } else { mSloppyGesture = false; mGestureInProgress = mListener.onScaleBegin(this); } } } } break; } case android.view.MotionEvent.ACTION_POINTER_UP: { if (mSloppyGesture) { int pointerCount = @event.getPointerCount(); int actionIndex = @event.getActionIndex(); int actionId = @event.getPointerId(actionIndex); if (pointerCount > 2) { if (actionId == mActiveId0) { int newIndex = findNewActiveIndex(@event, mActiveId1, actionIndex); if (newIndex >= 0) { mActiveId0 = @event.getPointerId(newIndex); } } else { if (actionId == mActiveId1) { int newIndex = findNewActiveIndex(@event, mActiveId0, actionIndex); if (newIndex >= 0) { mActiveId1 = @event.getPointerId(newIndex); } } } } else { // Set focus point to the remaining finger int index = @event.findPointerIndex(actionId == mActiveId0 ? mActiveId1 : mActiveId0 ); if (index < 0) { mInvalidGesture = true; android.util.Log.e(TAG, "Invalid MotionEvent stream detected.", new System.Exception ()); if (mGestureInProgress) { mListener.onScaleEnd(this); } return false; } mActiveId0 = @event.getPointerId(index); mActive0MostRecent = true; mActiveId1 = -1; mFocusX = @event.getX(index); mFocusY = @event.getY(index); } } break; } } } else { switch (action) { case android.view.MotionEvent.ACTION_POINTER_DOWN: { // Transform gesture in progress - attempt to handle it // End the old gesture and begin a new one with the most recent two fingers. mListener.onScaleEnd(this); int oldActive0 = mActiveId0; int oldActive1 = mActiveId1; reset(); mPrevEvent = android.view.MotionEvent.obtain(@event); mActiveId0 = mActive0MostRecent ? oldActive0 : oldActive1; mActiveId1 = @event.getPointerId(@event.getActionIndex()); mActive0MostRecent = false; int index0 = @event.findPointerIndex(mActiveId0); if (index0 < 0 || mActiveId0 == mActiveId1) { // Probably someone sending us a broken event stream. android.util.Log.e(TAG, "Got " + android.view.MotionEvent.actionToString(action) + " with bad state while a gesture was in progress. " + "Did you forget to pass an event to " + "ScaleGestureDetector#onTouchEvent?"); index0 = findNewActiveIndex(@event, mActiveId0 == mActiveId1 ? -1 : mActiveId1, index0 ); mActiveId0 = @event.getPointerId(index0); } setContext(@event); mGestureInProgress = mListener.onScaleBegin(this); break; } case android.view.MotionEvent.ACTION_POINTER_UP: { int pointerCount = @event.getPointerCount(); int actionIndex = @event.getActionIndex(); int actionId = @event.getPointerId(actionIndex); bool gestureEnded = false; if (pointerCount > 2) { if (actionId == mActiveId0) { int newIndex = findNewActiveIndex(@event, mActiveId1, actionIndex); if (newIndex >= 0) { mListener.onScaleEnd(this); mActiveId0 = @event.getPointerId(newIndex); mActive0MostRecent = true; mPrevEvent = android.view.MotionEvent.obtain(@event); setContext(@event); mGestureInProgress = mListener.onScaleBegin(this); } else { gestureEnded = true; } } else { if (actionId == mActiveId1) { int newIndex = findNewActiveIndex(@event, mActiveId0, actionIndex); if (newIndex >= 0) { mListener.onScaleEnd(this); mActiveId1 = @event.getPointerId(newIndex); mActive0MostRecent = false; mPrevEvent = android.view.MotionEvent.obtain(@event); setContext(@event); mGestureInProgress = mListener.onScaleBegin(this); } else { gestureEnded = true; } } } mPrevEvent.recycle(); mPrevEvent = android.view.MotionEvent.obtain(@event); setContext(@event); } else { gestureEnded = true; } if (gestureEnded) { // Gesture ended setContext(@event); // Set focus point to the remaining finger int activeId = actionId == mActiveId0 ? mActiveId1 : mActiveId0; int index = @event.findPointerIndex(activeId); mFocusX = @event.getX(index); mFocusY = @event.getY(index); mListener.onScaleEnd(this); reset(); mActiveId0 = activeId; mActive0MostRecent = true; } break; } case android.view.MotionEvent.ACTION_CANCEL: { mListener.onScaleEnd(this); reset(); break; } case android.view.MotionEvent.ACTION_UP: { reset(); break; } case android.view.MotionEvent.ACTION_MOVE: { setContext(@event); // Only accept the event if our relative pressure is within // a certain limit - this can help filter shaky data as a // finger is lifted. if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) { bool updatePrevious = mListener.onScale(this); if (updatePrevious) { mPrevEvent.recycle(); mPrevEvent = android.view.MotionEvent.obtain(@event); } } break; } } } } if (!handled && mInputEventConsistencyVerifier != null) { mInputEventConsistencyVerifier.onUnhandledEvent(@event, 0); } return handled; }
public override bool onInterceptTouchEvent(android.view.MotionEvent ev) { int action = ev.getAction(); if ((action == android.view.MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true; } switch (action & android.view.MotionEvent.ACTION_MASK) { case android.view.MotionEvent.ACTION_MOVE: { int activePointerId = mActivePointerId; if (activePointerId == INVALID_POINTER) { // If we don't have a valid id, the touch down wasn't on content. break; } int pointerIndex = ev.findPointerIndex(activePointerId); float x = ev.getX(pointerIndex); int xDiff = (int)System.Math.Abs(x - mLastMotionX); if (xDiff > mTouchSlop) { mIsBeingDragged = true; mLastMotionX = x; initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); if (mParent != null) { mParent.requestDisallowInterceptTouchEvent(true); } } break; } case android.view.MotionEvent.ACTION_DOWN: { float x = ev.getX(); if (!inChild((int)x, (int)ev.getY())) { mIsBeingDragged = false; recycleVelocityTracker(); break; } mLastMotionX = x; mActivePointerId = ev.getPointerId(0); initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); mIsBeingDragged = !mScroller.isFinished(); break; } case android.view.MotionEvent.ACTION_CANCEL: case android.view.MotionEvent.ACTION_UP: { mIsBeingDragged = false; mActivePointerId = INVALID_POINTER; if (mScroller.springBack(mScrollX, mScrollY, 0, getScrollRange(), 0, 0)) { invalidate(); } break; } case android.view.MotionEvent.ACTION_POINTER_DOWN: { int index = ev.getActionIndex(); mLastMotionX = ev.getX(index); mActivePointerId = ev.getPointerId(index); break; } case android.view.MotionEvent.ACTION_POINTER_UP: { onSecondaryPointerUp(ev); mLastMotionX = ev.getX(ev.findPointerIndex(mActivePointerId)); break; } } return mIsBeingDragged; }
private void handlePointerUp(android.view.MotionEvent ev) { int pointerIndex = ev.findPointerIndex(mActivePointerId); float newY = ev.getY(pointerIndex); int deltaY = (int)(newY - mInitialY); mLastInteractionTime = Sharpen.Util.CurrentTimeMillis; if (mVelocityTracker != null) { mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity); mYVelocity = (int)mVelocityTracker.getYVelocity(mActivePointerId); } if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } if (deltaY > mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_DOWN && mStackSlider .mMode == android.widget.StackView.StackSlider.NORMAL_MODE) { // We reset the gesture variable, because otherwise we will ignore showPrevious() / // showNext(); mSwipeGestureType = GESTURE_NONE; // Swipe threshold exceeded, swipe down if (mStackMode == ITEMS_SLIDE_UP) { showPrevious(); } else { showNext(); } mHighlight.bringToFront(); } else { if (deltaY < -mSwipeThreshold && mSwipeGestureType == GESTURE_SLIDE_UP && mStackSlider .mMode == android.widget.StackView.StackSlider.NORMAL_MODE) { // We reset the gesture variable, because otherwise we will ignore showPrevious() / // showNext(); mSwipeGestureType = GESTURE_NONE; // Swipe threshold exceeded, swipe up if (mStackMode == ITEMS_SLIDE_UP) { showNext(); } else { showPrevious(); } mHighlight.bringToFront(); } else { if (mSwipeGestureType == GESTURE_SLIDE_UP) { // Didn't swipe up far enough, snap back down int duration; float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 1 : 0; if (mStackMode == ITEMS_SLIDE_UP || mStackSlider.mMode != android.widget.StackView .StackSlider.NORMAL_MODE) { duration = Sharpen.Util.Round(mStackSlider.getDurationForNeutralPosition()); } else { duration = Sharpen.Util.Round(mStackSlider.getDurationForOffscreenPosition()); } android.widget.StackView.StackSlider animationSlider = new android.widget.StackView .StackSlider(this, mStackSlider); android.animation.PropertyValuesHolder snapBackY = android.animation.PropertyValuesHolder .ofFloat("YProgress", finalYProgress); android.animation.PropertyValuesHolder snapBackX = android.animation.PropertyValuesHolder .ofFloat("XProgress", 0.0f); android.animation.ObjectAnimator pa = android.animation.ObjectAnimator.ofPropertyValuesHolder (animationSlider, snapBackX, snapBackY); pa.setDuration(duration); pa.setInterpolator(new android.view.animation.LinearInterpolator()); pa.start(); } else { if (mSwipeGestureType == GESTURE_SLIDE_DOWN) { // Didn't swipe down far enough, snap back up float finalYProgress = (mStackMode == ITEMS_SLIDE_DOWN) ? 0 : 1; int duration; if (mStackMode == ITEMS_SLIDE_DOWN || mStackSlider.mMode != android.widget.StackView .StackSlider.NORMAL_MODE) { duration = Sharpen.Util.Round(mStackSlider.getDurationForNeutralPosition()); } else { duration = Sharpen.Util.Round(mStackSlider.getDurationForOffscreenPosition()); } android.widget.StackView.StackSlider animationSlider = new android.widget.StackView .StackSlider(this, mStackSlider); android.animation.PropertyValuesHolder snapBackY = android.animation.PropertyValuesHolder .ofFloat("YProgress", finalYProgress); android.animation.PropertyValuesHolder snapBackX = android.animation.PropertyValuesHolder .ofFloat("XProgress", 0.0f); android.animation.ObjectAnimator pa = android.animation.ObjectAnimator.ofPropertyValuesHolder (animationSlider, snapBackX, snapBackY); pa.setDuration(duration); pa.start(); } } } } mActivePointerId = INVALID_POINTER; mSwipeGestureType = GESTURE_NONE; }
public override bool onTouchEvent(android.view.MotionEvent ev) { base.onTouchEvent(ev); int action = ev.getAction(); int pointerIndex = ev.findPointerIndex(mActivePointerId); if (pointerIndex == INVALID_POINTER) { // no data for our primary pointer, this shouldn't happen, log it android.util.Log.d(TAG, "Error: No data for our primary pointer."); return false; } float newY = ev.getY(pointerIndex); float newX = ev.getX(pointerIndex); float deltaY = newY - mInitialY; float deltaX = newX - mInitialX; if (mVelocityTracker == null) { mVelocityTracker = android.view.VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); switch (action & android.view.MotionEvent.ACTION_MASK) { case android.view.MotionEvent.ACTION_MOVE: { beginGestureIfNeeded(deltaY); float rx = deltaX / (mSlideAmount * 1.0f); if (mSwipeGestureType == GESTURE_SLIDE_DOWN) { float r = (deltaY - mTouchSlop * 1.0f) / mSlideAmount * 1.0f; if (mStackMode == ITEMS_SLIDE_DOWN) { r = 1 - r; } mStackSlider.setYProgress(1 - r); mStackSlider.setXProgress(rx); return true; } else { if (mSwipeGestureType == GESTURE_SLIDE_UP) { float r = -(deltaY + mTouchSlop * 1.0f) / mSlideAmount * 1.0f; if (mStackMode == ITEMS_SLIDE_DOWN) { r = 1 - r; } mStackSlider.setYProgress(r); mStackSlider.setXProgress(rx); return true; } } break; } case android.view.MotionEvent.ACTION_UP: { handlePointerUp(ev); break; } case android.view.MotionEvent.ACTION_POINTER_UP: { onSecondaryPointerUp(ev); break; } case android.view.MotionEvent.ACTION_CANCEL: { mActivePointerId = INVALID_POINTER; mSwipeGestureType = GESTURE_NONE; break; } } return true; }
public override bool onInterceptTouchEvent(android.view.MotionEvent ev) { int action = ev.getAction(); switch (action & android.view.MotionEvent.ACTION_MASK) { case android.view.MotionEvent.ACTION_DOWN: { if (mActivePointerId == INVALID_POINTER) { mInitialX = ev.getX(); mInitialY = ev.getY(); mActivePointerId = ev.getPointerId(0); } break; } case android.view.MotionEvent.ACTION_MOVE: { int pointerIndex = ev.findPointerIndex(mActivePointerId); if (pointerIndex == INVALID_POINTER) { // no data for our primary pointer, this shouldn't happen, log it android.util.Log.d(TAG, "Error: No data for our primary pointer."); return false; } float newY = ev.getY(pointerIndex); float deltaY = newY - mInitialY; beginGestureIfNeeded(deltaY); break; } case android.view.MotionEvent.ACTION_POINTER_UP: { onSecondaryPointerUp(ev); break; } case android.view.MotionEvent.ACTION_UP: case android.view.MotionEvent.ACTION_CANCEL: { mActivePointerId = INVALID_POINTER; mSwipeGestureType = GESTURE_NONE; break; } } return mSwipeGestureType != GESTURE_NONE; }
public override bool onInterceptTouchEvent(android.view.MotionEvent ev) { int action = ev.getAction(); if ((action == android.view.MotionEvent.ACTION_MOVE) && (mIsBeingDragged)) { return true; } switch (action & android.view.MotionEvent.ACTION_MASK) { case android.view.MotionEvent.ACTION_MOVE: { int activePointerId = mActivePointerId; if (activePointerId == INVALID_POINTER) { // If we don't have a valid id, the touch down wasn't on content. break; } int pointerIndex = ev.findPointerIndex(activePointerId); float y = ev.getY(pointerIndex); int yDiff = (int)System.Math.Abs(y - mLastMotionY); if (yDiff > mTouchSlop) { mIsBeingDragged = true; mLastMotionY = y; initVelocityTrackerIfNotExists(); mVelocityTracker.addMovement(ev); if (mScrollStrictSpan == null) { mScrollStrictSpan = android.os.StrictMode.enterCriticalSpan("ScrollView-scroll"); } } break; } case android.view.MotionEvent.ACTION_DOWN: { float y = ev.getY(); if (!inChild((int)ev.getX(), (int)y)) { mIsBeingDragged = false; recycleVelocityTracker(); break; } mLastMotionY = y; mActivePointerId = ev.getPointerId(0); initOrResetVelocityTracker(); mVelocityTracker.addMovement(ev); mIsBeingDragged = !mScroller.isFinished(); if (mIsBeingDragged && mScrollStrictSpan == null) { mScrollStrictSpan = android.os.StrictMode.enterCriticalSpan("ScrollView-scroll"); } break; } case android.view.MotionEvent.ACTION_CANCEL: case android.view.MotionEvent.ACTION_UP: { mIsBeingDragged = false; mActivePointerId = INVALID_POINTER; recycleVelocityTracker(); if (mScroller.springBack(mScrollX, mScrollY, 0, 0, 0, getScrollRange())) { invalidate(); } break; } case android.view.MotionEvent.ACTION_POINTER_UP: { onSecondaryPointerUp(ev); break; } } return mIsBeingDragged; }