android.view.MotionEvent#getDownTime ( )源码实例Demo

下面列出了android.view.MotionEvent#getDownTime ( ) 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。

源代码1 项目: Zom-Android-XMPP   文件: PZSImageView.java
/**
 * check user double tapped this view.. or not.
 * @param ev current motion event in a @{link MotionEvent}
 * @return {@code true} if user double tapped this view.
 */
protected boolean isDoubleTap(MotionEvent ev){
	//if old pointer is tapped?
	if( ev.getPointerCount() > 1){
		//if there are more than one pointer... reset
		mLastTocuhDownTime = 0;
		return false;
	}

	long downTime = ev.getDownTime();
	long diff = downTime - mLastTocuhDownTime;
	mLastTocuhDownTime = downTime;

	return diff < DOUBLE_TAP_MARGIN_TIME;
}
 
源代码2 项目: FirefoxReality   文件: ServoPanZoomController.java
private boolean handleMotionEvent(MotionEvent event) {
    if (!mAttached) {
        mQueuedEvents.add(new Pair(EVENT_SOURCE_MOTION, event));
        return false;
    }

    if (event.getPointerCount() <= 0) {
        return false;
    }

    final int action = event.getActionMasked();

    if (action == MotionEvent.ACTION_DOWN) {
        mLastDownTime = event.getDownTime();
    } else if (mLastDownTime != event.getDownTime()) {
        return false;
    }

    final MotionEvent.PointerCoords coords = new MotionEvent.PointerCoords();
    event.getPointerCoords(0, coords);

    if (action == MotionEvent.ACTION_UP) {
        mSession.click((int) coords.x, (int) coords.y);
    }

    return true;
}
 
@Override
public boolean onTouch(View view, MotionEvent e) {
	if (getNavVisibility() && e.getAction() == MotionEvent.ACTION_UP && downTime != e.getDownTime()) {
		toggleNavVisibility(); // this also removes navHider callbacks.
	} else if (!getNavVisibility() && e.getAction() == MotionEvent.ACTION_DOWN) {
		downTime = e.getDownTime();
		toggleNavVisibility(); // this also removes navHider callbacks.
		if (videoFragment != null && videoFragment.isPlaying()) {
			handler.postDelayed(navHider, NAV_HIDE_DELAY);
		}
	}
	return false;
}
 
源代码4 项目: android-chromium   文件: LongPressDetector.java
void cancelLongPressIfNeeded(Iterator<MotionEvent> pendingEvents) {
    if (mCurrentDownEvent == null)
        return;
    long currentDownTime = mCurrentDownEvent.getDownTime();
    while (pendingEvents.hasNext()) {
        MotionEvent pending = pendingEvents.next();
        if (pending.getDownTime() != currentDownTime) {
            break;
        }
        cancelLongPressIfNeeded(pending);
    }
}
 
private MotionEvent transformEvent(MotionEvent e, int headerPosition) {
    if (headerPosition == MATCHED_STICKIED_HEADER) {
        return e;
    }

    long downTime = e.getDownTime();
    long eventTime = e.getEventTime();
    int action = e.getAction();
    int pointerCount = e.getPointerCount();
    int[] pointerIds = getPointerIds(e);
    MotionEvent.PointerCoords[] pointerCoords = getPointerCoords(e);
    int metaState = e.getMetaState();
    float xPrecision = e.getXPrecision();
    float yPrecision = e.getYPrecision();
    int deviceId = e.getDeviceId();
    int edgeFlags = e.getEdgeFlags();
    int source = e.getSource();
    int flags = e.getFlags();

    View headerHolder = getChildAt(headerPosition);
    for (int i = 0; i < pointerCount;i++) {
        pointerCoords[i].y -= headerHolder.getTop();
    }
    MotionEvent n = MotionEvent.obtain(downTime, eventTime, action,
            pointerCount, pointerIds, pointerCoords, metaState, xPrecision,
            yPrecision, deviceId, edgeFlags, source, flags);
    return n;
}
 
