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; 761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mInLongPress; 771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mAlwaysInTapRegion; 781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mAlwaysInBiggerTapRegion; 791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private MotionEvent mCurrentDownEvent; 811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private MotionEvent mPreviousUpEvent; 821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * True when the user is still touching for the second tap (down, move, and 851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * up events). Can only be true if there is a double tap listener attached. 861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mIsDoubleTapping; 881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mLastFocusX; 901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mLastFocusY; 911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mDownFocusX; 921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private float mDownFocusY; 931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean mIsLongpressEnabled; 951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Determines speed during touch scrolling 981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private VelocityTracker mVelocityTracker; 1001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private class GestureHandler extends Handler { 1021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell GestureHandler() { 1031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell super(); 1041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell GestureHandler(Handler handler) { 1071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell super(handler.getLooper()); 1081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 1111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void handleMessage(Message msg) { 1121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell switch (msg.what) { 1131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case SHOW_PRESS: 1141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mListener.onShowPress(mCurrentDownEvent); 1151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 1161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case LONG_PRESS: 1181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell dispatchLongPress(); 1191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 1201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case TAP: 1221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // If the user's finger is still down, do not count it as a tap 1231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mDoubleTapListener != null && !mStillDown) { 1241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent); 1251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 1271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell default: 1291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell throw new RuntimeException("Unknown message " + msg); //never 1301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 1351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetector with the supplied listener. 1361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * You may only use this constructor from a UI thread (this is the usual situation). 1371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 1381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 1391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 1401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 1411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 1421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param handler the handler to use 1431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 1441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @throws NullPointerException if {@code listener} is null. 1451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 1461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompatImplBase(Context context, OnGestureListener listener, 1471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell Handler handler) { 1481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (handler != null) { 1491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler = new GestureHandler(handler); 1501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 1511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler = new GestureHandler(); 1521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mListener = listener; 1541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (listener instanceof OnDoubleTapListener) { 1551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell setOnDoubleTapListener((OnDoubleTapListener) listener); 1561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell init(context); 1581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void init(Context context) { 1611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (context == null) { 1621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell throw new IllegalArgumentException("Context must not be null"); 1631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mListener == null) { 1651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell throw new IllegalArgumentException("OnGestureListener must not be null"); 1661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsLongpressEnabled = true; 1681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final ViewConfiguration configuration = ViewConfiguration.get(context); 1701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int touchSlop = configuration.getScaledTouchSlop(); 1711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int doubleTapSlop = configuration.getScaledDoubleTapSlop(); 1721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity(); 1731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity(); 1741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mTouchSlopSquare = touchSlop * touchSlop; 1761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop; 1771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 1801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Sets the listener which will be called for double-tap and related 1811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * gestures. 1821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 1831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param onDoubleTapListener the listener invoked for all the callbacks, or 1841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * null to stop listening for double-tap gestures. 1851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 1861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) { 1871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDoubleTapListener = onDoubleTapListener; 1881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 1891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 1901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 1911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Set whether longpress is enabled, if this is enabled when a user 1921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * presses and holds down you get a longpress event and nothing further. 1931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * If it's disabled the user can press and hold down and then later 1941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * moved their finger and you will get scroll events. By default 1951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * longpress is enabled. 1961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 1971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param isLongpressEnabled whether longpress should be enabled. 1981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 1991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean isLongpressEnabled) { 2001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsLongpressEnabled = isLongpressEnabled; 2011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 2041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if longpress is enabled, else false. 2051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 2061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 2071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mIsLongpressEnabled; 2081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 2111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Analyzes the given motion event and if applicable triggers the 2121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * appropriate callbacks on the {@link OnGestureListener} supplied. 2131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 2141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param ev The current motion event. 2151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if the {@link OnGestureListener} consumed the event, 2161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * else false. 2171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 2181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent ev) { 2191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int action = ev.getAction(); 2201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mVelocityTracker == null) { 2221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = VelocityTracker.obtain(); 2231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.addMovement(ev); 2251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final boolean pointerUp = 2271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell (action & MotionEventCompat.ACTION_MASK) == MotionEventCompat.ACTION_POINTER_UP; 2281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int skipIndex = pointerUp ? MotionEventCompat.getActionIndex(ev) : -1; 2291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Determine focal point 2311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell float sumX = 0, sumY = 0; 2321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int count = MotionEventCompat.getPointerCount(ev); 2331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell for (int i = 0; i < count; i++) { 2341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (skipIndex == i) continue; 2351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell sumX += MotionEventCompat.getX(ev, i); 2361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell sumY += MotionEventCompat.getY(ev, i); 2371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int div = pointerUp ? count - 1 : count; 2391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float focusX = sumX / div; 2401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float focusY = sumY / div; 2411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell boolean handled = false; 2431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell switch (action & MotionEventCompat.ACTION_MASK) { 2451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEventCompat.ACTION_POINTER_DOWN: 2461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusX = mLastFocusX = focusX; 2471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusY = mLastFocusY = focusY; 2481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Cancel long press and taps 2491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell cancelTaps(); 2501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 2511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEventCompat.ACTION_POINTER_UP: 2531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusX = mLastFocusX = focusX; 2541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusY = mLastFocusY = focusY; 2551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Check the dot product of current velocities. 2571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // If the pointer that left was opposing another velocity vector, clear. 2581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 2591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int upIndex = MotionEventCompat.getActionIndex(ev); 2601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int id1 = MotionEventCompat.getPointerId(ev, upIndex); 2611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float x1 = VelocityTrackerCompat.getXVelocity(mVelocityTracker, id1); 2621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float y1 = VelocityTrackerCompat.getYVelocity(mVelocityTracker, id1); 2631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell for (int i = 0; i < count; i++) { 2641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (i == upIndex) continue; 2651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int id2 = MotionEventCompat.getPointerId(ev, i); 2671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float x = x1 * VelocityTrackerCompat.getXVelocity(mVelocityTracker, id2); 2681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float y = y1 * VelocityTrackerCompat.getYVelocity(mVelocityTracker, id2); 2691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float dot = x + y; 2711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (dot < 0) { 2721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.clear(); 2731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 2741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 2771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_DOWN: 2791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mDoubleTapListener != null) { 2801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell boolean hadTapMessage = mHandler.hasMessages(TAP); 2811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (hadTapMessage) mHandler.removeMessages(TAP); 2821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage && 2831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) { 2841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // This is a second tap 2851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = true; 2861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Give a callback with the first tap of the double-tap 2871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); 2881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Give a callback with down event of the double-tap 2891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTapEvent(ev); 2901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 2911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // This is a first tap 2921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); 2931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 2951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 2961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusX = mLastFocusX = focusX; 2971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDownFocusY = mLastFocusY = focusY; 2981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mCurrentDownEvent != null) { 2991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mCurrentDownEvent.recycle(); 3001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mCurrentDownEvent = MotionEvent.obtain(ev); 3021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = true; 3031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = true; 3041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mStillDown = true; 3051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 3061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mIsLongpressEnabled) { 3081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 3091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime() 3101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell + TAP_TIMEOUT + LONGPRESS_TIMEOUT); 3111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT); 3131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mListener.onDown(ev); 3141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_MOVE: 3171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 3181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float scrollX = mLastFocusX - focusX; 3211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float scrollY = mLastFocusY - focusY; 3221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mIsDoubleTapping) { 3231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Give the move events of the double-tap 3241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTapEvent(ev); 3251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if (mAlwaysInTapRegion) { 3261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int deltaX = (int) (focusX - mDownFocusX); 3271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int deltaY = (int) (focusY - mDownFocusY); 3281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int distance = (deltaX * deltaX) + (deltaY * deltaY); 3291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (distance > mTouchSlopSquare) { 3301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); 3311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusX = focusX; 3321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusY = focusY; 3331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 3341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 3351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 3361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 3371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (distance > mTouchSlopSquare) { 3391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 3401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) { 3421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY); 3431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusX = focusX; 3441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mLastFocusY = focusY; 3451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_UP: 3491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mStillDown = false; 3501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell MotionEvent currentUpEvent = MotionEvent.obtain(ev); 3511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mIsDoubleTapping) { 3521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Finally, give the up event of the double-tap 3531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled |= mDoubleTapListener.onDoubleTapEvent(ev); 3541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if (mInLongPress) { 3551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 3561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 3571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else if (mAlwaysInTapRegion) { 3581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onSingleTapUp(ev); 3591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 3601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // A fling must travel the minimum tap distance 3621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final VelocityTracker velocityTracker = mVelocityTracker; 3631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final int pointerId = MotionEventCompat.getPointerId(ev, 0); 3641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity); 3651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float velocityY = VelocityTrackerCompat.getYVelocity( 3661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell velocityTracker, pointerId); 3671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell final float velocityX = VelocityTrackerCompat.getXVelocity( 3681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell velocityTracker, pointerId); 3691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if ((Math.abs(velocityY) > mMinimumFlingVelocity) 3711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell || (Math.abs(velocityX) > mMinimumFlingVelocity)){ 3721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY); 3731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mPreviousUpEvent != null) { 3761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mPreviousUpEvent.recycle(); 3771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // Hold the event we obtained above - listeners may have changed the original. 3791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mPreviousUpEvent = currentUpEvent; 3801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mVelocityTracker != null) { 3811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // This may have been cleared when we called out to the 3821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell // application above. 3831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.recycle(); 3841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = null; 3851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 3871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 3881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 3891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell case MotionEvent.ACTION_CANCEL: 3921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell cancel(); 3931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell break; 3941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return handled; 3971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 3981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 3991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void cancel() { 4001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 4011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 4021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 4031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker.recycle(); 4041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mVelocityTracker = null; 4051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 4061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mStillDown = false; 4071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 4081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 4091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 4101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 4111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void cancelTaps() { 4151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(SHOW_PRESS); 4161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(LONG_PRESS); 4171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 4181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mIsDoubleTapping = false; 4191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInTapRegion = false; 4201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mAlwaysInBiggerTapRegion = false; 4211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (mInLongPress) { 4221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = false; 4231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp, 4271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell MotionEvent secondDown) { 4281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (!mAlwaysInBiggerTapRegion) { 4291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return false; 4301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) { 4331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return false; 4341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int deltaX = (int) firstDown.getX() - (int) secondDown.getX(); 4371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell int deltaY = (int) firstDown.getY() - (int) secondDown.getY(); 4381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare); 4391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private void dispatchLongPress() { 4421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mHandler.removeMessages(TAP); 4431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mInLongPress = true; 4441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mListener.onLongPress(mCurrentDownEvent); 4451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell static class GestureDetectorCompatImplJellybeanMr1 implements GestureDetectorCompatImpl { 4491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final GestureDetector mDetector; 4501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompatImplJellybeanMr1(Context context, OnGestureListener listener, 4521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell Handler handler) { 4531ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector = new GestureDetector(context, listener, handler); 4541ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4551ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4561ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4571ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 4581ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mDetector.isLongpressEnabled(); 4591ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4601ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4611ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4621ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent ev) { 4631ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mDetector.onTouchEvent(ev); 4641ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4651ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4661ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4671ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean enabled) { 4681ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector.setIsLongpressEnabled(enabled); 4691ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4701ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4711ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell @Override 4721ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener listener) { 4731ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mDetector.setOnDoubleTapListener(listener); 4741ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4751ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4761ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4771ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell private final GestureDetectorCompatImpl mImpl; 4781ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4791ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 4801ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetectorCompat with the supplied listener. 4811ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * As usual, you may only use this constructor from a UI thread. 4821ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 4831ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 4841ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 4851ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 4861ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 4871ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 4881ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompat(Context context, OnGestureListener listener) { 4891ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell this(context, listener, null); 4901ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 4911ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 4921ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 4931ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Creates a GestureDetectorCompat with the supplied listener. 4941ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * As usual, you may only use this constructor from a UI thread. 4951ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @see android.os.Handler#Handler() 4961ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 4971ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param context the application's context 4981ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, this must 4991ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * not be null. 5001ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param handler the handler that will be used for posting deferred messages 5011ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5021ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public GestureDetectorCompat(Context context, OnGestureListener listener, Handler handler) { 5031ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell if (Build.VERSION.SDK_INT >= 17) { 5041ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl = new GestureDetectorCompatImplJellybeanMr1(context, listener, handler); 5051ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } else { 5061ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl = new GestureDetectorCompatImplBase(context, listener, handler); 5071ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5081ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5091ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5101ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5111ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if longpress is enabled, else false. 5121ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5131ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean isLongpressEnabled() { 5141ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mImpl.isLongpressEnabled(); 5151ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5161ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5171ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5181ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Analyzes the given motion event and if applicable triggers the 5191ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * appropriate callbacks on the {@link OnGestureListener} supplied. 5201ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5211ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param event The current motion event. 5221ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @return true if the {@link OnGestureListener} consumed the event, 5231ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * else false. 5241ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5251ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public boolean onTouchEvent(MotionEvent event) { 5261ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell return mImpl.onTouchEvent(event); 5271ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5281ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5291ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5301ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Set whether longpress is enabled, if this is enabled when a user 5311ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * presses and holds down you get a longpress event and nothing further. 5321ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * If it's disabled the user can press and hold down and then later 5331ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * moved their finger and you will get scroll events. By default 5341ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * longpress is enabled. 5351ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5361ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param enabled whether longpress should be enabled. 5371ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5381ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setIsLongpressEnabled(boolean enabled) { 5391ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl.setIsLongpressEnabled(enabled); 5401ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5411ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell 5421ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell /** 5431ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * Sets the listener which will be called for double-tap and related 5441ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * gestures. 5451ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * 5461ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * @param listener the listener invoked for all the callbacks, or 5471ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell * null to stop listening for double-tap gestures. 5481ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell */ 5491ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell public void setOnDoubleTapListener(OnDoubleTapListener listener) { 5501ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell mImpl.setOnDoubleTapListener(listener); 5511ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell } 5521ce805e30800bf2852fa5421b7277a18e089ee31Adam Powell} 553