private void reset() { if (mPrevEvent != null) { mPrevEvent.recycle(); mPrevEvent = null; } if (mCurrEvent != null) { mCurrEvent.recycle(); mCurrEvent = null; } mSloppyGesture = false; mGestureInProgress = false; }
public void onDragOver(DragObject d) { final DragView dragView = d.dragView; final int scrollOffset = mScrollView.getScrollY(); final float[] r = getDragViewVisualCenter(d.x, d.y, d.xOffset, d.yOffset, dragView, null); r[0] -= getPaddingLeft(); r[1] -= getPaddingTop(); final long downTime = SystemClock.uptimeMillis(); final MotionEvent translatedEv = MotionEvent.obtain(downTime, downTime, MotionEvent.ACTION_MOVE, d.x, d.y, 0); if (!mAutoScrollHelper.isEnabled()) { mAutoScrollHelper.setEnabled(true); } final boolean handled = mAutoScrollHelper.onTouch(this, translatedEv); translatedEv.recycle(); if (handled) { mReorderAlarm.cancelAlarm(); } else { mTargetCell = mContent.findNearestArea((int) r[0], (int) r[1] + scrollOffset, 1, 1, mTargetCell); if (isLayoutRtl()) { mTargetCell[0] = mContent.getCountX() - mTargetCell[0] - 1; } if (mTargetCell[0] != mPreviousTargetCell[0] || mTargetCell[1] != mPreviousTargetCell[1]) { mReorderAlarm.cancelAlarm(); mReorderAlarm.setOnAlarmListener(mReorderAlarmListener); mReorderAlarm.setAlarm(REORDER_DELAY); mPreviousTargetCell[0] = mTargetCell[0]; mPreviousTargetCell[1] = mTargetCell[1]; } } }
private boolean processTouch(MotionEvent event) { // Checking if that event was already processed // (by onInterceptTouchEvent prior to onTouchEvent) long eventTime = event.getEventTime(); int action = event.getActionMasked(); if (lastTouchEventTime == eventTime && lastTouchEventAction == action) { return lastTouchEventResult; } lastTouchEventTime = eventTime; lastTouchEventAction = action; if (getCount() > 0) { // Fixing event's Y position due to performed translation MotionEvent eventCopy = MotionEvent.obtain(event); eventCopy.offsetLocation(0, getTranslationY()); lastTouchEventResult = gestureDetector.onTouchEvent(eventCopy); eventCopy.recycle(); } else { lastTouchEventResult = false; } if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { onUpOrCancel(); } return lastTouchEventResult; }
private void setContext(MotionEvent curr) { if (mCurrEvent != null) { mCurrEvent.recycle(); } mCurrEvent = MotionEvent.obtain(curr); mCurrLen = -1; mPrevLen = -1; mScaleFactor = -1; final MotionEvent prev = mPrevEvent; final float px0 = prev.getX(0); final float py0 = prev.getY(0); final float px1 = prev.getX(1); final float py1 = prev.getY(1); final float cx0 = curr.getX(0); final float cy0 = curr.getY(0); final float cx1 = curr.getX(1); final float cy1 = curr.getY(1); final float pvx = px1 - px0; final float pvy = py1 - py0; final float cvx = cx1 - cx0; final float cvy = cy1 - cy0; mPrevFingerDiffX = pvx; mPrevFingerDiffY = pvy; mCurrFingerDiffX = cvx; mCurrFingerDiffY = cvy; mTimeDelta = curr.getEventTime() - prev.getEventTime(); mCurrPressure = curr.getPressure(0) + curr.getPressure(1); mPrevPressure = prev.getPressure(0) + prev.getPressure(1); }
@Override public boolean onTouchEvent(MotionEvent event) { final int action = event.getAction(); final float x = event.getX(); final float y = event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: if (mCurrentDownEvent != null) { mCurrentDownEvent.recycle(); } mCurrentDownEvent = MotionEvent.obtain(event); mAlwaysInTapRegion = true; showPress(mCurrentDownEvent, true); break; case MotionEvent.ACTION_MOVE: if (mAlwaysInTapRegion) { final int deltaX = (int) (x - mCurrentDownEvent.getX()); final int deltaY = (int) (y - mCurrentDownEvent.getY()); int distance = (deltaX * deltaX) + (deltaY * deltaY); if (distance > mTouchSlopSquare) { mAlwaysInTapRegion = false; showPress(mCurrentDownEvent, false); } } break; case MotionEvent.ACTION_UP: showPress(mCurrentDownEvent, false); if (mAlwaysInTapRegion) { onTap(mCurrentDownEvent); } } return true; }
/** Force show keyboard */ public void showKeyboard() { this.requestFocus(); Context context = getContext(); if (Activity.class.isInstance(context)) { ((Activity) context) .getWindow() .setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); } // mImm.showSoftInput(this, InputMethodManager.SHOW_IMPLICIT | InputMethodManager.SHOW_FORCED); // mImm.toggleSoftInput(0, 0); // Trick used to create a fake touch event on the editText MotionEvent event = MotionEvent.obtain( 0, SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN | MotionEvent.ACTION_UP, this.getMeasuredWidth(), 0, 0); this.onTouchEvent(event); event.recycle(); }
public void init(MotionEvent e) { if (mInitialEvent != null) { mInitialEvent.recycle(); } mInitialEvent = MotionEvent.obtain(e); mIsPending = true; }
public void dispatchPointer(MotionEvent event) { if (mEngine != null) { mEngine.dispatchPointer(event); } else { event.recycle(); } }
private void clearTouchTarget() { mTouchTarget = null; if (mDownEvent != null) { mDownEvent.recycle(); mDownEvent = null; } }
public boolean dispatchTouchEvent(MotionEvent paramMotionEvent) { float f1 = paramMotionEvent.getRawX(); float f2 = paramMotionEvent.getRawY(); if ((this.f == null) && (this.a != null) && (this.a.getVisibility() == 0) && (this.b != null)) { this.b.getLocationOnScreen(this.g); if ((f1 >= this.g[0]) && (f1 < this.g[0] + this.b.getWidth()) && (f2 >= this.g[1]) && (f2 < this.g[1] + this.b.getHeight())) { this.f = this.a; } } if ((this.f == null) && (this.a != null) && (this.a.getVisibility() == 0)) { if ((this.d == null) || (this.d.getVisibility() != 0)) { break label269; } this.d.getLocationOnScreen(this.g); if (f2 >= this.g[1]) { this.f = this.a; } if (f2 >= this.g[1]) { this.f = this.a; } } int i = paramMotionEvent.getAction(); if (this.f != null) { localView = this.f; if (paramMotionEvent.getAction() == 3) { localView.dispatchTouchEvent(paramMotionEvent); if ((i == 3) || (i == 1)) { this.f = null; } } } label269: while (this.e == null) { for (;;) { View localView; return true; if ((this.c != null) && (this.c.getVisibility() == 0)) { this.c.getLocationOnScreen(this.g); break; } this.g[0] = 2147483647; this.g[1] = 2147483647; break; MotionEvent localMotionEvent = MotionEvent.obtain(paramMotionEvent); localMotionEvent.offsetLocation(getScrollX() - localView.getLeft(), getScrollY() - localView.getTop()); localView.dispatchTouchEvent(localMotionEvent); localMotionEvent.recycle(); } } this.e.a(i); return true; }
private void clear() { mActionDownInside.recycle(); mActionDownOutside.recycle(); mActionUpInside.recycle(); mActionUpOutside.recycle(); mActionMoveInside.recycle(); mActionMoveOutside.recycle(); mActionCancelInside.recycle(); mActionCancelOutside.recycle(); }
@Override public boolean dispatchTouchEvent(MotionEvent ev) { final float x = ev.getX(); final float y = ev.getY(); final int action = ev.getAction(); if (action == MotionEvent.ACTION_DOWN && mTouchTarget == null && mPinnedSection != null && isPinnedViewTouched(mPinnedSection.view, x, y)) { // create touch target // user touched pinned view mTouchTarget = mPinnedSection.view; mTouchPoint.x = x; mTouchPoint.y = y; // copy down event for eventually be used later mDownEvent = MotionEvent.obtain(ev); } if (mTouchTarget != null) { if (isPinnedViewTouched(mTouchTarget, x, y)) { // forward event to pinned view mTouchTarget.dispatchTouchEvent(ev); } if (action == MotionEvent.ACTION_UP) { // perform onClick on pinned view super.dispatchTouchEvent(ev); performPinnedItemClick(); clearTouchTarget(); } else if (action == MotionEvent.ACTION_CANCEL) { // cancel clearTouchTarget(); } else if (action == MotionEvent.ACTION_MOVE) { if (Math.abs(y - mTouchPoint.y) > mTouchSlop) { // cancel sequence on touch target MotionEvent event = MotionEvent.obtain(ev); event.setAction(MotionEvent.ACTION_CANCEL); mTouchTarget.dispatchTouchEvent(event); event.recycle(); // provide correct sequence to super class for further handling super.dispatchTouchEvent(mDownEvent); super.dispatchTouchEvent(ev); clearTouchTarget(); } } return true; } // call super if this was not our pinned view return super.dispatchTouchEvent(ev); }
private static void injectMotionEvent( @NonNull ViewGroup container, @NonNull MotionEvent base, int action) { long downTime = SystemClock.uptimeMillis(); long eventTime = SystemClock.uptimeMillis() + 100; MotionEvent event = MotionEvent.obtain( downTime, eventTime, action, base.getX(), base.getY(), 0.0f, 0.0f, 0, 1.0f, 1.0f, 0, 0); container.dispatchTouchEvent(event); event.recycle(); }
private void removeOneComponent(GLView component) { if (mMotionTarget == component) { long now = SystemClock.uptimeMillis(); MotionEvent cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0, 0, 0); dispatchTouchEvent(cancelEvent); cancelEvent.recycle(); } component.onDetachFromRoot(); component.mParent = null; }
@Override public boolean onTouchEvent(MotionEvent event) { final int action = event.getAction(); boolean handled = false; switch (action) { case MotionEvent.ACTION_DOWN: mCurrPercentage = 0; mDownEvent = MotionEvent.obtain(event); mPrevY = mDownEvent.getY(); break; case MotionEvent.ACTION_MOVE: if (mDownEvent != null && !mReturningToStart) { final float eventY = event.getY(); float yDiff = eventY - mDownEvent.getY(); if (yDiff > mTouchSlop) { // User velocity passed min velocity; trigger a refresh if (yDiff > mDistanceToTriggerSync) { // User movement passed distance; trigger a refresh startRefresh(); handled = true; break; } else { // Just track the user's movement setTriggerPercentage( mAccelerateInterpolator.getInterpolation(yDiff / mDistanceToTriggerSync)); float offsetTop = yDiff; if (mPrevY > eventY) { offsetTop = yDiff - mTouchSlop; } updateContentOffsetTop((int) (offsetTop)); if (mPrevY > eventY && (mTarget.getTop() < mTouchSlop)) { // If the user puts the view back at the top, we // don't need to. This shouldn't be considered // cancelling the gesture as the user can restart from the top. removeCallbacks(mCancel); } else { updatePositionTimeout(); } mPrevY = event.getY(); handled = true; } } } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if (mDownEvent != null) { mDownEvent.recycle(); mDownEvent = null; } break; } return handled; }
public boolean onTouchEvent(MotionEvent paramMotionEvent) { Object localObject = null; int i1 = t.a(paramMotionEvent); boolean bool2; if (q == null) { bool2 = a(paramMotionEvent, 1); if (!bool2) {} } for (;;) { Behavior localBehavior = ((d)q.getLayoutParams()).b(); boolean bool1; if (localBehavior != null) { bool1 = localBehavior.a(this, q, paramMotionEvent); } for (;;) { boolean bool3; if (q == null) { bool3 = bool1 | super.onTouchEvent(paramMotionEvent); paramMotionEvent = (MotionEvent)localObject; } do { if (((bool3) || (i1 != 0)) || (paramMotionEvent != null)) { paramMotionEvent.recycle(); } if ((i1 == 1) || (i1 == 3)) { e(); } return bool3; paramMotionEvent = (MotionEvent)localObject; bool3 = bool1; } while (!bool2); long l1; if (0 == 0) { l1 = SystemClock.uptimeMillis(); } for (paramMotionEvent = MotionEvent.obtain(l1, l1, 3, 0.0F, 0.0F, 0);; paramMotionEvent = null) { super.onTouchEvent(paramMotionEvent); bool3 = bool1; break; } bool1 = false; continue; bool1 = false; } bool2 = false; } }
protected void cancelContentTouch() { final long now = SystemClock.uptimeMillis(); final MotionEvent cancelEvent = MotionEvent.obtain(now, now, MotionEvent.ACTION_CANCEL, 0.0f, 0.0f, 0); final int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { getChildAt(i).dispatchTouchEvent(cancelEvent); } mContentContainer.dispatchTouchEvent(cancelEvent); cancelEvent.recycle(); }
@Override public boolean dispatchTouchEvent(MotionEvent ev) { if (((!mEnabled || !mInterceptTouch) && mMode == MODE_READY) || mAlwaysOpened) { return super.dispatchTouchEvent(ev); } if (mMode != MODE_FINISHED) { onTouchEvent(ev); if (mMode != MODE_SLIDE) { super.dispatchTouchEvent(ev); } else { MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent.setAction(MotionEvent.ACTION_CANCEL); super.dispatchTouchEvent(cancelEvent); cancelEvent.recycle(); } return true; } else { final int action = ev.getAction(); Rect rect = new Rect(); View menu = getChildAt(0); menu.getHitRect(rect); if (!rect.contains((int) ev.getX(), (int) ev.getY())) { if (action == MotionEvent.ACTION_UP && mCloseOnRelease && !mDispatchWhenOpened) { close(); mCloseOnRelease = false; } else { if (action == MotionEvent.ACTION_DOWN && !mDispatchWhenOpened) { mCloseOnRelease = true; } onTouchEvent(ev); } if (mDispatchWhenOpened) { super.dispatchTouchEvent(ev); } return true; } else { onTouchEvent(ev); ev.offsetLocation(-menu.getLeft(), -menu.getTop()); menu.dispatchTouchEvent(ev); return true; } } }
@Override public boolean dispatchTouchEvent(MotionEvent ev) { int action = ev.getAction() & MotionEvent.ACTION_MASK; if (action == MotionEvent.ACTION_DOWN) { mDownY = ev.getY(); mHeaderOwnsTouch = mHeader != null && mDownY <= mHeader.getHeight() + mHeaderOffset; } boolean handled; if (mHeaderOwnsTouch) { if (mHeader != null && Math.abs(mDownY - ev.getY()) <= mTouchSlop) { handled = mHeader.dispatchTouchEvent(ev); } else { if (mHeader != null) { MotionEvent cancelEvent = MotionEvent.obtain(ev); cancelEvent.setAction(MotionEvent.ACTION_CANCEL); mHeader.dispatchTouchEvent(cancelEvent); cancelEvent.recycle(); } MotionEvent downEvent = MotionEvent.obtain( ev.getDownTime(), ev.getEventTime(), ev.getAction(), ev.getX(), mDownY, ev.getMetaState()); downEvent.setAction(MotionEvent.ACTION_DOWN); handled = mList.dispatchTouchEvent(downEvent); downEvent.recycle(); mHeaderOwnsTouch = false; } } else { handled = mList.dispatchTouchEvent(ev); } return handled; }
public void startSelectionActionMode() { // Force the EditText to show the CAB (hacky!) MotionEvent event = MotionEvent.obtain( SystemClock.uptimeMillis(), SystemClock.uptimeMillis(), MotionEvent.ACTION_DOWN, 0, 0, 0); dispatchTouchEvent(event); event.recycle(); }
private void dispatchUiEvents(boolean calledFromHandler) { for (; ; ) { MotionEvent event; final int eventType; final int flags; synchronized (mLock) { DispatchEvent d = mUiDispatchEventQueue.dequeue(); if (d == null) { if (mUiDispatchScheduled) { mUiDispatchScheduled = false; if (!calledFromHandler) { mUiHandler.removeMessages(UiHandler.MSG_DISPATCH_UI_EVENTS); } } return; } event = d.mEvent; if (event != null && (d.mFlags & FLAG_WEBKIT_TRANSFORMED_EVENT) != 0) { event.scale(1.0f / d.mWebKitScale); event.offsetLocation(-d.mWebKitXOffset, -d.mWebKitYOffset); d.mFlags &= ~FLAG_WEBKIT_TRANSFORMED_EVENT; } eventType = d.mEventType; if (eventType == EVENT_TYPE_TOUCH) { event = mUiTouchStream.update(event); if (DEBUG && event == null && d.mEvent != null) { Log.d(TAG, "dispatchUiEvents: dropped event " + d.mEvent); } } flags = d.mFlags; if (event == d.mEvent) { d.mEvent = null; // retain ownership of event, don't recycle it yet } recycleDispatchEventLocked(d); if (eventType == EVENT_TYPE_CLICK) { scheduleHideTapHighlightLocked(); } } // Handle the event. if (event != null) { dispatchUiEvent(event, eventType, flags); event.recycle(); } } }
private void dispatchPointer(MotionEvent event) { if (event.isTouchEvent()) { synchronized (mLock) { if (event.getAction() == MotionEvent.ACTION_MOVE) { mPendingMove = event; } else { mPendingMove = null; } } Message msg = mCaller.obtainMessageO(MSG_TOUCH_EVENT, event); mCaller.sendMessage(msg); } else { event.recycle(); } }
public void computeScroll() { if (mDecelerationVelocity.x == 0.f && mDecelerationVelocity.y == 0.f) return; // There's no deceleration in progress final long currentTime = AnimationUtils.currentAnimationTimeMillis(); mDecelerationVelocity.x *= mChart.getDragDecelerationFrictionCoef(); mDecelerationVelocity.y *= mChart.getDragDecelerationFrictionCoef(); final float timeInterval = (float) (currentTime - mDecelerationLastTime) / 1000.f; float distanceX = mDecelerationVelocity.x * timeInterval; float distanceY = mDecelerationVelocity.y * timeInterval; mDecelerationCurrentPoint.x += distanceX; mDecelerationCurrentPoint.y += distanceY; MotionEvent event = MotionEvent.obtain( currentTime, currentTime, MotionEvent.ACTION_MOVE, mDecelerationCurrentPoint.x, mDecelerationCurrentPoint.y, 0); performDrag(event); event.recycle(); mMatrix = mChart.getViewPortHandler().refresh(mMatrix, mChart, false); mDecelerationLastTime = currentTime; if (Math.abs(mDecelerationVelocity.x) >= 0.01 || Math.abs(mDecelerationVelocity.y) >= 0.01) Utils.postInvalidateOnAnimation( mChart); // This causes computeScroll to fire, recommended for this by Google else { // Range might have changed, which means that Y-axis labels // could have changed in size, affecting Y-axis size. // So we need to recalculate offsets. mChart.calculateOffsets(); mChart.postInvalidate(); stopDeceleration(); } }
private void e() { int i1 = 0; if (q != null) { Behavior localBehavior = ((d)q.getLayoutParams()).b(); if (localBehavior != null) { long l1 = SystemClock.uptimeMillis(); MotionEvent localMotionEvent = MotionEvent.obtain(l1, l1, 3, 0.0F, 0.0F, 0); localBehavior.a(this, q, localMotionEvent); localMotionEvent.recycle(); } q = null; } int i2 = getChildCount(); while (i1 < i2) { ((d)getChildAt(i1).getLayoutParams()).f(); i1 += 1; } }
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { boolean intercept = false; if (mDoubleTapToSleepEnabled) { if (mService.getBarState() == StatusBarState.SHADE && ev.getY() < mStatusBarHeaderHeight) { if (DEBUG) Log.w(TAG, "logging double tap gesture"); mDoubleTapGesture.onTouchEvent(ev); } } final int h = getMeasuredHeight(); if (mDoubleTapToSleepLockScreen && mService.getBarState() == StatusBarState.KEYGUARD && (ev.getY() < (h / 3) || ev.getY() > (h - mStatusBarHeaderHeight))) { if (DEBUG) Log.w(TAG, "logging lock screen double tap gesture"); mDoubleTapGesture.onTouchEvent(ev); } if (mNotificationPanel.isFullyExpanded() && mStackScrollLayout.getVisibility() == View.VISIBLE && mService.getBarState() == StatusBarState.KEYGUARD && !mService.isBouncerShowing()) { intercept = mDragDownHelper.onInterceptTouchEvent(ev); // wake up on a touch down event, if dozing if (ev.getActionMasked() == MotionEvent.ACTION_DOWN) { mService.wakeUpIfDozing(ev.getEventTime(), ev); } } if (!intercept) { super.onInterceptTouchEvent(ev); } if (intercept) { MotionEvent cancellation = MotionEvent.obtain(ev); cancellation.setAction(MotionEvent.ACTION_CANCEL); mStackScrollLayout.onInterceptTouchEvent(cancellation); mNotificationPanel.onInterceptTouchEvent(cancellation); cancellation.recycle(); } return intercept; }
@Override public boolean onTouch(View v, MotionEvent event) { if (!callback.canSwipe()) return false; event.offsetLocation(translationX, 0); if (targetWidth < 2) targetWidth = view.getWidth(); switch (event.getActionMasked()) { case MotionEvent.ACTION_DOWN: { downX = event.getRawX(); velocityTracker = VelocityTracker.obtain(); velocityTracker.addMovement(event); return false; } case MotionEvent.ACTION_UP: { if (velocityTracker == null) break; velocityTracker.addMovement(event); velocityTracker.computeCurrentVelocity(1000); if (swiping) { view.animate() .translationX(0f) .setDuration(animTime) .setListener( new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { callback.onBound(canSwitch, swipingLeft); } }); } downX = 0; translationX = 0; swiping = false; velocityTracker.recycle(); velocityTracker = null; break; } case MotionEvent.ACTION_CANCEL: { if (velocityTracker == null) { break; } view.animate().translationX(0f).setDuration(animTime).setListener(null); downX = 0; translationX = 0; swiping = false; velocityTracker.recycle(); velocityTracker = null; break; } case MotionEvent.ACTION_MOVE: { if (velocityTracker == null) { break; } velocityTracker.addMovement(event); float deltaX = event.getRawX() - downX; if (Math.abs(deltaX) > slop) { swiping = true; swipingLeft = deltaX < 0; canSwitch = Math.abs(deltaX) >= ViewUnit.dp2px( view.getContext(), 48); // Can switch tabs when deltaX >= 48 to prevent misuse swipingSlop = (deltaX > 0 ? slop : -slop); view.getParent().requestDisallowInterceptTouchEvent(true); MotionEvent cancelEvent = MotionEvent.obtainNoHistory(event); cancelEvent.setAction( MotionEvent.ACTION_CANCEL | (event.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT)); view.onTouchEvent(cancelEvent); cancelEvent.recycle(); } if (swiping) { translationX = deltaX; view.setTranslationX(deltaX - swipingSlop); callback.onSwipe(); return true; } break; } } return false; }
/** * This function checks to see if we need to handle any sudden jumps in the pointer location that * could be due to a multi-touch being treated as a move by the firmware or hardware. Once a * sudden jump is detected, all subsequent move events are discarded until an UP is received. * * <p>When a sudden jump is detected, an UP event is simulated at the last position and when the * sudden moves subside, a DOWN event is simulated for the second key. * * @param me the motion event * @return true if the event was consumed, so that it doesn't continue to be handled by {@link * LatinKeyboardView}. */ private boolean handleSuddenJumping(MotionEvent me) { if (!mNeedsSuddenJumpingHack) return false; final int action = me.getAction(); final int x = (int) me.getX(); final int y = (int) me.getY(); boolean result = false; // Real multi-touch event? Stop looking for sudden jumps if (me.getPointerCount() > 1) { mDisableDisambiguation = true; } if (mDisableDisambiguation) { // If UP, reset the multi-touch flag if (action == MotionEvent.ACTION_UP) mDisableDisambiguation = false; return false; } switch (action) { case MotionEvent.ACTION_DOWN: // Reset the "session" mDroppingEvents = false; mDisableDisambiguation = false; break; case MotionEvent.ACTION_MOVE: // Is this a big jump? final int distanceSquare = (mLastX - x) * (mLastX - x) + (mLastY - y) * (mLastY - y); // Check the distance. if (distanceSquare > mJumpThresholdSquare) { // If we're not yet dropping events, start dropping and send an UP event if (!mDroppingEvents) { mDroppingEvents = true; // Send an up event MotionEvent translated = MotionEvent.obtain( me.getEventTime(), me.getEventTime(), MotionEvent.ACTION_UP, mLastX, mLastY, me.getMetaState()); mView.processMotionEvent(translated); translated.recycle(); } result = true; } else if (mDroppingEvents) { // If moves are small and we're already dropping events, continue dropping result = true; } break; case MotionEvent.ACTION_UP: if (mDroppingEvents) { // Send a down event first, as we dropped a bunch of sudden jumps and assume that // the user is releasing the touch on the second key. MotionEvent translated = MotionEvent.obtain( me.getEventTime(), me.getEventTime(), MotionEvent.ACTION_DOWN, x, y, me.getMetaState()); mView.processMotionEvent(translated); translated.recycle(); mDroppingEvents = false; // Let the up event get processed as well, result = false } break; } // Track the previous coordinate mLastX = x; mLastY = y; return result; }
@Override public boolean onTouch(View view, MotionEvent motionEvent) { if (mViewWidth < 2) { mViewWidth = mListView.getWidth(); } switch (motionEvent.getActionMasked()) { case MotionEvent.ACTION_DOWN: { if (mPaused) { return false; } if (mSwiping) { return true; } // 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 = mListView.getChildCount(); int headerCount = mListView.getHeaderViewsCount(); int footerCount = mListView.getFooterViewsCount(); int[] listViewCoords = new int[2]; mListView.getLocationOnScreen(listViewCoords); int x = (int) motionEvent.getRawX() - listViewCoords[0]; int y = (int) motionEvent.getRawY() - listViewCoords[1]; View child = null; for (int i = headerCount; i < (childCount - footerCount); i++) { child = mListView.getChildAt(i); child.getHitRect(rect); if (rect.contains(x, y)) { mDownView = child; break; } } if (mDownView != null) { mDownX = motionEvent.getRawX(); mDownY = motionEvent.getRawY(); mDownPosition = mListView.getPositionForView(mDownView); if (mDownPosition != ListView.INVALID_POSITION && mDownPosition < mListView.getAdapter().getCount()) { if (mListView.getAdapter().getItem(mDownPosition) instanceof Card) { if (mCallbacks.canDismiss( mDownPosition, (Card) mListView.getAdapter().getItem(mDownPosition))) { mVelocityTracker = VelocityTracker.obtain(); mVelocityTracker.addMovement(motionEvent); } else { mDownView = null; } } else { mDownView = null; } } else { mDownView = null; } } view.onTouchEvent(motionEvent); return true; // return false; } case MotionEvent.ACTION_UP: { if (mVelocityTracker == null) { break; } float deltaX = motionEvent.getRawX() - mDownX; mVelocityTracker.addMovement(motionEvent); mVelocityTracker.computeCurrentVelocity(1000); float velocityX = mVelocityTracker.getXVelocity(); float absVelocityX = Math.abs(velocityX); float absVelocityY = Math.abs(mVelocityTracker.getYVelocity()); boolean dismiss = false; boolean dismissRight = false; if (Math.abs(deltaX) > mViewWidth / swipeDistanceDivisor && 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 dismiss(mDownView, mDownPosition - mListView.getHeaderViewsCount(), dismissRight); } 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; if (mSwiping) { // To prevent onClick event with a fast swipe mSwiping = false; return true; } mSwiping = false; break; } case MotionEvent.ACTION_CANCEL: { if (mVelocityTracker == null) { break; } if (mDownView != null) { // 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; boolean movementAllowed = isSwipeMovementAllowed(deltaX); if (Math.abs(deltaX) > mSlop && Math.abs(deltaY) < Math.abs(deltaX) / 2 && movementAllowed) { mSwiping = true; mSwipingSlop = (deltaX > 0 ? mSlop : -mSlop); mListView.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)); mListView.onTouchEvent(cancelEvent); view.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; }
/** * Analyzes the given motion event and if applicable triggers the appropriate callbacks on the * {@link OnGestureListener} supplied. * * @param ev The current motion event. * @return true if the {@link OnGestureListener} consumed the event, else false. */ public boolean onTouchEvent(MotionEvent ev) { final int action = ev.getAction(); if (mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(ev); final boolean pointerUp = (action & MotionEventCompat.ACTION_MASK) == MotionEventCompat.ACTION_POINTER_UP; final int skipIndex = pointerUp ? MotionEventCompat.getActionIndex(ev) : -1; // Determine focal point float sumX = 0, sumY = 0; final int count = MotionEventCompat.getPointerCount(ev); for (int i = 0; i < count; i++) { if (skipIndex == i) continue; sumX += MotionEventCompat.getX(ev, i); sumY += MotionEventCompat.getY(ev, i); } final int div = pointerUp ? count - 1 : count; final float focusX = sumX / div; final float focusY = sumY / div; boolean handled = false; switch (action & MotionEventCompat.ACTION_MASK) { case MotionEventCompat.ACTION_POINTER_DOWN: mDownFocusX = mLastFocusX = focusX; mDownFocusY = mLastFocusY = focusY; // Cancel long press and taps cancelTaps(); break; case MotionEventCompat.ACTION_POINTER_UP: mDownFocusX = mLastFocusX = focusX; mDownFocusY = mLastFocusY = focusY; // Check the dot product of current velocities. // If the pointer that left was opposing another velocity vector, clear. mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); final int upIndex = MotionEventCompat.getActionIndex(ev); final int id1 = MotionEventCompat.getPointerId(ev, upIndex); final float x1 = VelocityTrackerCompat.getXVelocity(mVelocityTracker, id1); final float y1 = VelocityTrackerCompat.getYVelocity(mVelocityTracker, id1); for (int i = 0; i < count; i++) { if (i == upIndex) continue; final int id2 = MotionEventCompat.getPointerId(ev, i); final float x = x1 * VelocityTrackerCompat.getXVelocity(mVelocityTracker, id2); final float y = y1 * VelocityTrackerCompat.getYVelocity(mVelocityTracker, id2); final float dot = x + y; if (dot < 0) { mVelocityTracker.clear(); break; } } break; case MotionEvent.ACTION_DOWN: if (mDoubleTapListener != null) { boolean hadTapMessage = mHandler.hasMessages(TAP); if (hadTapMessage) mHandler.removeMessages(TAP); if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) { // This is a second tap mIsDoubleTapping = true; // Give a callback with the first tap of the double-tap handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); // Give a callback with down event of the double-tap handled |= mDoubleTapListener.onDoubleTapEvent(ev); } else { // This is a first tap mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); } } mDownFocusX = mLastFocusX = focusX; mDownFocusY = mLastFocusY = focusY; if (mCurrentDownEvent != null) { mCurrentDownEvent.recycle(); } mCurrentDownEvent = MotionEvent.obtain(ev); mAlwaysInTapRegion = true; mAlwaysInBiggerTapRegion = true; mStillDown = true; mInLongPress = false; if (mIsLongpressEnabled) { mHandler.removeMessages(LONG_PRESS); mHandler.sendEmptyMessageAtTime( LONG_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT + LONGPRESS_TIMEOUT); } mHandler.sendEmptyMessageAtTime( SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); handled |= mListener.onDown(ev); break; case MotionEvent.ACTION_MOVE: if (mInLongPress) { break; } final float scrollX = mLastFocusX - focusX; final float scrollY = mLastFocusY - focusY; if (mIsDoubleTapping) { // Give the move events of the double-tap handled |= mDoubleTapListener.onDoubleTapEvent(ev); } else if (mAlwaysInTapRegion) { final int deltaX = (int) (focusX - mDownFocusX); final int deltaY = (int) (focusY - mDownFocusY); int distance = (deltaX * deltaX) + (deltaY * deltaY); if (distance > mTouchSlopSquare) { handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); mLastFocusX = focusX; mLastFocusY = focusY; mAlwaysInTapRegion = false; mHandler.removeMessages(TAP); mHandler.removeMessages(SHOW_PRESS); mHandler.removeMessages(LONG_PRESS); } if (distance > mTouchSlopSquare) { mAlwaysInBiggerTapRegion = false; } } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) { handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); mLastFocusX = focusX; mLastFocusY = focusY; } break; case MotionEvent.ACTION_UP: mStillDown = false; MotionEvent currentUpEvent = MotionEvent.obtain(ev); if (mIsDoubleTapping) { // Finally, give the up event of the double-tap handled |= mDoubleTapListener.onDoubleTapEvent(ev); } else if (mInLongPress) { mHandler.removeMessages(TAP); mInLongPress = false; } else if (mAlwaysInTapRegion) { handled = mListener.onSingleTapUp(ev); } else { // A fling must travel the minimum tap distance final VelocityTracker velocityTracker = mVelocityTracker; final int pointerId = MotionEventCompat.getPointerId(ev, 0); velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); final float velocityY = VelocityTrackerCompat.getYVelocity(velocityTracker, pointerId); final float velocityX = VelocityTrackerCompat.getXVelocity(velocityTracker, pointerId); if ((Math.abs(velocityY) > mMinimumFlingVelocity) || (Math.abs(velocityX) > mMinimumFlingVelocity)) { handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY); } } if (mPreviousUpEvent != null) { mPreviousUpEvent.recycle(); } // Hold the event we obtained above - listeners may have changed the original. mPreviousUpEvent = currentUpEvent; if (mVelocityTracker != null) { // This may have been cleared when we called out to the // application above. mVelocityTracker.recycle(); mVelocityTracker = null; } mIsDoubleTapping = false; mHandler.removeMessages(SHOW_PRESS); mHandler.removeMessages(LONG_PRESS); break; case MotionEvent.ACTION_CANCEL: cancel(); break; } return handled; }
public boolean onTouchEvent(MotionEvent event) { final int action = event.getAction(); boolean handled = true; if (!mGestureInProgress) { switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_POINTER_DOWN: { // We have a new multi-finger gesture // as orientation can change, query the metrics in touch down DisplayMetrics metrics = mContext.getResources().getDisplayMetrics(); mRightSlopEdge = metrics.widthPixels - mEdgeSlop; mBottomSlopEdge = metrics.heightPixels - mEdgeSlop; // Be paranoid in case we missed an event reset(); mPrevEvent = MotionEvent.obtain(event); mTimeDelta = 0; 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. final float edgeSlop = mEdgeSlop; final float rightSlop = mRightSlopEdge; final float bottomSlop = mBottomSlopEdge; final float x0 = event.getRawX(); final float y0 = event.getRawY(); final float x1 = getRawX(event, 1); final float y1 = getRawY(event, 1); boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop; boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop; if (p0sloppy && p1sloppy) { mSloppyGesture = true; } else if (p0sloppy) { mSloppyGesture = true; } else if (p1sloppy) { mSloppyGesture = true; } else { mGestureInProgress = mListener.onScaleBegin(this); } } break; case MotionEvent.ACTION_MOVE: if (mSloppyGesture) { // Log.d(TAG, "scale gesture move mSloppyGesture"); // Initiate sloppy gestures if we've moved outside of the // slop area. final float edgeSlop = mEdgeSlop; final float rightSlop = mRightSlopEdge; final float bottomSlop = mBottomSlopEdge; final float x0 = event.getRawX(); final float y0 = event.getRawY(); final float x1 = getRawX(event, 1); final float y1 = getRawY(event, 1); boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop || x0 > rightSlop || y0 > bottomSlop; boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop || x1 > rightSlop || y1 > bottomSlop; if (p0sloppy && p1sloppy) { } else if (p0sloppy) { } else if (p1sloppy) { } else { mSloppyGesture = false; mGestureInProgress = mListener.onScaleBegin(this); } } break; case MotionEvent.ACTION_POINTER_UP: if (mSloppyGesture) {} break; } } else { // Transform gesture in progress - attempt to handle it switch (action & MotionEvent.ACTION_MASK) { case MotionEvent.ACTION_POINTER_UP: // Gesture ended setContext(event); if (!mSloppyGesture) { mListener.onScaleEnd(this); } reset(); break; case MotionEvent.ACTION_CANCEL: if (!mSloppyGesture) { mListener.onScaleEnd(this); } reset(); break; case MotionEvent.ACTION_MOVE: // Log.d(TAG, "scale gesture move"); setContext(event); mMiddleX = (event.getX(0) + event.getX(1)) / 2; mMiddleY = (event.getY(0) + event.getY(1)) / 2; // 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) { final boolean updatePrevious = mListener.onScale(this, mMiddleX, mMiddleY); if (updatePrevious) { mPrevEvent.recycle(); mPrevEvent = MotionEvent.obtain(event); } } break; } } return handled; }