@Override
public void perform(UiController uiController, View view) {
  float[] precision = precisionDescriber.describePrecision();
  float[] start = this.start.calculateCoordinates(view);
  float[] end = this.end.calculateCoordinates(view);
  float[][] steps = interpolate(start, end, STEPS);
  int delayBetweenMovements = DURATION / steps.length;
  // Down
  MotionEvent downEvent = MotionEvents.sendDown(uiController, start, precision).down;
  try {
    for (int i = 0; i < steps.length; i++) {
      // Wait
      long desiredTime = downEvent.getDownTime() + (long) (delayBetweenMovements * i);
      long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
      if (timeUntilDesired > 10L) {
        uiController.loopMainThreadForAtLeast(timeUntilDesired);
      }
      // Move
      if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) {
        MotionEvents.sendCancel(uiController, downEvent);
        throw new RuntimeException("Cannot drag: failed to send a move event.");
      }
    }
    int duration = ViewConfiguration.getPressedStateDuration();
    if (duration > 0) {
      uiController.loopMainThreadForAtLeast((long) duration);
    }
  } finally {
    downEvent.recycle();
  }
}
 
private MotionEvent transformEvent(MotionEvent e, int headerPosition) {
    if (headerPosition == MATCHED_STICKIED_HEADER) {
        return e;
    }

    long downTime = e.getDownTime();
    long eventTime = e.getEventTime();
    int action = e.getAction();
    int pointerCount = e.getPointerCount();
    int[] pointerIds = getPointerIds(e);
    MotionEvent.PointerCoords[] pointerCoords = getPointerCoords(e);
    int metaState = e.getMetaState();
    float xPrecision = e.getXPrecision();
    float yPrecision = e.getYPrecision();
    int deviceId = e.getDeviceId();
    int edgeFlags = e.getEdgeFlags();
    int source = e.getSource();
    int flags = e.getFlags();

    View headerHolder = getChildAt(headerPosition);
    for (int i = 0; i < pointerCount;i++) {
        pointerCoords[i].y -= headerHolder.getTop();
    }
    MotionEvent n = MotionEvent.obtain(downTime, eventTime, action,
            pointerCount, pointerIds, pointerCoords, metaState, xPrecision,
            yPrecision, deviceId, edgeFlags, source, flags);
    return n;
}
 
源代码8 项目: SimpleRatingBar   文件: RatingBarUtils.java
static boolean isClickEvent(float startX, float startY, MotionEvent event) {
    float duration = event.getEventTime() - event.getDownTime();
    if (duration > MAX_CLICK_DURATION) {
        return false;
    }

    float differenceX = Math.abs(startX - event.getX());
    float differenceY = Math.abs(startY - event.getY());
    return !(differenceX > MAX_CLICK_DISTANCE || differenceY > MAX_CLICK_DISTANCE);
}
 
源代码9 项目: o2oa   文件: StickyGridHeadersGridView.java
private MotionEvent transformEvent(MotionEvent e, int headerPosition) {
    if (headerPosition == MATCHED_STICKIED_HEADER) {
        return e;
    }

    long downTime = e.getDownTime();
    long eventTime = e.getEventTime();
    int action = e.getAction();
    int pointerCount = e.getPointerCount();
    int[] pointerIds = getPointerIds(e);
    MotionEvent.PointerCoords[] pointerCoords = getPointerCoords(e);
    int metaState = e.getMetaState();
    float xPrecision = e.getXPrecision();
    float yPrecision = e.getYPrecision();
    int deviceId = e.getDeviceId();
    int edgeFlags = e.getEdgeFlags();
    int source = e.getSource();
    int flags = e.getFlags();

    View headerHolder = getChildAt(headerPosition);
    for (int i = 0; i < pointerCount;i++) {
        pointerCoords[i].y -= headerHolder.getTop();
    }
    MotionEvent n = MotionEvent.obtain(downTime, eventTime, action,
            pointerCount, pointerIds, pointerCoords, metaState, xPrecision,
            yPrecision, deviceId, edgeFlags, source, flags);
    return n;
}
 
源代码10 项目: brailleback   文件: MotionEventCompatUtils.java
/**
 * Converts a hover {@link MotionEvent} to touch event by changing its
 * action and source. Returns an modified clone of the original event.
 * <p>
 * The following types are affected:
 * <ul>
 * <li>{@link MotionEventCompatUtils#ACTION_HOVER_ENTER}
 * <li>{@link MotionEventCompatUtils#ACTION_HOVER_MOVE}
 * <li>{@link MotionEventCompatUtils#ACTION_HOVER_EXIT}
 * </ul>
 * 
 * @param hoverEvent The hover event to convert.
 * @return a touch event
 */
