List of usage examples for android.view MotionEvent getActionMasked
public final int getActionMasked()
From source file:com.haarman.listviewanimations.itemmanipulation.SwipeDismissListViewTouchListener.java
@Override public boolean onTouch(View view, MotionEvent motionEvent) { if (mVirtualListCount == -1) { mVirtualListCount = mListView.getAdapter().getCount(); }//from ww w .j av a2 s . com if (mViewWidth < 2) { mViewWidth = mListView.getWidth(); } switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: mDisallowSwipe = false; view.onTouchEvent(motionEvent); return handleDownEvent(motionEvent); case MotionEvent.ACTION_MOVE: return handleMoveEvent(motionEvent); case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: mDisallowSwipe = false; mTouchChildTouched = false; return handleUpEvent(motionEvent); } return false; }
From source file:com.itude.mobile.mobbl.blueprint.app.view.listeners.SwipeDismissRecyclerViewTouchListener.java
@Override public boolean onTouch(View view, MotionEvent motionEvent) { if (mViewWidth < 2) { mViewWidth = mIsVertical ? mRecyclerView.getHeight() : mRecyclerView.getWidth(); }//from ww w.j a v a2s.c o m switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (mPaused) { return false; } // TODO: ensure this is a finger, and set a flag // Find the child view that was touched (perform a hit test) Rect rect = new Rect(); int childCount = mRecyclerView.getChildCount(); int[] listViewCoords = new int[2]; mRecyclerView.getLocationOnScreen(listViewCoords); int x = (int) motionEvent.getRawX() - listViewCoords[0]; int y = (int) motionEvent.getRawY() - listViewCoords[1]; View child; mDownView = mRecyclerView.findChildViewUnder(x, y); if (mDownView != null) { mDownX = motionEvent.getRawX(); mDownY = motionEvent.getRawY(); mDownPosition = mRecyclerView.getChildPosition(mDownView); if (mCallbacks.canDismiss(mDownPosition)) { mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(motionEvent); } else { mDownView = null; } } return false; } case MotionEvent.ACTION_CANCEL: { if (mVelocityTracker == null) { break; } if (mDownView != null && mSwiping) { // cancel if (mIsVertical) { mDownView.animate().translationY(0).alpha(1).setDuration(mAnimationTime).setListener(null); } else { mDownView.animate().translationX(0).alpha(1).setDuration(mAnimationTime).setListener(null); } } mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = RecyclerView.NO_POSITION; mSwiping = false; break; } case MotionEvent.ACTION_UP: { if (!mSwiping && mDownView != null && mItemTouchCallback != null) { mItemTouchCallback.onTouch(mRecyclerView.getChildPosition(mDownView)); mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; mSwiping = false; return true; } if (mVelocityTracker == null) { break; } float deltaX = motionEvent.getRawX() - mDownX; float deltaY = motionEvent.getRawY() - mDownY; mVelocityTracker.addMovement(motionEvent); mVelocityTracker.computeCurrentVelocity(1000); float velocityX = mVelocityTracker.getXVelocity(); float velocityY = mVelocityTracker.getYVelocity(); float absVelocityX = Math.abs(velocityX); float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); boolean dismiss = false; boolean dismissRight = false; if (mIsVertical) { if (Math.abs(deltaY) > mViewWidth / 2 && mSwiping) { dismiss = true; dismissRight = deltaY > 0; } else if (mMinFlingVelocity <= absVelocityY && absVelocityY <= mMaxFlingVelocity && absVelocityX < absVelocityY && mSwiping) { // dismiss only if flinging in the same direction as dragging dismiss = (velocityY < 0) == (deltaY < 0); dismissRight = mVelocityTracker.getYVelocity() > 0; } if (dismiss && mDownPosition != ListView.INVALID_POSITION) { // dismiss final View downView = mDownView; // mDownView gets null'd before animation ends final int downPosition = mDownPosition; ++mDismissAnimationRefCount; mDownView.animate().translationY(dismissRight ? mViewWidth : -mViewWidth).alpha(0) .setDuration(mAnimationTime).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { performDismiss(downView, downPosition); } }); } else { // cancel mDownView.animate().translationY(0).alpha(1).setDuration(mAnimationTime).setListener(null); } mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; mSwiping = false; } else { if (Math.abs(deltaX) > mViewWidth / 2 && mSwiping) { dismiss = true; dismissRight = deltaX > 0; } else if (mMinFlingVelocity <= absVelocityX && absVelocityX <= mMaxFlingVelocity && absVelocityY < absVelocityX && mSwiping) { // dismiss only if flinging in the same direction as dragging dismiss = (velocityX < 0) == (deltaX < 0); dismissRight = mVelocityTracker.getXVelocity() > 0; } if (dismiss && mDownPosition != ListView.INVALID_POSITION) { // dismiss final View downView = mDownView; // mDownView gets null'd before animation ends final int downPosition = mDownPosition; ++mDismissAnimationRefCount; mDownView.animate().translationX(dismissRight ? mViewWidth : -mViewWidth).alpha(0) .setDuration(mAnimationTime).setListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { performDismiss(downView, downPosition); } }); } else { // cancel mDownView.animate().translationX(0).alpha(1).setDuration(mAnimationTime).setListener(null); } mVelocityTracker.recycle(); mVelocityTracker = null; mDownX = 0; mDownY = 0; mDownView = null; mDownPosition = ListView.INVALID_POSITION; mSwiping = false; } break; } case MotionEvent.ACTION_MOVE: { if (mVelocityTracker == null || mPaused) { break; } mVelocityTracker.addMovement(motionEvent); float deltaX = motionEvent.getRawX() - mDownX; float deltaY = motionEvent.getRawY() - mDownY; if (mIsVertical) { if (Math.abs(deltaY) > mSlop && Math.abs(deltaX) < Math.abs(deltaY) / 2) { mSwiping = true; mSwipingSlop = (deltaY > 0 ? mSlop : -mSlop); mRecyclerView.requestDisallowInterceptTouchEvent(true); // Cancel ListView's touch (un-highlighting the item) MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); mRecyclerView.onTouchEvent(cancelEvent); cancelEvent.recycle(); } if (mSwiping) { mDownView.setTranslationY(deltaY - mSwipingSlop); mDownView.setAlpha(Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaY) / mViewWidth))); return true; } } else { if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2) { mSwiping = true; mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop); mRecyclerView.requestDisallowInterceptTouchEvent(true); // Cancel ListView's touch (un-highlighting the item) MotionEvent cancelEvent = MotionEvent.obtain(motionEvent); cancelEvent.setAction(MotionEvent.ACTION_CANCEL | (motionEvent.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); mRecyclerView.onTouchEvent(cancelEvent); cancelEvent.recycle(); } if (mSwiping) { mDownView.setTranslationX(deltaX - mSwipingSlop); mDownView.setAlpha(Math.max(0f, Math.min(1f, 1f - 2f * Math.abs(deltaX) / mViewWidth))); return true; } } break; } } return false; }
From source file:org.mozilla.focus.widget.InlineAutocompleteEditText.java
@Override public boolean onTouchEvent(MotionEvent event) { if (android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.M && event.getActionMasked() == MotionEvent.ACTION_UP) { // Android 6 occasionally throws a NullPointerException inside Editor.onTouchEvent() // for ACTION_UP when attempting to display (uninitialised) text handles. The Editor // and TextView IME interactions are quite complex, so I don't know how to properly // work around this issue, but we can at least catch the NPE to prevent crashing // the whole app. // (Editor tries to make both selection handles visible, but in certain cases they haven't // been initialised yet, causing the NPE. It doesn't bother to check the selection handle // state, and making some other calls to ensure the handles exist doesn't seem like a // clean solution either since I don't understand most of the selection logic. This implementation // only seems to exist in Android 6, both Android 5 and 7 have different implementations.) try {//from w w w . j a v a2 s . c om return super.onTouchEvent(event); } catch (NullPointerException ignored) { // Ignore this (see above) - since we're now in an unknown state let's clear all selection // (which is still better than an arbitrary crash that we can't control): clearFocus(); return true; } } else { return super.onTouchEvent(event); } }
From source file:org.telegram.ui.Components.Switch.java
@Override public boolean onTouchEvent(MotionEvent ev) { mVelocityTracker.addMovement(ev);// w w w. j a va2 s. co m final int action = ev.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); if (isEnabled() && hitThumb(x, y)) { mTouchMode = TOUCH_MODE_DOWN; mTouchX = x; mTouchY = y; } break; } case MotionEvent.ACTION_MOVE: { switch (mTouchMode) { case TOUCH_MODE_IDLE: break; case TOUCH_MODE_DOWN: { final float x = ev.getX(); final float y = ev.getY(); if (Math.abs(x - mTouchX) > mTouchSlop || Math.abs(y - mTouchY) > mTouchSlop) { mTouchMode = TOUCH_MODE_DRAGGING; getParent().requestDisallowInterceptTouchEvent(true); mTouchX = x; mTouchY = y; return true; } break; } case TOUCH_MODE_DRAGGING: { final float x = ev.getX(); final int thumbScrollRange = getThumbScrollRange(); final float thumbScrollOffset = x - mTouchX; float dPos; if (thumbScrollRange != 0) { dPos = thumbScrollOffset / thumbScrollRange; } else { dPos = thumbScrollOffset > 0 ? 1 : -1; } if (LocaleController.isRTL) { dPos = -dPos; } final float newPos = constrain(thumbPosition + dPos, 0, 1); if (newPos != thumbPosition) { mTouchX = x; setThumbPosition(newPos); } return true; } } break; } case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: { if (mTouchMode == TOUCH_MODE_DRAGGING) { stopDrag(ev); super.onTouchEvent(ev); return true; } mTouchMode = TOUCH_MODE_IDLE; mVelocityTracker.clear(); break; } } return super.onTouchEvent(ev); }
From source file:com.android.messaging.ui.conversationlist.ConversationListSwipeHelper.java
@Override public boolean onInterceptTouchEvent(final RecyclerView recyclerView, final MotionEvent event) { if (event.getPointerCount() > 1) { // Ignore subsequent pointers. return false; }// w w w. j a v a 2 s .c om // We are not yet tracking a swipe gesture. Begin detection by spying on // touch events bubbling down to our children. final int action = event.getActionMasked(); switch (action) { case MotionEvent.ACTION_DOWN: if (!hasGestureSwipeTarget()) { onGestureStart(); mVelocityTracker.addMovement(event); mInitialX = event.getX(); mInitialY = event.getY(); final View viewAtPoint = mRecyclerView.findChildViewUnder(mInitialX, mInitialY); final ConversationListItemView child = (ConversationListItemView) viewAtPoint; if (viewAtPoint instanceof ConversationListItemView && child != null && child.isSwipeAnimatable()) { // Begin detecting swipe on the target for the rest of the gesture. mListItemView = child; if (mListItemView.isAnimating()) { mListItemView = null; } } else { mListItemView = null; } } break; case MotionEvent.ACTION_MOVE: if (hasValidGestureSwipeTarget()) { mVelocityTracker.addMovement(event); final int historicalCount = event.getHistorySize(); // First consume the historical events, then consume the current ones. for (int i = 0; i < historicalCount + 1; i++) { float currX; float currY; if (i < historicalCount) { currX = event.getHistoricalX(i); currY = event.getHistoricalY(i); } else { currX = event.getX(); currY = event.getY(); } final float deltaX = currX - mInitialX; final float deltaY = currY - mInitialY; final float absDeltaX = Math.abs(deltaX); final float absDeltaY = Math.abs(deltaY); if (!mIsSwiping && absDeltaY > mTouchSlop && absDeltaY > (ERROR_FACTOR_MULTIPLIER * absDeltaX)) { // Stop detecting swipe for the remainder of this gesture. onGestureEnd(); return false; } if (absDeltaX > mTouchSlop) { // Swipe detected. Return true so we can handle the gesture in // onTouchEvent. mIsSwiping = true; // We don't want to suddenly jump the slop distance. mInitialX = event.getX(); mInitialY = event.getY(); onSwipeGestureStart(mListItemView); return true; } } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (hasGestureSwipeTarget()) { onGestureEnd(); } break; } // Start intercepting touch events from children if we detect a swipe. return mIsSwiping; }
From source file:edu.mit.mobile.android.livingpostcards.CameraActivity.java
@Override public boolean onTouch(View v, MotionEvent event) { switch (v.getId()) { case R.id.capture: switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: mHandler.sendEmptyMessageDelayed(MSG_START_AUTOFOCUS, 500); break; case MotionEvent.ACTION_UP: mHandler.removeMessages(MSG_START_AUTOFOCUS); break; }/*from www . ja va 2 s . c o m*/ return false; default: return false; } }
From source file:ch.tutti.android.bottomsheet.ResolverDrawerLayout.java
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { final int action = ev.getActionMasked(); if (canChildScrollUp()) { // Fail fast if we're not in a state where a swipe is possible return super.onInterceptTouchEvent(ev); }//from w ww .j a v a 2 s . c o m if (action == MotionEvent.ACTION_DOWN) { mVelocityTracker.clear(); } mVelocityTracker.addMovement(ev); switch (action) { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); mInitialTouchX = x; mInitialTouchY = mLastTouchY = y; mOpenOnClick = isListChildUnderClipped(x, y) && mCollapsibleHeight > 0; } break; case MotionEvent.ACTION_MOVE: { final float x = ev.getX(); final float y = ev.getY(); final float dy = y - mInitialTouchY; boolean isSlidingUp = Math.abs(dy) > mTouchSlop && findChildUnder(x, y) != null && mCollapseOffset > 0; boolean isSlidingDown = mCollapseOffset == 0 && dy > mTouchSlop; if (isSlidingUp || isSlidingDown) { mActivePointerId = ev.getPointerId(0); mIsDragging = true; mLastTouchY = Math.max(mLastTouchY - mTouchSlop, Math.min(mLastTouchY + dy, mLastTouchY + mTouchSlop)); } } break; case MotionEvent.ACTION_POINTER_UP: { onSecondaryPointerUp(ev); } break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { resetTouch(); } break; } if (mIsDragging) { mScroller.abortAnimation(); } return mIsDragging || mOpenOnClick; }
From source file:com.androidinspain.deskclock.alarms.AlarmActivity.java
@Override public boolean onTouch(View view, MotionEvent event) { if (mAlarmHandled) { LOGGER.v("onTouch ignored: %s", event); return false; }//from w w w . j a va 2s .c o m final int action = event.getActionMasked(); if (action == MotionEvent.ACTION_DOWN) { LOGGER.v("onTouch started: %s", event); // Track the pointer that initiated the touch sequence. mInitialPointerIndex = event.getPointerId(event.getActionIndex()); // Stop the pulse, allowing the last pulse to finish. mPulseAnimator.setRepeatCount(0); } else if (action == MotionEvent.ACTION_CANCEL) { LOGGER.v("onTouch canceled: %s", event); // Clear the pointer index. mInitialPointerIndex = MotionEvent.INVALID_POINTER_ID; // Reset everything. resetAnimations(); } final int actionIndex = event.getActionIndex(); if (mInitialPointerIndex == MotionEvent.INVALID_POINTER_ID || mInitialPointerIndex != event.getPointerId(actionIndex)) { // Ignore any pointers other than the initial one, bail early. return true; } final int[] contentLocation = { 0, 0 }; mContentView.getLocationOnScreen(contentLocation); final float x = event.getRawX() - contentLocation[0]; final float y = event.getRawY() - contentLocation[1]; final int alarmLeft = mAlarmButton.getLeft() + mAlarmButton.getPaddingLeft(); final int alarmRight = mAlarmButton.getRight() - mAlarmButton.getPaddingRight(); final float snoozeFraction, dismissFraction; if (mContentView.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) { snoozeFraction = getFraction(alarmRight, mSnoozeButton.getLeft(), x); dismissFraction = getFraction(alarmLeft, mDismissButton.getRight(), x); } else { snoozeFraction = getFraction(alarmLeft, mSnoozeButton.getRight(), x); dismissFraction = getFraction(alarmRight, mDismissButton.getLeft(), x); } setAnimatedFractions(snoozeFraction, dismissFraction); if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_POINTER_UP) { LOGGER.v("onTouch ended: %s", event); mInitialPointerIndex = MotionEvent.INVALID_POINTER_ID; if (snoozeFraction == 1.0f) { snooze(); } else if (dismissFraction == 1.0f) { dismiss(); } else { if (snoozeFraction > 0.0f || dismissFraction > 0.0f) { // Animate back to the initial state. AnimatorUtils.reverse(mAlarmAnimator, mSnoozeAnimator, mDismissAnimator); } else if (mAlarmButton.getTop() <= y && y <= mAlarmButton.getBottom()) { // User touched the alarm button, hint the dismiss action. hintDismiss(); } // Restart the pulse. mPulseAnimator.setRepeatCount(ValueAnimator.INFINITE); if (!mPulseAnimator.isStarted()) { mPulseAnimator.start(); } } } return true; }
From source file:ti.modules.titanium.ui.widget.TiUIEditText.java
/** * Called when a touch down/move/up event has been received. * @param event Provides information about the touch event. * @return Returns true if the touch event was consumed by this view. Returns false if not. *///from w ww .j a v a 2 s . c o m @Override public boolean onTouchEvent(MotionEvent event) { // Validate argument. if (event == null) { return false; } // Let the base class handle the event if touch or nested-scrolling is disabled. if (!isEnabled() || !isNestedScrollingEnabled()) { return super.onTouchEvent(event); } // Handle nested touch input and scroll handling. boolean wasHandled = false; switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: { // Determine if the EditText can be scrolled vertically or horizontally. // Note: There is a bug in EditText where canScrollHorizontally() will return // true when it's not scrollable for "center" or "right" aligned text. boolean isVertical = ((getInputType() & EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE) != 0); boolean isScrollable; if (isVertical) { isScrollable = canScrollVertically(1) || canScrollVertically(-1); } else { isScrollable = canScrollHorizontally(1) || canScrollHorizontally(-1); } // Start nested scrolling if the EditText is scrollable. this.isDragging = false; if (isScrollable) { if (isVertical) { this.scrollAxisDirection = ViewCompat.SCROLL_AXIS_VERTICAL; } else { this.scrollAxisDirection = ViewCompat.SCROLL_AXIS_HORIZONTAL; } this.startRawTouchX = (int) event.getRawX(); this.startRawTouchY = (int) event.getRawY(); this.lastRawTouchX = this.startRawTouchX; this.lastRawTouchY = this.startRawTouchY; boolean wasStarted = startNestedScroll(this.scrollAxisDirection); if (!wasStarted) { this.scrollAxisDirection = ViewCompat.SCROLL_AXIS_NONE; } } // Let the base class handle the touch "down" event. wasHandled = super.onTouchEvent(event); break; } case MotionEvent.ACTION_MOVE: { // Handle nested scrolling, if enabled. if (this.scrollAxisDirection != ViewCompat.SCROLL_AXIS_NONE) { // Determine if the touch point has moved far enough to be considered a drag event. // Note: Touch down/up events within this min distance are considered taps/clicks. boolean isVertical = (this.scrollAxisDirection == ViewCompat.SCROLL_AXIS_VERTICAL); if (!this.isDragging) { int dragDistance; if (isVertical) { dragDistance = this.startRawTouchY - (int) event.getRawY(); } else { dragDistance = this.startRawTouchX - (int) event.getRawX(); } if (Math.abs(dragDistance) > this.minDragStartDistance) { this.isDragging = true; } } // Check if we need to scroll the parent, if currently dragging. if (this.isDragging) { // Determine scroll direction, distance, and if EditText has hit scroll limit. computeScroll(); int deltaX = this.lastRawTouchX - (int) event.getRawX(); int deltaY = this.lastRawTouchY - (int) event.getRawY(); int deltaValue = isVertical ? deltaY : deltaX; boolean isScrollEnabled; boolean canScrollFurther; if (isVertical) { isScrollEnabled = canScrollVertically(1) || canScrollVertically(-1); canScrollFurther = canScrollVertically(deltaValue); } else { isScrollEnabled = canScrollHorizontally(1) || canScrollHorizontally(-1); canScrollFurther = canScrollHorizontally(deltaValue); } // Request the parent to scroll if one of the following is true: // - EditText is not scrollable. (ie: All text fits within the box.) // - EditText is scrollabe, but cannot scroll any further in given direction. if (!isScrollEnabled || !canScrollFurther) { wasHandled = dispatchNestedPreScroll(deltaX, deltaY, null, null); wasHandled |= dispatchNestedScroll(0, 0, deltaX, deltaY, null); } // Cancel EditText's long-press timer if parent was scrolled. // Note: EditText will move with the user's finger while scrolling the parent // in this case and we don't want it to trigger a long-press text selection. if (wasHandled) { cancelLongPress(); } } // Store the last received touch point in screen coordinates. // This is needed to calculate nested scroll distances. this.lastRawTouchX = (int) event.getRawX(); this.lastRawTouchY = (int) event.getRawY(); } // Let the EditText handle the event if the parent wasn't scrolled via the above. if (!wasHandled) { wasHandled = super.onTouchEvent(event); } break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { // Handle the touch release event. wasHandled = super.onTouchEvent(event); // Stop nested-scrolling if active. this.isDragging = false; if (this.scrollAxisDirection != ViewCompat.SCROLL_AXIS_NONE) { stopNestedScroll(); this.scrollAxisDirection = ViewCompat.SCROLL_AXIS_NONE; } break; } default: { // Let the base class handle all other events, such as multi-touch. wasHandled = super.onTouchEvent(event); break; } } return wasHandled; }
From source file:ch.tutti.android.bottomsheet.ResolverDrawerLayout.java
@Override public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getActionMasked(); if (canChildScrollUp()) { // Fail fast if we're not in a state where a swipe is possible return super.onTouchEvent(ev); }/*from w w w . j a va 2s . c o m*/ mVelocityTracker.addMovement(ev); boolean handled = false; switch (action) { case MotionEvent.ACTION_DOWN: { final float x = ev.getX(); final float y = ev.getY(); mInitialTouchX = x; mInitialTouchY = mLastTouchY = y; mActivePointerId = ev.getPointerId(0); if (findChildUnder(mInitialTouchX, mInitialTouchY) == null && mClickOutsideListener != null) { mIsDragging = handled = true; } handled |= mCollapsibleHeight > 0; mScroller.abortAnimation(); } break; case MotionEvent.ACTION_MOVE: { int index = ev.findPointerIndex(mActivePointerId); if (index < 0) { Log.e(TAG, "Bad pointer id " + mActivePointerId + ", resetting"); index = 0; mActivePointerId = ev.getPointerId(0); mInitialTouchX = ev.getX(); mInitialTouchY = mLastTouchY = ev.getY(); } final float x = ev.getX(index); final float y = ev.getY(index); if (!mIsDragging) { final float dy = y - mInitialTouchY; if (Math.abs(dy) > mTouchSlop && findChildUnder(x, y) != null) { handled = mIsDragging = true; mLastTouchY = Math.max(mLastTouchY - mTouchSlop, Math.min(mLastTouchY + dy, mLastTouchY + mTouchSlop)); } } if (mIsDragging) { final float dy = y - mLastTouchY; performDrag(dy); } mLastTouchY = y; } break; case MotionEvent.ACTION_POINTER_DOWN: { final int pointerIndex = ev.getActionIndex(); final int pointerId = ev.getPointerId(pointerIndex); mActivePointerId = pointerId; mInitialTouchX = ev.getX(pointerIndex); mInitialTouchY = mLastTouchY = ev.getY(pointerIndex); } break; case MotionEvent.ACTION_POINTER_UP: { onSecondaryPointerUp(ev); } break; case MotionEvent.ACTION_UP: { mIsDragging = false; if (!mIsDragging && findChildUnder(mInitialTouchX, mInitialTouchY) == null && findChildUnder(ev.getX(), ev.getY()) == null) { if (mClickOutsideListener != null) { mClickOutsideListener.onClick(this); resetTouch(); return true; } } if (mOpenOnClick && Math.abs(ev.getX() - mInitialTouchX) < mTouchSlop && Math.abs(ev.getY() - mInitialTouchY) < mTouchSlop) { smoothScrollTo(0, 0); return true; } mVelocityTracker.computeCurrentVelocity(1000); final float yvel = mVelocityTracker.getYVelocity(mActivePointerId); if (Math.abs(yvel) > mMinFlingVelocity) { smoothScrollTo(yvel < 0 ? 0 : mCollapsibleHeight, yvel); } else { smoothScrollTo(mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0); } resetTouch(); } break; case MotionEvent.ACTION_CANCEL: { if (mIsDragging) { smoothScrollTo(mCollapseOffset < mCollapsibleHeight / 2 ? 0 : mCollapsibleHeight, 0); } resetTouch(); return true; } } return handled || (action == MotionEvent.ACTION_MOVE && mCollapseOffset > 0); }