11ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell/* 21ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Copyright (C) 2012 The Android Open Source Project 31ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 41ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Licensed under the Apache License, Version 2.0 (the "License"); 51ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * you may not use this file except in compliance with the License. 61ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * You may obtain a copy of the License at 71ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 81ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * http://www.apache.org/licenses/LICENSE-2.0 91ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Unless required by applicable law or agreed to in writing, software 111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * distributed under the License is distributed on an "AS IS" BASIS, 121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * See the License for the specific language governing permissions and 141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * limitations under the License. 151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellpackage android.support.v4.view; 181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.content.Context; 201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.os.Build; 211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.os.Handler; 221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.os.Message; 231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.view.GestureDetector; 241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.view.GestureDetector.OnDoubleTapListener; 251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.view.GestureDetector.OnGestureListener; 261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.view.MotionEvent; 271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.view.VelocityTracker; 281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.view.View; 291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellimport android.view.ViewConfiguration; 301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell/** 321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Detects various gestures and events using the supplied {@link MotionEvent}s. 331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * The {@link OnGestureListener} callback will notify users when a particular 341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * motion event has occurred. This class should only be used with {@link MotionEvent}s 351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * reported via touch (don't use for trackball events). 361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * <p>This compatibility implementation of the framework's GestureDetector guarantees 381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * the newer focal point scrolling behavior from Jellybean MR1 on all platform versions.</p> 391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * To use this class: 411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * <ul> 421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * <li>Create an instance of the {@code GestureDetectorCompat} for your {@link View} 431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call 441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback 451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * will be executed when the events occur. 461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * </ul> 471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powellpublic class GestureDetectorCompat { 491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell interface GestureDetectorCompatImpl { 501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell boolean isLongpressEnabled(); 511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell boolean onTouchEvent(MotionEvent ev); 521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell void setIsLongpressEnabled(boolean enabled); 531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell void setOnDoubleTapListener(OnDoubleTapListener listener); 541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell static class GestureDetectorCompatImplBase implements GestureDetectorCompatImpl { 571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private int mTouchSlopSquare; 581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private int mDoubleTapSlopSquare; 591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private int mMinimumFlingVelocity; 601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private int mMaximumFlingVelocity; 611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); 631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout(); 641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout(); 651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // constants for Message.what used by GestureHandler below 671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private static final int SHOW_PRESS = 1; 681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private static final int LONG_PRESS = 2; 691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private static final int TAP = 3; 701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final Handler mHandler; 721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final OnGestureListener mListener; 731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private OnDoubleTapListener mDoubleTapListener; 741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mStillDown; 76f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell private boolean mDeferConfirmSingleTap; 771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mInLongPress; 781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mAlwaysInTapRegion; 791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mAlwaysInBiggerTapRegion; 801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private MotionEvent mCurrentDownEvent; 821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private MotionEvent mPreviousUpEvent; 831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * True when the user is still touching for the second tap (down, move, and 861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * up events). Can only be true if there is a double tap listener attached. 871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mIsDoubleTapping; 891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mLastFocusX; 911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mLastFocusY; 921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mDownFocusX; 931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mDownFocusY; 941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mIsLongpressEnabled; 961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Determines speed during touch scrolling 991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 1001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private VelocityTracker mVelocityTracker; 1011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private class GestureHandler extends Handler { 1031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell GestureHandler() { 1041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell super(); 1051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell GestureHandler(Handler handler) { 1081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell super(handler.getLooper()); 1091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 1121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void handleMessage(Message msg) { 1131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell switch (msg.what) { 1141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case SHOW_PRESS: 1151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mListener.onShowPress(mCurrentDownEvent); 1161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 1171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case LONG_PRESS: 1191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell dispatchLongPress(); 1201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 1211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case TAP: 1231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // If the user's finger is still down, do not count it as a tap 124f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell if (mDoubleTapListener != null) { 125f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell if (!mStillDown) { 126f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent); 127f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell } else { 128f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = true; 129f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell } 1301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 1321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell default: 1341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell throw new RuntimeException("Unknown message " + msg); //never 1351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 1401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetector with the supplied listener. 1411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * You may only use this constructor from a UI thread (this is the usual situation). 1421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 1431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 1441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 1451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 1461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 1471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param handler the handler to use 1481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 1491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @throws NullPointerException if {@code listener} is null. 1501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 1511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompatImplBase(Context context, OnGestureListener listener, 1521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell Handler handler) { 1531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (handler != null) { 1541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler = new GestureHandler(handler); 1551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 1561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler = new GestureHandler(); 1571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mListener = listener; 1591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (listener instanceof OnDoubleTapListener) { 1601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell setOnDoubleTapListener((OnDoubleTapListener) listener); 1611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell init(context); 1631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void init(Context context) { 1661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (context == null) { 1671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell throw new IllegalArgumentException("Context must not be null"); 1681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mListener == null) { 1701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell throw new IllegalArgumentException("OnGestureListener must not be null"); 1711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsLongpressEnabled = true; 1731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final ViewConfiguration configuration = ViewConfiguration.get(context); 1751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int touchSlop = configuration.getScaledTouchSlop(); 1761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int doubleTapSlop = configuration.getScaledDoubleTapSlop(); 1771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 1781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity(); 1791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mTouchSlopSquare = touchSlop * touchSlop; 1811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop; 1821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 1851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Sets the listener which will be called for double-tap and related 1861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * gestures. 1871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 1881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param onDoubleTapListener the listener invoked for all the callbacks, or 1891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * null to stop listening for double-tap gestures. 1901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 1911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) { 1921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDoubleTapListener = onDoubleTapListener; 1931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 1961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Set whether longpress is enabled, if this is enabled when a user 1971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * presses and holds down you get a longpress event and nothing further. 1981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * If it's disabled the user can press and hold down and then later 1991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * moved their finger and you will get scroll events. By default 2001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * longpress is enabled. 2011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 2021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param isLongpressEnabled whether longpress should be enabled. 2031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 2041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean isLongpressEnabled) { 2051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsLongpressEnabled = isLongpressEnabled; 2061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 2091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if longpress is enabled, else false. 2101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 2111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 2121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mIsLongpressEnabled; 2131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 2161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Analyzes the given motion event and if applicable triggers the 2171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * appropriate callbacks on the {@link OnGestureListener} supplied. 2181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 2191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param ev The current motion event. 2201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if the {@link OnGestureListener} consumed the event, 2211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * else false. 2221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 2231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent ev) { 2241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int action = ev.getAction(); 2251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mVelocityTracker == null) { 2271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = VelocityTracker.obtain(); 2281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.addMovement(ev); 2301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final boolean pointerUp = 2321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell (action & MotionEventCompat.ACTION_MASK) == MotionEventCompat.ACTION_POINTER_UP; 2331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int skipIndex = pointerUp ? MotionEventCompat.getActionIndex(ev) : -1; 2341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Determine focal point 2361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell float sumX = 0, sumY = 0; 2371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int count = MotionEventCompat.getPointerCount(ev); 2381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell for (int i = 0; i < count; i++) { 2391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (skipIndex == i) continue; 2401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell sumX += MotionEventCompat.getX(ev, i); 2411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell sumY += MotionEventCompat.getY(ev, i); 2421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int div = pointerUp ? count - 1 : count; 2441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float focusX = sumX / div; 2451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float focusY = sumY / div; 2461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell boolean handled = false; 2481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell switch (action & MotionEventCompat.ACTION_MASK) { 2501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEventCompat.ACTION_POINTER_DOWN: 2511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusX = mLastFocusX = focusX; 2521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusY = mLastFocusY = focusY; 2531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Cancel long press and taps 2541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell cancelTaps(); 2551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 2561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEventCompat.ACTION_POINTER_UP: 2581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusX = mLastFocusX = focusX; 2591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusY = mLastFocusY = focusY; 2601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Check the dot product of current velocities. 2621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // If the pointer that left was opposing another velocity vector, clear. 2631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 2641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int upIndex = MotionEventCompat.getActionIndex(ev); 2651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int id1 = MotionEventCompat.getPointerId(ev, upIndex); 2661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float x1 = VelocityTrackerCompat.getXVelocity(mVelocityTracker, id1); 2671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float y1 = VelocityTrackerCompat.getYVelocity(mVelocityTracker, id1); 2681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell for (int i = 0; i < count; i++) { 2691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (i == upIndex) continue; 2701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int id2 = MotionEventCompat.getPointerId(ev, i); 2721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float x = x1 * VelocityTrackerCompat.getXVelocity(mVelocityTracker, id2); 2731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float y = y1 * VelocityTrackerCompat.getYVelocity(mVelocityTracker, id2); 2741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float dot = x + y; 2761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (dot < 0) { 2771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.clear(); 2781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 2791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 2821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_DOWN: 2841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mDoubleTapListener != null) { 2851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell boolean hadTapMessage = mHandler.hasMessages(TAP); 2861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (hadTapMessage) mHandler.removeMessages(TAP); 2871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && 2881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) { 2891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // This is a second tap 2901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = true; 2911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Give a callback with the first tap of the double-tap 2921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); 2931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Give a callback with down event of the double-tap 2941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTapEvent(ev); 2951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 2961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // This is a first tap 2971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); 2981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusX = mLastFocusX = focusX; 3021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusY = mLastFocusY = focusY; 3031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mCurrentDownEvent != null) { 3041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mCurrentDownEvent.recycle(); 3051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mCurrentDownEvent = MotionEvent.obtain(ev); 3071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = true; 3081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = true; 3091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mStillDown = true; 3101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 311f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 3121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mIsLongpressEnabled) { 3141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 3151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() 3161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell + TAP_TIMEOUT + LONGPRESS_TIMEOUT); 3171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); 3191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mListener.onDown(ev); 3201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_MOVE: 3231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 3241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float scrollX = mLastFocusX - focusX; 3271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float scrollY = mLastFocusY - focusY; 3281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mIsDoubleTapping) { 3291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Give the move events of the double-tap 3301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTapEvent(ev); 3311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if (mAlwaysInTapRegion) { 3321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int deltaX = (int) (focusX - mDownFocusX); 3331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int deltaY = (int) (focusY - mDownFocusY); 3341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int distance = (deltaX * deltaX) + (deltaY * deltaY); 3351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (distance > mTouchSlopSquare) { 3361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); 3371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusX = focusX; 3381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusY = focusY; 3391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 3401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 3411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 3421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 3431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (distance > mTouchSlopSquare) { 3451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 3461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) { 3481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); 3491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusX = focusX; 3501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusY = focusY; 3511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_UP: 3551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mStillDown = false; 3561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell MotionEvent currentUpEvent = MotionEvent.obtain(ev); 3571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mIsDoubleTapping) { 3581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Finally, give the up event of the double-tap 3591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTapEvent(ev); 3601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if (mInLongPress) { 3611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 3621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 3631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if (mAlwaysInTapRegion) { 3641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onSingleTapUp(ev); 365f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell if (mDeferConfirmSingleTap && mDoubleTapListener != null) { 366f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDoubleTapListener.onSingleTapConfirmed(ev); 367f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell } 3681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 3691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // A fling must travel the minimum tap distance 3701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 3711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int pointerId = MotionEventCompat.getPointerId(ev, 0); 3721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 3731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float velocityY = VelocityTrackerCompat.getYVelocity( 3741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell velocityTracker, pointerId); 3751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float velocityX = VelocityTrackerCompat.getXVelocity( 3761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell velocityTracker, pointerId); 3771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if ((Math.abs(velocityY) > mMinimumFlingVelocity) 3791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell || (Math.abs(velocityX) > mMinimumFlingVelocity)){ 3801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY); 3811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mPreviousUpEvent != null) { 3841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mPreviousUpEvent.recycle(); 3851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Hold the event we obtained above - listeners may have changed the original. 3871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mPreviousUpEvent = currentUpEvent; 3881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mVelocityTracker != null) { 3891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // This may have been cleared when we called out to the 3901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // application above. 3911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.recycle(); 3921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = null; 3931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 395f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 3961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 3971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 3981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_CANCEL: 4011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell cancel(); 4021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 4031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return handled; 4061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void cancel() { 4091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 4101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 4111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 4121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.recycle(); 4131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = null; 4141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 4151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mStillDown = false; 4161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 4171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 418f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 4191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 4201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 4211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void cancelTaps() { 4251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 4261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 4271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 4281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 4291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 4301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 431f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 4321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 4331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 4341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp, 4381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell MotionEvent secondDown) { 4391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (!mAlwaysInBiggerTapRegion) { 4401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return false; 4411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) { 4441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return false; 4451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int deltaX = (int) firstDown.getX() - (int) secondDown.getX(); 4481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int deltaY = (int) firstDown.getY() - (int) secondDown.getY(); 4491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare); 4501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void dispatchLongPress() { 4531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 454f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 4551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = true; 4561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mListener.onLongPress(mCurrentDownEvent); 4571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 460f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell static class GestureDetectorCompatImplJellybeanMr2 implements GestureDetectorCompatImpl { 4611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final GestureDetector mDetector; 4621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 463f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell public GestureDetectorCompatImplJellybeanMr2(Context context, OnGestureListener listener, 4641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell Handler handler) { 4651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector = new GestureDetector(context, listener, handler); 4661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 4701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mDetector.isLongpressEnabled(); 4711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent ev) { 4751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mDetector.onTouchEvent(ev); 4761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean enabled) { 4801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector.setIsLongpressEnabled(enabled); 4811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener listener) { 4851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector.setOnDoubleTapListener(listener); 4861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final GestureDetectorCompatImpl mImpl; 4901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 4921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetectorCompat with the supplied listener. 4931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * As usual, you may only use this constructor from a UI thread. 4941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 4951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 4961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 4971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 4981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 4991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompat(Context context, OnGestureListener listener) { 5011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell this(context, listener, null); 5021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetectorCompat with the supplied listener. 5061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * As usual, you may only use this constructor from a UI thread. 5071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 5081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 5101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 5111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 5121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param handler the handler that will be used for posting deferred messages 5131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompat(Context context, OnGestureListener listener, Handler handler) { 515f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell if (Build.VERSION.SDK_INT > 17) { 516f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mImpl = new GestureDetectorCompatImplJellybeanMr2(context, listener, handler); 5171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 5181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl = new GestureDetectorCompatImplBase(context, listener, handler); 5191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if longpress is enabled, else false. 5241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 5261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mImpl.isLongpressEnabled(); 5271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Analyzes the given motion event and if applicable triggers the 5311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * appropriate callbacks on the {@link OnGestureListener} supplied. 5321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param event The current motion event. 5341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if the {@link OnGestureListener} consumed the event, 5351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * else false. 5361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent event) { 5381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mImpl.onTouchEvent(event); 5391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Set whether longpress is enabled, if this is enabled when a user 5431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * presses and holds down you get a longpress event and nothing further. 5441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * If it's disabled the user can press and hold down and then later 5451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * moved their finger and you will get scroll events. By default 5461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * longpress is enabled. 5471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param enabled whether longpress should be enabled. 5491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean enabled) { 5511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl.setIsLongpressEnabled(enabled); 5521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Sets the listener which will be called for double-tap and related 5561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * gestures. 5571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, or 5591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * null to stop listening for double-tap gestures. 5601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener listener) { 5621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl.setOnDoubleTapListener(listener); 5631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell} 565