public static MotionEvent convertHoverToTouch(MotionEvent hoverEvent) {
    final MotionEvent touchEvent = MotionEvent.obtain(hoverEvent);

    long downTime = sPreviousDownTime;

    switch (touchEvent.getAction()) {
        case MotionEventCompatUtils.ACTION_HOVER_ENTER:
            touchEvent.setAction(MotionEvent.ACTION_DOWN);
            sPreviousDownTime = SystemClock.uptimeMillis();
            downTime = sPreviousDownTime;
            break;
        case MotionEventCompatUtils.ACTION_HOVER_MOVE:
            touchEvent.setAction(MotionEvent.ACTION_MOVE);
            break;
        case MotionEventCompatUtils.ACTION_HOVER_EXIT:
            touchEvent.setAction(MotionEvent.ACTION_UP);
            sPreviousDownTime = 0;
            break;
        default:
            downTime = touchEvent.getDownTime();
    }

    MotionEventCompatUtils.setSource(touchEvent, InputDeviceCompatUtils.SOURCE_MOUSE);
    MotionEventCompatUtils.setDownTime(touchEvent, downTime);

    return touchEvent;
}
 
源代码11 项目: android-chromium   文件: LongPressDetector.java
void cancelLongPressIfNeeded(MotionEvent ev) {
    if (!hasPendingMessage() ||
        mCurrentDownEvent == null || ev.getDownTime() != mCurrentDownEvent.getDownTime()) {
        return;
    }
    final int action = ev.getAction();
    final float y = ev.getY();
    final float x = ev.getX();
    switch (action & MotionEvent.ACTION_MASK) {
        case MotionEvent.ACTION_MOVE:
            final int deltaX = (int) (x - mCurrentDownEvent.getX());
            final int deltaY = (int) (y - mCurrentDownEvent.getY());
            int distance = (deltaX * deltaX) + (deltaY * deltaY);
            if (distance > mTouchSlopSquare) {
                cancelLongPress();
            }
            break;
        case MotionEvent.ACTION_UP:
        case MotionEvent.ACTION_CANCEL:
            if (calculateLongPressTimeoutTime(mCurrentDownEvent) > ev.getEventTime()) {
                cancelLongPress();
            }
            break;
        default:
            break;
    }
}
 
源代码12 项目: ProgressView   文件: LongTouchHandler.java
@Override
public boolean onTouch(View v, MotionEvent event) {
    if (v.isClickable()) {
        /* handle press states */
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            v.setPressed(true);
            timer = new Timer();
            // Initial delay = length of a long press
            timer.schedule(new IncrementTask(0, ViewConfiguration.getLongPressTimeout()), ViewConfiguration.getLongPressTimeout());
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            timer.cancel();
            v.setPressed(false);
        }

        long lengthOfPress = event.getEventTime() - event.getDownTime();
        // If the button has been "tapped" then handle normally
        if (lengthOfPress < ViewConfiguration.getLongPressTimeout()
            && event.getAction() == MotionEvent.ACTION_UP) {
                incrementListener.increment();
        }

        return true;
    } else {
        /* If the view isn't clickable, let the touch be handled by others. */
        return false;
    }
}
 
源代码13 项目: sealtalk-android   文件: SwitchButton.java
@Override
public boolean onTouchEvent(MotionEvent event) {

	if (!isEnabled() || !isClickable()) {
		return false;
	}

	int action = event.getAction();

	float deltaX = event.getX() - mStartX;
	float deltaY = event.getY() - mStartY;

	// status the view going to change to when finger released
	boolean nextStatus;

	switch (action) {
		case MotionEvent.ACTION_DOWN:
			catchView();
			mStartX = event.getX();
			mStartY = event.getY();
			mLastX = mStartX;
			setPressed(true);
			break;

		case MotionEvent.ACTION_MOVE:
			float x = event.getX();
			setProcess(getProcess() + (x - mLastX) / mSafeRectF.width());
			mLastX = x;
			break;

		case MotionEvent.ACTION_CANCEL:
		case MotionEvent.ACTION_UP:
			setPressed(false);
			nextStatus = getStatusBasedOnPos();
			float time = event.getEventTime() - event.getDownTime();
			if (deltaX < mTouchSlop && deltaY < mTouchSlop && time < mClickTimeout) {
				performClick();
			} else {
				if (nextStatus != isChecked()) {
					playSoundEffect(SoundEffectConstants.CLICK);
					setChecked(nextStatus);
				} else {
					animateToState(nextStatus);
				}
			}
			break;

		default:
			break;
	}
	return true;
}
 
