11ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell/* 2ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikas * Copyright 2018 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 17ac5fe7c617c66850fff75a9fce9979c6e5674b0fAurimas Liutikaspackage androidx.core.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 */ 48c5847d13e40f5d52459f5c0dab32dc08f1a9a683Chris Banespublic final 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; 72552766fa685c63ad760c92239faaba12e6ad51f1Aurimas Liutikas final OnGestureListener mListener; 73552766fa685c63ad760c92239faaba12e6ad51f1Aurimas Liutikas OnDoubleTapListener mDoubleTapListener; 741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 75552766fa685c63ad760c92239faaba12e6ad51f1Aurimas Liutikas boolean mStillDown; 76552766fa685c63ad760c92239faaba12e6ad51f1Aurimas Liutikas boolean mDeferConfirmSingleTap; 771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mInLongPress; 781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mAlwaysInTapRegion; 791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mAlwaysInBiggerTapRegion; 801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 81552766fa685c63ad760c92239faaba12e6ad51f1Aurimas Liutikas 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 */ 1515211222f71426ccfc1f2cca9f5f6bb89c61c9ed5Jake Wharton 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 */ 19115375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 1921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) { 1931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDoubleTapListener = onDoubleTapListener; 1941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 1971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Set whether longpress is enabled, if this is enabled when a user 1981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * presses and holds down you get a longpress event and nothing further. 1991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * If it's disabled the user can press and hold down and then later 2001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * moved their finger and you will get scroll events. By default 2011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * longpress is enabled. 2021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 2031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param isLongpressEnabled whether longpress should be enabled. 2041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 20515375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 2061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean isLongpressEnabled) { 2071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsLongpressEnabled = isLongpressEnabled; 2081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 2111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if longpress is enabled, else false. 2121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 21315375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 2141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 2151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mIsLongpressEnabled; 2161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 2191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Analyzes the given motion event and if applicable triggers the 2201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * appropriate callbacks on the {@link OnGestureListener} supplied. 2211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 2221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param ev The current motion event. 2231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if the {@link OnGestureListener} consumed the event, 2241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * else false. 2251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 22615375aa6fd54b036f97f99229aefab2822c8a1c9Aurimas Liutikas @Override 2271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent ev) { 2281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int action = ev.getAction(); 2291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mVelocityTracker == null) { 2311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = VelocityTracker.obtain(); 2321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.addMovement(ev); 2341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final boolean pointerUp = 2366ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP; 2376ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas final int skipIndex = pointerUp ? ev.getActionIndex() : -1; 2381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Determine focal point 2401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell float sumX = 0, sumY = 0; 2411b3e9466b4c4d72f28bb4448672ef8bab19b6f3eKirill Grouchnikov final int count = ev.getPointerCount(); 2421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell for (int i = 0; i < count; i++) { 2431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (skipIndex == i) continue; 2441b3e9466b4c4d72f28bb4448672ef8bab19b6f3eKirill Grouchnikov sumX += ev.getX(i); 2451b3e9466b4c4d72f28bb4448672ef8bab19b6f3eKirill Grouchnikov sumY += ev.getY(i); 2461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int div = pointerUp ? count - 1 : count; 2481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float focusX = sumX / div; 2491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float focusY = sumY / div; 2501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell boolean handled = false; 2521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2536ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas switch (action & MotionEvent.ACTION_MASK) { 2546ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas case MotionEvent.ACTION_POINTER_DOWN: 255374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDownFocusX = mLastFocusX = focusX; 256374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDownFocusY = mLastFocusY = focusY; 257374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // Cancel long press and taps 258374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas cancelTaps(); 259374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas break; 260374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 2616ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas case MotionEvent.ACTION_POINTER_UP: 262374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDownFocusX = mLastFocusX = focusX; 263374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDownFocusY = mLastFocusY = focusY; 264374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 265374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // Check the dot product of current velocities. 266374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // If the pointer that left was opposing another velocity vector, clear. 267374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 2686ed40c1f86bcb172a1f0f069cde1c571a7781aeeAurimas Liutikas final int upIndex = ev.getActionIndex(); 269374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final int id1 = ev.getPointerId(upIndex); 270374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float x1 = mVelocityTracker.getXVelocity(id1); 271374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float y1 = mVelocityTracker.getYVelocity(id1); 272374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas for (int i = 0; i < count; i++) { 273374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (i == upIndex) continue; 274374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 275374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final int id2 = ev.getPointerId(i); 276374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float x = x1 * mVelocityTracker.getXVelocity(id2); 277374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float y = y1 * mVelocityTracker.getYVelocity(id2); 278374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 279374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float dot = x + y; 280374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (dot < 0) { 281374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mVelocityTracker.clear(); 282374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas break; 283374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 2841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 285374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas break; 286374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 287374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas case MotionEvent.ACTION_DOWN: 288374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mDoubleTapListener != null) { 289374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas boolean hadTapMessage = mHandler.hasMessages(TAP); 290374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (hadTapMessage) mHandler.removeMessages(TAP); 291374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) 292374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas && hadTapMessage && isConsideredDoubleTap( 293374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mCurrentDownEvent, mPreviousUpEvent, ev)) { 294374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // This is a second tap 295374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mIsDoubleTapping = true; 296374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // Give a callback with the first tap of the double-tap 297374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); 298374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // Give a callback with down event of the double-tap 299374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled |= mDoubleTapListener.onDoubleTapEvent(ev); 300374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } else { 301374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // This is a first tap 302374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); 303374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 3041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 306374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDownFocusX = mLastFocusX = focusX; 307374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDownFocusY = mLastFocusY = focusY; 308374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mCurrentDownEvent != null) { 309374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mCurrentDownEvent.recycle(); 310374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 311374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mCurrentDownEvent = MotionEvent.obtain(ev); 312374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mAlwaysInTapRegion = true; 313374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mAlwaysInBiggerTapRegion = true; 314374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mStillDown = true; 315374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mInLongPress = false; 316374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDeferConfirmSingleTap = false; 3171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 318374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mIsLongpressEnabled) { 319374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.removeMessages(LONG_PRESS); 320374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() 321374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas + TAP_TIMEOUT + LONGPRESS_TIMEOUT); 322374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 323374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.sendEmptyMessageAtTime(SHOW_PRESS, 324374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); 325374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled |= mListener.onDown(ev); 3261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 327374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 328374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas case MotionEvent.ACTION_MOVE: 329374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mInLongPress) { 330374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas break; 331374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 332374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float scrollX = mLastFocusX - focusX; 333374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float scrollY = mLastFocusY - focusY; 334374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mIsDoubleTapping) { 335374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // Give the move events of the double-tap 336374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled |= mDoubleTapListener.onDoubleTapEvent(ev); 337374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } else if (mAlwaysInTapRegion) { 338374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final int deltaX = (int) (focusX - mDownFocusX); 339374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final int deltaY = (int) (focusY - mDownFocusY); 340374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas int distance = (deltaX * deltaX) + (deltaY * deltaY); 341374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (distance > mTouchSlopSquare) { 342374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); 343374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mLastFocusX = focusX; 344374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mLastFocusY = focusY; 345374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mAlwaysInTapRegion = false; 346374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.removeMessages(TAP); 347374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.removeMessages(SHOW_PRESS); 348374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.removeMessages(LONG_PRESS); 349374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 350374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (distance > mTouchSlopSquare) { 351374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mAlwaysInBiggerTapRegion = false; 352374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 353374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) { 3541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); 3551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusX = focusX; 3561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusY = focusY; 3571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 358374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas break; 359374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 360374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas case MotionEvent.ACTION_UP: 361374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mStillDown = false; 362374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas MotionEvent currentUpEvent = MotionEvent.obtain(ev); 363374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mIsDoubleTapping) { 364374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // Finally, give the up event of the double-tap 365374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled |= mDoubleTapListener.onDoubleTapEvent(ev); 366374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } else if (mInLongPress) { 367374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.removeMessages(TAP); 368374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mInLongPress = false; 369374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } else if (mAlwaysInTapRegion) { 370374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled = mListener.onSingleTapUp(ev); 371374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mDeferConfirmSingleTap && mDoubleTapListener != null) { 372374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDoubleTapListener.onSingleTapConfirmed(ev); 373374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 374374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } else { 375374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // A fling must travel the minimum tap distance 376374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final VelocityTracker velocityTracker = mVelocityTracker; 377374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final int pointerId = ev.getPointerId(0); 378374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 379374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float velocityY = velocityTracker.getYVelocity(pointerId); 380374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas final float velocityX = velocityTracker.getXVelocity(pointerId); 381374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 382374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if ((Math.abs(velocityY) > mMinimumFlingVelocity) 383374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas || (Math.abs(velocityX) > mMinimumFlingVelocity)) { 384374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas handled = mListener.onFling( 385374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mCurrentDownEvent, ev, velocityX, velocityY); 386374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas } 3871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 388374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mPreviousUpEvent != null) { 389374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mPreviousUpEvent.recycle(); 390f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell } 391374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // Hold the event we obtained above - listeners may have changed the original. 392374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mPreviousUpEvent = currentUpEvent; 393374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas if (mVelocityTracker != null) { 394374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // This may have been cleared when we called out to the 395374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas // application above. 396374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mVelocityTracker.recycle(); 397374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mVelocityTracker = null; 3981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 399374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mIsDoubleTapping = false; 400374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mDeferConfirmSingleTap = false; 401374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.removeMessages(SHOW_PRESS); 402374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas mHandler.removeMessages(LONG_PRESS); 403374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas break; 404374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas 405374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas case MotionEvent.ACTION_CANCEL: 406374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas cancel(); 407374cad6778dfb6923f35bfc28290a9baad22743eAurimas Liutikas break; 4081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return handled; 4111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void cancel() { 4141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 4151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 4161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 4171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.recycle(); 4181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = null; 4191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 4201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mStillDown = false; 4211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 4221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 423f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 4241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 4251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 4261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void cancelTaps() { 4301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 4311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 4321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 4331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 4341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 4351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 436f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 4371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 4381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 4391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp, 4431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell MotionEvent secondDown) { 4441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (!mAlwaysInBiggerTapRegion) { 4451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return false; 4461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) { 4491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return false; 4501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int deltaX = (int) firstDown.getX() - (int) secondDown.getX(); 4531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int deltaY = (int) firstDown.getY() - (int) secondDown.getY(); 4541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare); 4551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 457552766fa685c63ad760c92239faaba12e6ad51f1Aurimas Liutikas void dispatchLongPress() { 4581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 459f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mDeferConfirmSingleTap = false; 4601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = true; 4611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mListener.onLongPress(mCurrentDownEvent); 4621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 465f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell static class GestureDetectorCompatImplJellybeanMr2 implements GestureDetectorCompatImpl { 4661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final GestureDetector mDetector; 4671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4685211222f71426ccfc1f2cca9f5f6bb89c61c9ed5Jake Wharton GestureDetectorCompatImplJellybeanMr2(Context context, OnGestureListener listener, 4691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell Handler handler) { 4701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector = new GestureDetector(context, listener, handler); 4711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 4751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mDetector.isLongpressEnabled(); 4761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent ev) { 4801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mDetector.onTouchEvent(ev); 4811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean enabled) { 4851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector.setIsLongpressEnabled(enabled); 4861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener listener) { 4901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector.setOnDoubleTapListener(listener); 4911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final GestureDetectorCompatImpl mImpl; 4951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 4971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetectorCompat with the supplied listener. 4981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * As usual, you may only use this constructor from a UI thread. 4991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 5001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 5021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 5031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 5041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompat(Context context, OnGestureListener listener) { 5061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell this(context, listener, null); 5071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetectorCompat with the supplied listener. 5111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * As usual, you may only use this constructor from a UI thread. 5121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 5131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 5151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 5161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 5171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param handler the handler that will be used for posting deferred messages 5181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompat(Context context, OnGestureListener listener, Handler handler) { 520f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell if (Build.VERSION.SDK_INT > 17) { 521f48af3312a4f63d8ce232fe7476932c0201774d9Adam Powell mImpl = new GestureDetectorCompatImplJellybeanMr2(context, listener, handler); 5221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 5231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl = new GestureDetectorCompatImplBase(context, listener, handler); 5241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if longpress is enabled, else false. 5291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 5311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mImpl.isLongpressEnabled(); 5321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Analyzes the given motion event and if applicable triggers the 5361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * appropriate callbacks on the {@link OnGestureListener} supplied. 5371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param event The current motion event. 5391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if the {@link OnGestureListener} consumed the event, 5401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * else false. 5411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent event) { 5431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mImpl.onTouchEvent(event); 5441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Set whether longpress is enabled, if this is enabled when a user 5481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * presses and holds down you get a longpress event and nothing further. 5491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * If it's disabled the user can press and hold down and then later 5501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * moved their finger and you will get scroll events. By default 5511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * longpress is enabled. 5521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param enabled whether longpress should be enabled. 5541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean enabled) { 5561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl.setIsLongpressEnabled(enabled); 5571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Sets the listener which will be called for double-tap and related 5611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * gestures. 5621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, or 5641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * null to stop listening for double-tap gestures. 5651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener listener) { 5671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl.setOnDoubleTapListener(listener); 5681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell} 570