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