源代码14 项目: DoraemonKit   文件: TouchProxy.java
public boolean onTouchEvent(View v, MotionEvent event) {
    int distance = UIUtils.dp2px(1) * MIN_DISTANCE_MOVE;
    int x = (int) event.getRawX();
    int y = (int) event.getRawY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN: {
            mStartX = x;
            mStartY = y;
            mLastY = y;
            mLastX = x;
            if (mEventListener != null) {
                mEventListener.onDown(x, y);
            }
        }
        break;
        case MotionEvent.ACTION_MOVE: {
            if (Math.abs(x - mStartX) < distance
                    && Math.abs(y - mStartY) < distance) {
                if (mState == TouchState.STATE_STOP) {
                    break;
                }
            } else if (mState != TouchState.STATE_MOVE) {
                mState = TouchState.STATE_MOVE;
            }
            if (mEventListener != null) {
                mEventListener.onMove(mLastX, mLastY, x - mLastX, y - mLastY);
            }
            mLastY = y;
            mLastX = x;
            mState = TouchState.STATE_MOVE;
        }
        break;
        case MotionEvent.ACTION_UP: {
            if (mEventListener != null) {
                mEventListener.onUp(x, y);
            }
            if (mState != TouchState.STATE_MOVE
                    && event.getEventTime() - event.getDownTime() < MIN_TAP_TIME) {
                v.performClick();
            }
            mState = TouchState.STATE_STOP;
        }
        break;
        default:
            break;
    }
    return true;
}
 
源代码15 项目: VCL-Android   文件: AudioPlayer.java
@Override
public boolean onTouch(View v, MotionEvent event) {
    if (mService == null)
        return false;
    switch(event.getAction()) {
    case MotionEvent.ACTION_DOWN:
        (forward ? mNext : mPrevious).setImageResource(this.pressed);

        possibleSeek = (int) mService.getTime();

        mPreviewingSeek = true;
        vibrated = false;
        length = mService.getLength();

        h.postDelayed(seekRunnable, 1000);
        return true;

    case MotionEvent.ACTION_UP:
        (forward ? mNext : mPrevious).setImageResource(this.normal);
        h.removeCallbacks(seekRunnable);
        mPreviewingSeek = false;

        if(event.getEventTime()-event.getDownTime() < 1000) {
            if(forward)
                onNextClick(v);
            else
                onPreviousClick(v);
        } else {
            if(forward) {
                if(possibleSeek < mService.getLength())
                    mService.setTime(possibleSeek);
                else
                    onNextClick(v);
            } else {
                if(possibleSeek > 0)
                    mService.setTime(possibleSeek);
                else
                    onPreviousClick(v);
            }
        }
        return true;
    }
    return false;
}
 
源代码16 项目: BaseProject   文件: SwitchButton.java
@Override
public boolean onTouchEvent(MotionEvent event) {
    int action = event.getAction();
    float x = event.getX();
    float y = event.getY();
    float deltaX = Math.abs(x - mFirstDownX);
    float deltaY = Math.abs(y - mFirstDownY);
    switch (action) {
        case MotionEvent.ACTION_DOWN:
            attemptClaimDrag();
            mFirstDownX = x;
            mFirstDownY = y;
            mCurBtnPic = mBtnPressed;
            mBtnInitPos = mChecked ? mBtnOnPos : mBtnOffPos;
            break;
        case MotionEvent.ACTION_MOVE:
            float time = event.getEventTime() - event.getDownTime();
            mBtnPos = mBtnInitPos + event.getX() - mFirstDownX;
            if (mBtnPos >= mBtnOffPos) {
                mBtnPos = mBtnOffPos;
            }
            if (mBtnPos <= mBtnOnPos) {
                mBtnPos = mBtnOnPos;
            }
            mTurningOn = mBtnPos > (mBtnOffPos - mBtnOnPos) / 2 + mBtnOnPos;

            mRealPos = getRealPos(mBtnPos);
            break;
        case MotionEvent.ACTION_UP:
            mCurBtnPic = mBtnNormal;
            time = event.getEventTime() - event.getDownTime();
            if (deltaY < mTouchSlop && deltaX < mTouchSlop && time < mClickTimeout) {
                if (mPerformClick == null) {
                    mPerformClick = new PerformClick();
                }
                if (!post(mPerformClick)) {
                    performClick();
                }
            } else {
                startAnimation(!mTurningOn);
            }
            break;
    }

    invalidate();
    return isEnabled();
}
 
