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