19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.view;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
19216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powellimport android.content.Context;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Message;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Detects various gestures and events using the supplied {@link MotionEvent}s.
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * The {@link OnGestureListener} callback will notify users when a particular
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * motion event has occurred. This class should only be used with {@link MotionEvent}s
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * reported via touch (don't use for trackball events).
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * To use this class:
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <ul>
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  <li>Create an instance of the {@code GestureDetector} for your {@link View}
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *  <li>In the {@link View#onTouchEvent(MotionEvent)} method ensure you call
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *          {@link #onTouchEvent(MotionEvent)}. The methods defined in your callback
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *          will be executed when the events occur.
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * </ul>
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic class GestureDetector {
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The listener that is used to notify when gestures occur.
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If you want to listen for all the different gestures then implement
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * this interface. If you only want to listen for a subset it might
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * be easier to extend {@link SimpleOnGestureListener}.
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface OnGestureListener {
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified when a tap occurs with the down {@link MotionEvent}
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * that triggered it. This will be triggered immediately for
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * every down event. All other events should be preceded by this.
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e The down motion event.
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean onDown(MotionEvent e);
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * The user has performed a down {@link MotionEvent} and not performed
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * a move or up yet. This event is commonly used to provide visual
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * feedback to the user to let them know that their action has been
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * recognized i.e. highlight an element.
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e The down motion event
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onShowPress(MotionEvent e);
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified when a tap occurs with the up {@link MotionEvent}
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * that triggered it.
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e The up motion event that completed the first tap
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the event is consumed, else false
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean onSingleTapUp(MotionEvent e);
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * current move {@link MotionEvent}. The distance in x and y is also supplied for
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * convenience.
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e1 The first down motion event that started the scrolling.
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e2 The move motion event that triggered the current onScroll.
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param distanceX The distance along the X axis that has been scrolled since the last
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              call to onScroll. This is NOT the distance between {@code e1}
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              and {@code e2}.
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param distanceY The distance along the Y axis that has been scrolled since the last
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              call to onScroll. This is NOT the distance between {@code e1}
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              and {@code e2}.
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the event is consumed, else false
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified when a long press occurs with the initial on down {@link MotionEvent}
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * that trigged it.
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e The initial on down motion event that started the longpress.
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void onLongPress(MotionEvent e);
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified of a fling event when it occurs with the initial on down {@link MotionEvent}
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * and the matching up {@link MotionEvent}. The calculated velocity is supplied along
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the x and y axis in pixels per second.
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e1 The first down motion event that started the fling.
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e2 The move motion event that triggered the current onFling.
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param velocityX The velocity of this fling measured in pixels per second
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              along the x axis.
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param velocityY The velocity of this fling measured in pixels per second
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *              along the y axis.
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the event is consumed, else false
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY);
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The listener that is used to notify when a double-tap or a confirmed
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * single-tap occur.
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public interface OnDoubleTapListener {
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified when a single-tap occurs.
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * <p>
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * will only be called after the detector is confident that the user's
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * first tap is not followed by a second tap leading to a double-tap
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * gesture.
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e The down motion event of the single-tap.
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the event is consumed, else false
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean onSingleTapConfirmed(MotionEvent e);
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified when a double-tap occurs.
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e The down motion event of the first tap of the double-tap.
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the event is consumed, else false
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean onDoubleTap(MotionEvent e);
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Notified when an event within a double-tap gesture occurs, including
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the down, move, and up events.
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @param e The motion event that occurred during the double-tap gesture.
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return true if the event is consumed, else false
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean onDoubleTapEvent(MotionEvent e);
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * A convenience class to extend when you only want to listen for a subset
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of all the gestures. This implements all methods in the
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link OnGestureListener} and {@link OnDoubleTapListener} but does
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * nothing and return {@code false} for all applicable methods.
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onSingleTapUp(MotionEvent e) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onLongPress(MotionEvent e) {
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onScroll(MotionEvent e1, MotionEvent e2,
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                float distanceX, float distanceY) {
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX,
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                float velocityY) {
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onShowPress(MotionEvent e) {
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onDown(MotionEvent e) {
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onDoubleTap(MotionEvent e) {
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onDoubleTapEvent(MotionEvent e) {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean onSingleTapConfirmed(MotionEvent e) {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTouchSlopSquare;
196006fa48bce7759013d9025376cd5167236c434a7Gilles Debunne    private int mDoubleTapTouchSlopSquare;
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mDoubleTapSlopSquare;
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMinimumFlingVelocity;
1994296fc4d326447875c26a925f12b3935632f13bbRomain Guy    private int mMaximumFlingVelocity;
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout();
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAP_TIMEOUT = ViewConfiguration.getTapTimeout();
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout();
204af1785f0b54bff4fcc6218619e34b9861e129cb9Adam Powell    private static final int DOUBLE_TAP_MIN_TIME = ViewConfiguration.getDoubleTapMinTime();
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // constants for Message.what used by GestureHandler below
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int SHOW_PRESS = 1;
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int LONG_PRESS = 2;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private static final int TAP = 3;
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final Handler mHandler;
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private final OnGestureListener mListener;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private OnDoubleTapListener mDoubleTapListener;
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mStillDown;
216eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell    private boolean mDeferConfirmSingleTap;
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mInLongPress;
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAlwaysInTapRegion;
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAlwaysInBiggerTapRegion;
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private MotionEvent mCurrentDownEvent;
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private MotionEvent mPreviousUpEvent;
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * True when the user is still touching for the second tap (down, move, and
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * up events). Can only be true if there is a double tap listener attached.
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsDoubleTapping;
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
23005a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell    private float mLastFocusX;
23105a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell    private float mLastFocusY;
23205a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell    private float mDownFocusX;
23305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell    private float mDownFocusY;
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mIsLongpressEnabled;
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Determines speed during touch scrolling
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private VelocityTracker mVelocityTracker;
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
24221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    /**
24321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     * Consistency verifier for debugging purposes.
24421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown     */
24521bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown    private final InputEventConsistencyVerifier mInputEventConsistencyVerifier =
24621bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            InputEventConsistencyVerifier.isInstrumentationEnabled() ?
24721bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown                    new InputEventConsistencyVerifier(this, 0) : null;
24821bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private class GestureHandler extends Handler {
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GestureHandler() {
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super();
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GestureHandler(Handler handler) {
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            super(handler.getLooper());
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void handleMessage(Message msg) {
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            switch (msg.what) {
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case SHOW_PRESS:
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mListener.onShowPress(mCurrentDownEvent);
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case LONG_PRESS:
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                dispatchLongPress();
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            case TAP:
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // If the user's finger is still down, do not count it as a tap
271eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                if (mDoubleTapListener != null) {
272eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                    if (!mStillDown) {
273eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                        mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
274eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                    } else {
275eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                        mDeferConfirmSingleTap = true;
276eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                    }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            default:
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                throw new RuntimeException("Unknown message " + msg); //never
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a GestureDetector with the supplied listener.
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This variant of the constructor should be used from a non-UI thread
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * (as it allows specifying the Handler).
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param listener the listener invoked for all the callbacks, this must
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not be null.
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param handler the handler to use
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if either {@code listener} or
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@code handler} is null.
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @deprecated Use {@link #GestureDetector(android.content.Context,
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *      android.view.GestureDetector.OnGestureListener, android.os.Handler)} instead.
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Deprecated
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GestureDetector(OnGestureListener listener, Handler handler) {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(null, listener, handler);
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a GestureDetector with the supplied listener.
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * You may only use this constructor from a UI thread (this is the usual situation).
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.os.Handler#Handler()
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param listener the listener invoked for all the callbacks, this must
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not be null.
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if {@code listener} is null.
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @deprecated Use {@link #GestureDetector(android.content.Context,
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *      android.view.GestureDetector.OnGestureListener)} instead.
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Deprecated
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GestureDetector(OnGestureListener listener) {
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(null, listener, null);
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Creates a GestureDetector with the supplied listener.
326c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * You may only use this constructor from a {@link android.os.Looper} thread.
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.os.Handler#Handler()
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the application's context
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param listener the listener invoked for all the callbacks, this must
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not be null.
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if {@code listener} is null.
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GestureDetector(Context context, OnGestureListener listener) {
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        this(context, listener, null);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
340c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * Creates a GestureDetector with the supplied listener that runs deferred events on the
341c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * thread associated with the supplied {@link android.os.Handler}.
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see android.os.Handler#Handler()
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context the application's context
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param listener the listener invoked for all the callbacks, this must
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * not be null.
347c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * @param handler the handler to use for running deferred listener events.
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @throws NullPointerException if {@code listener} is null.
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
35205a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        if (handler != null) {
35305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mHandler = new GestureHandler(handler);
35405a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        } else {
35505a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mHandler = new GestureHandler();
35605a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        }
35705a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        mListener = listener;
35805a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        if (listener instanceof OnDoubleTapListener) {
35905a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            setOnDoubleTapListener((OnDoubleTapListener) listener);
36005a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        }
36105a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        init(context);
362216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell    }
363216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell
364216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell    /**
365c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * Creates a GestureDetector with the supplied listener that runs deferred events on the
366c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * thread associated with the supplied {@link android.os.Handler}.
367216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     * @see android.os.Handler#Handler()
368216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     *
369216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     * @param context the application's context
370216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     * @param listener the listener invoked for all the callbacks, this must
371216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     * not be null.
372c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * @param handler the handler to use for running deferred listener events.
373c27ea258d2790f3f38bfc64c90f32fe0cbcc35a7Scott Main     * @param unused currently not used.
374216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     *
375216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     * @throws NullPointerException if {@code listener} is null.
376216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell     */
377216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell    public GestureDetector(Context context, OnGestureListener listener, Handler handler,
37805a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            boolean unused) {
37905a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        this(context, listener, handler);
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
38205a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell    private void init(Context context) {
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mListener == null) {
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new NullPointerException("OnGestureListener must not be null");
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsLongpressEnabled = true;
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Fallback to support pre-donuts releases
389006fa48bce7759013d9025376cd5167236c434a7Gilles Debunne        int touchSlop, doubleTapSlop, doubleTapTouchSlop;
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (context == null) {
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection deprecation
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            touchSlop = ViewConfiguration.getTouchSlop();
393006fa48bce7759013d9025376cd5167236c434a7Gilles Debunne            doubleTapTouchSlop = touchSlop; // Hack rather than adding a hiden method for this
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            doubleTapSlop = ViewConfiguration.getDoubleTapSlop();
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            //noinspection deprecation
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMinimumFlingVelocity = ViewConfiguration.getMinimumFlingVelocity();
3974296fc4d326447875c26a925f12b3935632f13bbRomain Guy            mMaximumFlingVelocity = ViewConfiguration.getMaximumFlingVelocity();
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final ViewConfiguration configuration = ViewConfiguration.get(context);
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            touchSlop = configuration.getScaledTouchSlop();
401006fa48bce7759013d9025376cd5167236c434a7Gilles Debunne            doubleTapTouchSlop = configuration.getScaledDoubleTapTouchSlop();
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            doubleTapSlop = configuration.getScaledDoubleTapSlop();
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mMinimumFlingVelocity = configuration.getScaledMinimumFlingVelocity();
4044296fc4d326447875c26a925f12b3935632f13bbRomain Guy            mMaximumFlingVelocity = configuration.getScaledMaximumFlingVelocity();
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTouchSlopSquare = touchSlop * touchSlop;
407006fa48bce7759013d9025376cd5167236c434a7Gilles Debunne        mDoubleTapTouchSlopSquare = doubleTapTouchSlop * doubleTapTouchSlop;
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the listener which will be called for double-tap and related
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * gestures.
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param onDoubleTapListener the listener invoked for all the callbacks, or
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        null to stop listening for double-tap gestures.
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mDoubleTapListener = onDoubleTapListener;
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set whether longpress is enabled, if this is enabled when a user
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * presses and holds down you get a longpress event and nothing further.
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If it's disabled the user can press and hold down and then later
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * moved their finger and you will get scroll events. By default
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * longpress is enabled.
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isLongpressEnabled whether longpress should be enabled.
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setIsLongpressEnabled(boolean isLongpressEnabled) {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mIsLongpressEnabled = isLongpressEnabled;
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if longpress is enabled, else false.
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isLongpressEnabled() {
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mIsLongpressEnabled;
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Analyzes the given motion event and if applicable triggers the
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * appropriate callbacks on the {@link OnGestureListener} supplied.
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param ev The current motion event.
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return true if the {@link OnGestureListener} consumed the event,
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *              else false.
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean onTouchEvent(MotionEvent ev) {
45121bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        if (mInputEventConsistencyVerifier != null) {
45221bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown            mInputEventConsistencyVerifier.onTouchEvent(ev, 0);
45321bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown        }
45421bc5c917d4ee2a9b2b8173091e6bba85eaff899Jeff Brown
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int action = ev.getAction();
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mVelocityTracker == null) {
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mVelocityTracker = VelocityTracker.obtain();
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mVelocityTracker.addMovement(ev);
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
462f90165aeda1a8353c1b5e837b1ef4a818ecbefc5Adam Powell        final boolean pointerUp =
463f90165aeda1a8353c1b5e837b1ef4a818ecbefc5Adam Powell                (action & MotionEvent.ACTION_MASK) == MotionEvent.ACTION_POINTER_UP;
46405a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        final int skipIndex = pointerUp ? ev.getActionIndex() : -1;
46505a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell
46605a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        // Determine focal point
46705a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        float sumX = 0, sumY = 0;
46805a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        final int count = ev.getPointerCount();
46905a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        for (int i = 0; i < count; i++) {
47005a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            if (skipIndex == i) continue;
47105a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            sumX += ev.getX(i);
47205a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            sumY += ev.getY(i);
47305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        }
47405a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        final int div = pointerUp ? count - 1 : count;
47505a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        final float focusX = sumX / div;
47605a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        final float focusY = sumY / div;
47705a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean handled = false;
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
480216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        switch (action & MotionEvent.ACTION_MASK) {
481216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        case MotionEvent.ACTION_POINTER_DOWN:
48205a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mDownFocusX = mLastFocusX = focusX;
48305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mDownFocusY = mLastFocusY = focusY;
48405a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            // Cancel long press and taps
48505a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            cancelTaps();
486216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell            break;
487216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell
488216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        case MotionEvent.ACTION_POINTER_UP:
48905a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mDownFocusX = mLastFocusX = focusX;
49005a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mDownFocusY = mLastFocusY = focusY;
491cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell
492cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            // Check the dot product of current velocities.
493cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            // If the pointer that left was opposing another velocity vector, clear.
494cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            mVelocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
495cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            final int upIndex = ev.getActionIndex();
496cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            final int id1 = ev.getPointerId(upIndex);
497cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            final float x1 = mVelocityTracker.getXVelocity(id1);
498cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            final float y1 = mVelocityTracker.getYVelocity(id1);
499cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            for (int i = 0; i < count; i++) {
500cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                if (i == upIndex) continue;
501cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell
502cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                final int id2 = ev.getPointerId(i);
503cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                final float x = x1 * mVelocityTracker.getXVelocity(id2);
504cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                final float y = y1 * mVelocityTracker.getYVelocity(id2);
505cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell
506cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                final float dot = x + y;
507cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                if (dot < 0) {
508cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                    mVelocityTracker.clear();
509cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                    break;
510cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell                }
511cd66359ab9d072b18631276ee4431b2e689a870bAdam Powell            }
512216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell            break;
513216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case MotionEvent.ACTION_DOWN:
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mDoubleTapListener != null) {
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                boolean hadTapMessage = mHandler.hasMessages(TAP);
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (hadTapMessage) mHandler.removeMessages(TAP);
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This is a second tap
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mIsDoubleTapping = true;
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Give a callback with the first tap of the double-tap
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // Give a callback with down event of the double-tap
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    // This is a first tap
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
53205a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mDownFocusX = mLastFocusX = focusX;
53305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mDownFocusY = mLastFocusY = focusY;
53445f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell            if (mCurrentDownEvent != null) {
53545f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell                mCurrentDownEvent.recycle();
53645f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell            }
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCurrentDownEvent = MotionEvent.obtain(ev);
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAlwaysInTapRegion = true;
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mAlwaysInBiggerTapRegion = true;
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStillDown = true;
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mInLongPress = false;
542eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell            mDeferConfirmSingleTap = false;
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mIsLongpressEnabled) {
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHandler.removeMessages(LONG_PRESS);
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        + TAP_TIMEOUT + LONGPRESS_TIMEOUT);
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            handled |= mListener.onDown(ev);
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case MotionEvent.ACTION_MOVE:
55405a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            if (mInLongPress) {
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
55705a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            final float scrollX = mLastFocusX - focusX;
55805a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            final float scrollY = mLastFocusY - focusY;
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mIsDoubleTapping) {
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Give the move events of the double-tap
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (mAlwaysInTapRegion) {
56305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                final int deltaX = (int) (focusX - mDownFocusX);
56405a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                final int deltaY = (int) (focusY - mDownFocusY);
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int distance = (deltaX * deltaX) + (deltaY * deltaY);
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (distance > mTouchSlopSquare) {
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
56805a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                    mLastFocusX = focusX;
56905a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                    mLastFocusY = focusY;
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAlwaysInTapRegion = false;
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mHandler.removeMessages(TAP);
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mHandler.removeMessages(SHOW_PRESS);
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mHandler.removeMessages(LONG_PRESS);
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
575006fa48bce7759013d9025376cd5167236c434a7Gilles Debunne                if (distance > mDoubleTapTouchSlopSquare) {
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mAlwaysInBiggerTapRegion = false;
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
58005a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                mLastFocusX = focusX;
58105a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                mLastFocusY = focusY;
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case MotionEvent.ACTION_UP:
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mStillDown = false;
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MotionEvent currentUpEvent = MotionEvent.obtain(ev);
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mIsDoubleTapping) {
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Finally, give the up event of the double-tap
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled |= mDoubleTapListener.onDoubleTapEvent(ev);
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (mInLongPress) {
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mHandler.removeMessages(TAP);
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mInLongPress = false;
594f5b4b98fada53d91c4c2ebeb5a1d33ccc95c94d2The Android Open Source Project            } else if (mAlwaysInTapRegion) {
5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                handled = mListener.onSingleTapUp(ev);
596eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                if (mDeferConfirmSingleTap && mDoubleTapListener != null) {
597eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                    mDoubleTapListener.onSingleTapConfirmed(ev);
598eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell                }
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // A fling must travel the minimum tap distance
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final VelocityTracker velocityTracker = mVelocityTracker;
60305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                final int pointerId = ev.getPointerId(0);
6044296fc4d326447875c26a925f12b3935632f13bbRomain Guy                velocityTracker.computeCurrentVelocity(1000, mMaximumFlingVelocity);
60505a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                final float velocityY = velocityTracker.getYVelocity(pointerId);
60605a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell                final float velocityX = velocityTracker.getXVelocity(pointerId);
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if ((Math.abs(velocityY) > mMinimumFlingVelocity)
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        || (Math.abs(velocityX) > mMinimumFlingVelocity)){
61045f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell                    handled = mListener.onFling(mCurrentDownEvent, ev, velocityX, velocityY);
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
61345f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell            if (mPreviousUpEvent != null) {
61445f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell                mPreviousUpEvent.recycle();
61545f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell            }
61645f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell            // Hold the event we obtained above - listeners may have changed the original.
61745f2ca7f7d9fac55aa228e022f46ecbac8712a15Adam Powell            mPreviousUpEvent = currentUpEvent;
6187a83b93e12e4a215b90bfa32a753a5a53525d011Dianne Hackborn            if (mVelocityTracker != null) {
6197a83b93e12e4a215b90bfa32a753a5a53525d011Dianne Hackborn                // This may have been cleared when we called out to the
6207a83b93e12e4a215b90bfa32a753a5a53525d011Dianne Hackborn                // application above.
6217a83b93e12e4a215b90bfa32a753a5a53525d011Dianne Hackborn                mVelocityTracker.recycle();
6227a83b93e12e4a215b90bfa32a753a5a53525d011Dianne Hackborn                mVelocityTracker = null;
6237a83b93e12e4a215b90bfa32a753a5a53525d011Dianne Hackborn            }
624b2a3dd88a53cc8c6d19f6dc8ec4f3d6c4abd9b54The Android Open Source Project            mIsDoubleTapping = false;
625eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell            mDeferConfirmSingleTap = false;
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHandler.removeMessages(SHOW_PRESS);
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mHandler.removeMessages(LONG_PRESS);
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            break;
629bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        case MotionEvent.ACTION_CANCEL:
631216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell            cancel();
632bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            break;
633bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        }
634bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown
635bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown        if (!handled && mInputEventConsistencyVerifier != null) {
636bbdc50b102faf52768ac3028bc49e027ff140656Jeff Brown            mInputEventConsistencyVerifier.onUnhandledEvent(ev, 0);
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return handled;
6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
641216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell    private void cancel() {
642216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        mHandler.removeMessages(SHOW_PRESS);
643216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        mHandler.removeMessages(LONG_PRESS);
644216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        mHandler.removeMessages(TAP);
645216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        mVelocityTracker.recycle();
646216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        mVelocityTracker = null;
647216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        mIsDoubleTapping = false;
648216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        mStillDown = false;
64917921eefe3d2219ee2348face5d650d33db64b06Adam Powell        mAlwaysInTapRegion = false;
65017921eefe3d2219ee2348face5d650d33db64b06Adam Powell        mAlwaysInBiggerTapRegion = false;
651eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell        mDeferConfirmSingleTap = false;
652216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        if (mInLongPress) {
653216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell            mInLongPress = false;
654216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell        }
655216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell    }
656216bccf804db9c972b317620a27de6a8adf7fbfeAdam Powell
65705a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell    private void cancelTaps() {
65805a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        mHandler.removeMessages(SHOW_PRESS);
65905a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        mHandler.removeMessages(LONG_PRESS);
66005a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        mHandler.removeMessages(TAP);
66105a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        mIsDoubleTapping = false;
66205a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        mAlwaysInTapRegion = false;
66305a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        mAlwaysInBiggerTapRegion = false;
664eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell        mDeferConfirmSingleTap = false;
66505a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        if (mInLongPress) {
66605a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell            mInLongPress = false;
66705a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell        }
66805a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell    }
66905a1e1f64e06b113a64591be2c28c9f6814490a5Adam Powell
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            MotionEvent secondDown) {
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (!mAlwaysInBiggerTapRegion) {
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
676af1785f0b54bff4fcc6218619e34b9861e129cb9Adam Powell        final long deltaTime = secondDown.getEventTime() - firstUp.getEventTime();
677af1785f0b54bff4fcc6218619e34b9861e129cb9Adam Powell        if (deltaTime > DOUBLE_TAP_TIMEOUT || deltaTime < DOUBLE_TAP_MIN_TIME) {
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return false;
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int deltaX = (int) firstDown.getX() - (int) secondDown.getX();
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int deltaY = (int) firstDown.getY() - (int) secondDown.getY();
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare);
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void dispatchLongPress() {
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler.removeMessages(TAP);
688eca3e6065ee6ce26027ef792d106f2f754a3169dAdam Powell        mDeferConfirmSingleTap = false;
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mInLongPress = true;
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mListener.onLongPress(mCurrentDownEvent);
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
693