源代码17 项目: SettingView   文件: SwitchButton.java
@Override
public boolean onTouchEvent(MotionEvent event) {
	int action = event.getAction();
	float x = event.getX();
	float y = event.getY();
	float deltaX = Math.abs(x - mFirstDownX);
	float deltaY = Math.abs(y - mFirstDownY);
	switch (action) {
	case MotionEvent.ACTION_DOWN:
		ViewParent mParent = getParent();
		if (mParent != null) {
			// 通知父控件不要拦截本view的触摸事件
			mParent.requestDisallowInterceptTouchEvent(true);
		}
		mFirstDownX = x;
		mFirstDownY = y;
		bmCurBtnPic = bmBtnPressed;
		startBtnPos = mChecked ? onBtnPos : offBtnPos;
		break;
	case MotionEvent.ACTION_MOVE:
		float time = event.getEventTime() - event.getDownTime();
		curBtnPos = startBtnPos + event.getX() - mFirstDownX;
		if (curBtnPos >= onBtnPos) {
			curBtnPos = onBtnPos;
		}
		if (curBtnPos <= offBtnPos) {
			curBtnPos = offBtnPos;
		}
		mTurningOn = curBtnPos > bgWidth / 2 - btnWidth / 2;
		break;
	case MotionEvent.ACTION_UP:
		bmCurBtnPic = bmBtnNormal;
		time = event.getEventTime() - event.getDownTime();
		if (deltaY < mTouchSlop && deltaX < mTouchSlop && time < mClickTimeout) {
			if (mPerformClick == null) {
				mPerformClick = new PerformClick();
			}
			if (!post(mPerformClick)) {
				performClick();
			}
		} else {
			startAnimation(mTurningOn);
		}
		break;
	}
	invalidate();
	return isEnabled();
}
 
源代码18 项目: DevHeadLine   文件: SwitchButton.java
@Override
public boolean onTouchEvent(MotionEvent event) {

    if (!isEnabled() || !isClickable()) {
        return false;
    }

    int action = event.getAction();

    float deltaX = event.getX() - mStartX;
    float deltaY = event.getY() - mStartY;

    // status the view going to change to when finger released
    boolean nextStatus;

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            catchView();
            mStartX = event.getX();
            mStartY = event.getY();
            mLastX = mStartX;
            setPressed(true);
            break;

        case MotionEvent.ACTION_MOVE:
            float x = event.getX();
            setProcess(getProcess() + (x - mLastX) / mSafeRectF.width());
            mLastX = x;
            break;

        case MotionEvent.ACTION_CANCEL:
        case MotionEvent.ACTION_UP:
            setPressed(false);
            nextStatus = getStatusBasedOnPos();
            float time = event.getEventTime() - event.getDownTime();
            if (deltaX < mTouchSlop && deltaY < mTouchSlop && time < mClickTimeout) {
                performClick();
            } else {
                if (nextStatus != isChecked()) {
                    playSoundEffect(SoundEffectConstants.CLICK);
                    setChecked(nextStatus);
                } else {
                    animateToState(nextStatus);
                }
            }
            break;

        default:
            break;
    }
    return true;
}
 
源代码19 项目: AndroidChromium   文件: AppMenuDragHelper.java
/**
 * Gets all the touch events and updates dragging related logic. Note that if this app menu
 * is initiated by software UI control, then the control should set onTouchListener and forward
 * all the events to this method because the initial UI control that processed ACTION_DOWN will
 * continue to get all the subsequent events.
 *
 * @param event Touch event to be processed.
 * @param button Button that received the touch event.
 * @return Whether the event is handled.
 */
boolean handleDragging(MotionEvent event, View button) {
    if (!mAppMenu.isShowing() || !mDragScrolling.isRunning()) return false;

    // We will only use the screen space coordinate (rawX, rawY) to reduce confusion.
    // This code works across many different controls, so using local coordinates will be
    // a disaster.

    final float rawX = event.getRawX();
    final float rawY = event.getRawY();
    final int roundedRawX = Math.round(rawX);
    final int roundedRawY = Math.round(rawY);
    final int eventActionMasked = event.getActionMasked();
    final long timeSinceDown = event.getEventTime() - event.getDownTime();
    final ListView listView = mAppMenu.getPopup().getListView();

    mLastTouchX = rawX;
    mLastTouchY = rawY;
    mMenuButtonScreenCenterY = getScreenVisibleRect(button).centerY();

    if (eventActionMasked == MotionEvent.ACTION_CANCEL) {
        mAppMenu.dismiss();
        return true;
    } else if (eventActionMasked == MotionEvent.ACTION_UP) {
        nativeRecordAppMenuTouchDuration(timeSinceDown);
    }

    mIsSingleTapCanceled |= timeSinceDown > mTapTimeout;
    mIsSingleTapCanceled |= !pointInView(button, event.getX(), event.getY(), mScaledTouchSlop);
    if (!mIsSingleTapCanceled && eventActionMasked == MotionEvent.ACTION_UP) {
        RecordUserAction.record("MobileUsingMenuBySwButtonTap");
        finishDragging();
    }

    // After this line, drag scrolling is happening.
    if (!mDragScrolling.isRunning()) return false;

    boolean didPerformClick = false;
    int itemAction = ITEM_ACTION_CLEAR_HIGHLIGHT_ALL;
    switch (eventActionMasked) {
        case MotionEvent.ACTION_DOWN:
        case MotionEvent.ACTION_MOVE:
            itemAction = ITEM_ACTION_HIGHLIGHT;
            break;
        case MotionEvent.ACTION_UP:
            itemAction = ITEM_ACTION_PERFORM;
            break;
        default:
            break;
    }
    didPerformClick = menuItemAction(roundedRawX, roundedRawY, itemAction);

    if (eventActionMasked == MotionEvent.ACTION_UP && !didPerformClick) {
        RecordUserAction.record("MobileUsingMenuBySwButtonDragging");
        mAppMenu.dismiss();
    } else if (eventActionMasked == MotionEvent.ACTION_MOVE) {
        // Auto scrolling on the top or the bottom of the listView.
        if (listView.getHeight() > 0) {
            float autoScrollAreaRatio = Math.min(AUTO_SCROLL_AREA_MAX_RATIO,
                    mItemRowHeight * 1.2f / listView.getHeight());
            float normalizedY =
                    (rawY - getScreenVisibleRect(listView).top) / listView.getHeight();
            if (normalizedY < autoScrollAreaRatio) {
                // Top
                mDragScrollingVelocity = (normalizedY / autoScrollAreaRatio - 1.0f)
                        * mAutoScrollFullVelocity;
            } else if (normalizedY > 1.0f - autoScrollAreaRatio) {
                // Bottom
                mDragScrollingVelocity = ((normalizedY - 1.0f) / autoScrollAreaRatio + 1.0f)
                        * mAutoScrollFullVelocity;
            } else {
                // Middle or not scrollable.
                mDragScrollingVelocity = 0.0f;
            }
        }
    }

    return true;
}
 
源代码20 项目: AndroidPDF   文件: DragPinchListener.java
/**
 * Test if a MotionEvent with the given start and end offsets
 * can be considered as a "click".
 * @param upEvent The final finger-up event.
 * @param xDown   The x-offset of the down event.
 * @param yDown   The y-offset of the down event.
 * @param xUp     The x-offset of the up event.
 * @param yUp     The y-offset of the up event.
 * @return true if it's a click, false otherwise
 */
private boolean isClick(MotionEvent upEvent, float xDown, float yDown, float xUp, float yUp) {
    if (upEvent == null) return false;
    long time = upEvent.getEventTime() - upEvent.getDownTime();
    float distance = PointF.length( //
            xDown - xUp, //
            yDown - yUp);
    return time < MAX_CLICK_TIME && distance < MAX_CLICK_DISTANCE;
}