Blame client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/utils/GestureDetector.java

Packit 1fb8d4
/*
Packit 1fb8d4
 * Copyright (C) 2008 The Android Open Source Project
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *      http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 * 
Packit 1fb8d4
 * Modified for aFreeRDP by Martin Fleisz (martin.fleisz@thincast.com)
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
package com.freerdp.freerdpcore.utils;
Packit 1fb8d4
Packit 1fb8d4
import android.content.Context;
Packit 1fb8d4
import android.os.Build;
Packit 1fb8d4
import android.os.Handler;
Packit 1fb8d4
import android.os.Message;
Packit 1fb8d4
import android.util.DisplayMetrics;
Packit 1fb8d4
import android.view.MotionEvent;
Packit 1fb8d4
import android.view.ViewConfiguration;
Packit 1fb8d4
Packit 1fb8d4
public class GestureDetector {
Packit 1fb8d4
Packit 1fb8d4
    private static final int TAP_TIMEOUT = 100;
Packit 1fb8d4
    private static final int DOUBLE_TAP_TIMEOUT = 200;
Packit 1fb8d4
    // Distance a touch can wander before we think the user is the first touch in a sequence of double tap
Packit 1fb8d4
    private static final int LARGE_TOUCH_SLOP = 18;
Packit 1fb8d4
    // Distance between the first touch and second touch to still be considered a double tap
Packit 1fb8d4
    private static final int DOUBLE_TAP_SLOP = 100;
Packit 1fb8d4
    // constants for Message.what used by GestureHandler below
Packit 1fb8d4
    private static final int SHOW_PRESS = 1;
Packit 1fb8d4
    private static final int LONG_PRESS = 2;
Packit 1fb8d4
    private static final int TAP = 3;
Packit 1fb8d4
    private final Handler mHandler;
Packit 1fb8d4
    private final OnGestureListener mListener;
Packit 1fb8d4
    private int mTouchSlopSquare;
Packit 1fb8d4
    private int mLargeTouchSlopSquare;
Packit 1fb8d4
    private int mDoubleTapSlopSquare;
Packit 1fb8d4
    private int mLongpressTimeout = 100;
Packit 1fb8d4
    private OnDoubleTapListener mDoubleTapListener;
Packit 1fb8d4
    private boolean mStillDown;
Packit 1fb8d4
    private boolean mInLongPress;
Packit 1fb8d4
    private boolean mAlwaysInTapRegion;
Packit 1fb8d4
    private boolean mAlwaysInBiggerTapRegion;
Packit 1fb8d4
    private MotionEvent mCurrentDownEvent;
Packit 1fb8d4
    private MotionEvent mPreviousUpEvent;
Packit 1fb8d4
    /**
Packit 1fb8d4
     * True when the user is still touching for the second tap (down, move, and
Packit 1fb8d4
     * up events). Can only be true if there is a double tap listener attached.
Packit 1fb8d4
     */
Packit 1fb8d4
    private boolean mIsDoubleTapping;
Packit 1fb8d4
    private float mLastMotionY;
Packit 1fb8d4
    private float mLastMotionX;
Packit 1fb8d4
    private boolean mIsLongpressEnabled;
Packit 1fb8d4
    /**
Packit 1fb8d4
     * True if we are at a target API level of >= Froyo or the developer can
Packit 1fb8d4
     * explicitly set it. If true, input events with > 1 pointer will be ignored
Packit 1fb8d4
     * so we can work side by side with multitouch gesture detectors.
Packit 1fb8d4
     */
Packit 1fb8d4
    private boolean mIgnoreMultitouch;
Packit 1fb8d4
    /**
Packit 1fb8d4
     * Creates a GestureDetector with the supplied listener.
Packit 1fb8d4
     * You may only use this constructor from a UI thread (this is the usual situation).
Packit 1fb8d4
     *
Packit 1fb8d4
     * @param context  the application's context
Packit 1fb8d4
     * @param listener the listener invoked for all the callbacks, this must
Packit 1fb8d4
     *                 not be null.
Packit 1fb8d4
     * @throws NullPointerException if {@code listener} is null.
Packit 1fb8d4
     * @see android.os.Handler#Handler()
Packit 1fb8d4
     */
Packit 1fb8d4
    public GestureDetector(Context context, OnGestureListener listener) {
Packit 1fb8d4
        this(context, listener, null);
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * Creates a GestureDetector with the supplied listener.
Packit 1fb8d4
     * You may only use this constructor from a UI thread (this is the usual situation).
Packit 1fb8d4
     *
Packit 1fb8d4
     * @param context  the application's context
Packit 1fb8d4
     * @param listener the listener invoked for all the callbacks, this must
Packit 1fb8d4
     *                 not be null.
Packit 1fb8d4
     * @param handler  the handler to use
Packit 1fb8d4
     * @throws NullPointerException if {@code listener} is null.
Packit 1fb8d4
     * @see android.os.Handler#Handler()
Packit 1fb8d4
     */
Packit 1fb8d4
    public GestureDetector(Context context, OnGestureListener listener, Handler handler) {
Packit 1fb8d4
        this(context, listener, handler, context != null &&
Packit 1fb8d4
                context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.FROYO);
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * Creates a GestureDetector with the supplied listener.
Packit 1fb8d4
     * You may only use this constructor from a UI thread (this is the usual situation).
Packit 1fb8d4
     *
Packit 1fb8d4
     * @param context          the application's context
Packit 1fb8d4
     * @param listener         the listener invoked for all the callbacks, this must
Packit 1fb8d4
     *                         not be null.
Packit 1fb8d4
     * @param handler          the handler to use
Packit 1fb8d4
     * @param ignoreMultitouch whether events involving more than one pointer should
Packit 1fb8d4
     *                         be ignored.
Packit 1fb8d4
     * @throws NullPointerException if {@code listener} is null.
Packit 1fb8d4
     * @see android.os.Handler#Handler()
Packit 1fb8d4
     */
Packit 1fb8d4
    public GestureDetector(Context context, OnGestureListener listener, Handler handler,
Packit 1fb8d4
                           boolean ignoreMultitouch) {
Packit 1fb8d4
        if (handler != null) {
Packit 1fb8d4
            mHandler = new GestureHandler(handler);
Packit 1fb8d4
        } else {
Packit 1fb8d4
            mHandler = new GestureHandler();
Packit 1fb8d4
        }
Packit 1fb8d4
        mListener = listener;
Packit 1fb8d4
        if (listener instanceof OnDoubleTapListener) {
Packit 1fb8d4
            setOnDoubleTapListener((OnDoubleTapListener) listener);
Packit 1fb8d4
        }
Packit 1fb8d4
        init(context, ignoreMultitouch);
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    private void init(Context context, boolean ignoreMultitouch) {
Packit 1fb8d4
        if (mListener == null) {
Packit 1fb8d4
            throw new NullPointerException("OnGestureListener must not be null");
Packit 1fb8d4
        }
Packit 1fb8d4
        mIsLongpressEnabled = true;
Packit 1fb8d4
        mIgnoreMultitouch = ignoreMultitouch;
Packit 1fb8d4
Packit 1fb8d4
        // Fallback to support pre-donuts releases
Packit 1fb8d4
        int touchSlop, largeTouchSlop, doubleTapSlop;
Packit 1fb8d4
        if (context == null) {
Packit 1fb8d4
            //noinspection deprecation
Packit 1fb8d4
            touchSlop = ViewConfiguration.getTouchSlop();
Packit 1fb8d4
            largeTouchSlop = touchSlop + 2;
Packit 1fb8d4
            doubleTapSlop = DOUBLE_TAP_SLOP;
Packit 1fb8d4
        } else {
Packit 1fb8d4
            final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
Packit 1fb8d4
            final float density = metrics.density;
Packit 1fb8d4
            final ViewConfiguration configuration = ViewConfiguration.get(context);
Packit 1fb8d4
            touchSlop = configuration.getScaledTouchSlop();
Packit 1fb8d4
            largeTouchSlop = (int) (density * LARGE_TOUCH_SLOP + 0.5f);
Packit 1fb8d4
            doubleTapSlop = configuration.getScaledDoubleTapSlop();
Packit 1fb8d4
        }
Packit 1fb8d4
        mTouchSlopSquare = touchSlop * touchSlop;
Packit 1fb8d4
        mLargeTouchSlopSquare = largeTouchSlop * largeTouchSlop;
Packit 1fb8d4
        mDoubleTapSlopSquare = doubleTapSlop * doubleTapSlop;
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * Sets the listener which will be called for double-tap and related
Packit 1fb8d4
     * gestures.
Packit 1fb8d4
     *
Packit 1fb8d4
     * @param onDoubleTapListener the listener invoked for all the callbacks, or
Packit 1fb8d4
     *                            null to stop listening for double-tap gestures.
Packit 1fb8d4
     */
Packit 1fb8d4
    public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) {
Packit 1fb8d4
        mDoubleTapListener = onDoubleTapListener;
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * Set whether longpress is enabled, if this is enabled when a user
Packit 1fb8d4
     * presses and holds down you get a longpress event and nothing further.
Packit 1fb8d4
     * If it's disabled the user can press and hold down and then later
Packit 1fb8d4
     * moved their finger and you will get scroll events. By default
Packit 1fb8d4
     * longpress is enabled.
Packit 1fb8d4
     *
Packit 1fb8d4
     * @param isLongpressEnabled whether longpress should be enabled.
Packit 1fb8d4
     */
Packit 1fb8d4
    public void setIsLongpressEnabled(boolean isLongpressEnabled) {
Packit 1fb8d4
        mIsLongpressEnabled = isLongpressEnabled;
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * @return true if longpress is enabled, else false.
Packit 1fb8d4
     */
Packit 1fb8d4
    public boolean isLongpressEnabled() {
Packit 1fb8d4
        return mIsLongpressEnabled;
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    public void setLongPressTimeout(int timeout) {
Packit 1fb8d4
        mLongpressTimeout = timeout;
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * Analyzes the given motion event and if applicable triggers the
Packit 1fb8d4
     * appropriate callbacks on the {@link OnGestureListener} supplied.
Packit 1fb8d4
     *
Packit 1fb8d4
     * @param ev The current motion event.
Packit 1fb8d4
     * @return true if the {@link OnGestureListener} consumed the event,
Packit 1fb8d4
     * else false.
Packit 1fb8d4
     */
Packit 1fb8d4
    public boolean onTouchEvent(MotionEvent ev) {
Packit 1fb8d4
        final int action = ev.getAction();
Packit 1fb8d4
        final float y = ev.getY();
Packit 1fb8d4
        final float x = ev.getX();
Packit 1fb8d4
Packit 1fb8d4
        boolean handled = false;
Packit 1fb8d4
Packit 1fb8d4
        switch (action & MotionEvent.ACTION_MASK) {
Packit 1fb8d4
            case MotionEvent.ACTION_POINTER_DOWN:
Packit 1fb8d4
                if (mIgnoreMultitouch) {
Packit 1fb8d4
                    // Multitouch event - abort.
Packit 1fb8d4
                    cancel();
Packit 1fb8d4
                }
Packit 1fb8d4
                break;
Packit 1fb8d4
Packit 1fb8d4
            case MotionEvent.ACTION_POINTER_UP:
Packit 1fb8d4
                // Ending a multitouch gesture and going back to 1 finger
Packit 1fb8d4
                if (mIgnoreMultitouch && ev.getPointerCount() == 2) {
Packit 1fb8d4
                    int index = (((action & MotionEvent.ACTION_POINTER_INDEX_MASK)
Packit 1fb8d4
                            >> MotionEvent.ACTION_POINTER_INDEX_SHIFT) == 0) ? 1 : 0;
Packit 1fb8d4
                    mLastMotionX = ev.getX(index);
Packit 1fb8d4
                    mLastMotionY = ev.getY(index);
Packit 1fb8d4
                }
Packit 1fb8d4
                break;
Packit 1fb8d4
Packit 1fb8d4
            case MotionEvent.ACTION_DOWN:
Packit 1fb8d4
                if (mDoubleTapListener != null) {
Packit 1fb8d4
                    boolean hadTapMessage = mHandler.hasMessages(TAP);
Packit 1fb8d4
                    if (hadTapMessage) mHandler.removeMessages(TAP);
Packit 1fb8d4
                    if ((mCurrentDownEvent != null) && (mPreviousUpEvent != null) && hadTapMessage &&
Packit 1fb8d4
                            isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) {
Packit 1fb8d4
                        // This is a second tap
Packit 1fb8d4
                        mIsDoubleTapping = true;
Packit 1fb8d4
                        // Give a callback with the first tap of the double-tap
Packit 1fb8d4
                        handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent);
Packit 1fb8d4
                        // Give a callback with down event of the double-tap
Packit 1fb8d4
                        handled |= mDoubleTapListener.onDoubleTapEvent(ev);
Packit 1fb8d4
                    } else {
Packit 1fb8d4
                        // This is a first tap
Packit 1fb8d4
                        mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT);
Packit 1fb8d4
                    }
Packit 1fb8d4
                }
Packit 1fb8d4
Packit 1fb8d4
                mLastMotionX = x;
Packit 1fb8d4
                mLastMotionY = y;
Packit 1fb8d4
                if (mCurrentDownEvent != null) {
Packit 1fb8d4
                    mCurrentDownEvent.recycle();
Packit 1fb8d4
                }
Packit 1fb8d4
                mCurrentDownEvent = MotionEvent.obtain(ev);
Packit 1fb8d4
                mAlwaysInTapRegion = true;
Packit 1fb8d4
                mAlwaysInBiggerTapRegion = true;
Packit 1fb8d4
                mStillDown = true;
Packit 1fb8d4
                mInLongPress = false;
Packit 1fb8d4
Packit 1fb8d4
                if (mIsLongpressEnabled) {
Packit 1fb8d4
                    mHandler.removeMessages(LONG_PRESS);
Packit 1fb8d4
                    mHandler.sendEmptyMessageAtTime(LONG_PRESS, mCurrentDownEvent.getDownTime()
Packit 1fb8d4
                            + TAP_TIMEOUT + mLongpressTimeout);
Packit 1fb8d4
                }
Packit 1fb8d4
                mHandler.sendEmptyMessageAtTime(SHOW_PRESS, mCurrentDownEvent.getDownTime() + TAP_TIMEOUT);
Packit 1fb8d4
                handled |= mListener.onDown(ev);
Packit 1fb8d4
                break;
Packit 1fb8d4
Packit 1fb8d4
            case MotionEvent.ACTION_MOVE:
Packit 1fb8d4
                if (mIgnoreMultitouch && ev.getPointerCount() > 1) {
Packit 1fb8d4
                    break;
Packit 1fb8d4
                }
Packit 1fb8d4
                final float scrollX = mLastMotionX - x;
Packit 1fb8d4
                final float scrollY = mLastMotionY - y;
Packit 1fb8d4
                if (mIsDoubleTapping) {
Packit 1fb8d4
                    // Give the move events of the double-tap
Packit 1fb8d4
                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);
Packit 1fb8d4
                } else if (mAlwaysInTapRegion) {
Packit 1fb8d4
                    final int deltaX = (int) (x - mCurrentDownEvent.getX());
Packit 1fb8d4
                    final int deltaY = (int) (y - mCurrentDownEvent.getY());
Packit 1fb8d4
                    int distance = (deltaX * deltaX) + (deltaY * deltaY);
Packit 1fb8d4
                    if (distance > mTouchSlopSquare) {
Packit 1fb8d4
                        mLastMotionX = x;
Packit 1fb8d4
                        mLastMotionY = y;
Packit 1fb8d4
                        mAlwaysInTapRegion = false;
Packit 1fb8d4
                        mHandler.removeMessages(TAP);
Packit 1fb8d4
                        mHandler.removeMessages(SHOW_PRESS);
Packit 1fb8d4
                        mHandler.removeMessages(LONG_PRESS);
Packit 1fb8d4
                    }
Packit 1fb8d4
                    if (distance > mLargeTouchSlopSquare) {
Packit 1fb8d4
                        mAlwaysInBiggerTapRegion = false;
Packit 1fb8d4
                    }
Packit 1fb8d4
                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
Packit 1fb8d4
                } else if ((Math.abs(scrollX) >= 1) || (Math.abs(scrollY) >= 1)) {
Packit 1fb8d4
                    handled = mListener.onScroll(mCurrentDownEvent, ev, scrollX, scrollY);
Packit 1fb8d4
                    mLastMotionX = x;
Packit 1fb8d4
                    mLastMotionY = y;
Packit 1fb8d4
                }
Packit 1fb8d4
                break;
Packit 1fb8d4
Packit 1fb8d4
            case MotionEvent.ACTION_UP:
Packit 1fb8d4
                mStillDown = false;
Packit 1fb8d4
                MotionEvent currentUpEvent = MotionEvent.obtain(ev);
Packit 1fb8d4
                if (mIsDoubleTapping) {
Packit 1fb8d4
                    // Finally, give the up event of the double-tap
Packit 1fb8d4
                    handled |= mDoubleTapListener.onDoubleTapEvent(ev);
Packit 1fb8d4
                } else if (mInLongPress) {
Packit 1fb8d4
                    mHandler.removeMessages(TAP);
Packit 1fb8d4
                    mListener.onLongPressUp(ev);
Packit 1fb8d4
                    mInLongPress = false;
Packit 1fb8d4
                } else if (mAlwaysInTapRegion) {
Packit 1fb8d4
                    handled = mListener.onSingleTapUp(mCurrentDownEvent);
Packit 1fb8d4
                } else {
Packit 1fb8d4
                    // A fling must travel the minimum tap distance
Packit 1fb8d4
                }
Packit 1fb8d4
                if (mPreviousUpEvent != null) {
Packit 1fb8d4
                    mPreviousUpEvent.recycle();
Packit 1fb8d4
                }
Packit 1fb8d4
                // Hold the event we obtained above - listeners may have changed the original.
Packit 1fb8d4
                mPreviousUpEvent = currentUpEvent;
Packit 1fb8d4
                mIsDoubleTapping = false;
Packit 1fb8d4
                mHandler.removeMessages(SHOW_PRESS);
Packit 1fb8d4
                mHandler.removeMessages(LONG_PRESS);
Packit 1fb8d4
                handled |= mListener.onUp(ev);
Packit 1fb8d4
                break;
Packit 1fb8d4
            case MotionEvent.ACTION_CANCEL:
Packit 1fb8d4
                cancel();
Packit 1fb8d4
                break;
Packit 1fb8d4
        }
Packit 1fb8d4
        return handled;
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    private void cancel() {
Packit 1fb8d4
        mHandler.removeMessages(SHOW_PRESS);
Packit 1fb8d4
        mHandler.removeMessages(LONG_PRESS);
Packit 1fb8d4
        mHandler.removeMessages(TAP);
Packit 1fb8d4
        mAlwaysInTapRegion = false; // ensures that we won't receive an OnSingleTap notification when a 2-Finger tap is performed
Packit 1fb8d4
        mIsDoubleTapping = false;
Packit 1fb8d4
        mStillDown = false;
Packit 1fb8d4
        if (mInLongPress) {
Packit 1fb8d4
            mInLongPress = false;
Packit 1fb8d4
        }
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    private boolean isConsideredDoubleTap(MotionEvent firstDown, MotionEvent firstUp,
Packit 1fb8d4
                                          MotionEvent secondDown) {
Packit 1fb8d4
        if (!mAlwaysInBiggerTapRegion) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        int deltaX = (int) firstDown.getX() - (int) secondDown.getX();
Packit 1fb8d4
        int deltaY = (int) firstDown.getY() - (int) secondDown.getY();
Packit 1fb8d4
        return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare);
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    private void dispatchLongPress() {
Packit 1fb8d4
        mHandler.removeMessages(TAP);
Packit 1fb8d4
        mInLongPress = true;
Packit 1fb8d4
        mListener.onLongPress(mCurrentDownEvent);
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * The listener that is used to notify when gestures occur.
Packit 1fb8d4
     * If you want to listen for all the different gestures then implement
Packit 1fb8d4
     * this interface. If you only want to listen for a subset it might
Packit 1fb8d4
     * be easier to extend {@link SimpleOnGestureListener}.
Packit 1fb8d4
     */
Packit 1fb8d4
    public interface OnGestureListener {
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a tap occurs with the down {@link MotionEvent}
Packit 1fb8d4
         * that triggered it. This will be triggered immediately for
Packit 1fb8d4
         * every down event. All other events should be preceded by this.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The down motion event.
Packit 1fb8d4
         */
Packit 1fb8d4
        boolean onDown(MotionEvent e);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a tap finishes with the up {@link MotionEvent}
Packit 1fb8d4
         * that triggered it. This will be triggered immediately for
Packit 1fb8d4
         * every up event. All other events should be preceded by this.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The up motion event.
Packit 1fb8d4
         */
Packit 1fb8d4
        boolean onUp(MotionEvent e);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * The user has performed a down {@link MotionEvent} and not performed
Packit 1fb8d4
         * a move or up yet. This event is commonly used to provide visual
Packit 1fb8d4
         * feedback to the user to let them know that their action has been
Packit 1fb8d4
         * recognized i.e. highlight an element.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The down motion event
Packit 1fb8d4
         */
Packit 1fb8d4
        void onShowPress(MotionEvent e);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a tap occurs with the up {@link MotionEvent}
Packit 1fb8d4
         * that triggered it.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The up motion event that completed the first tap
Packit 1fb8d4
         * @return true if the event is consumed, else false
Packit 1fb8d4
         */
Packit 1fb8d4
        boolean onSingleTapUp(MotionEvent e);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a scroll occurs with the initial on down {@link MotionEvent} and the
Packit 1fb8d4
         * current move {@link MotionEvent}. The distance in x and y is also supplied for
Packit 1fb8d4
         * convenience.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e1        The first down motion event that started the scrolling.
Packit 1fb8d4
         * @param e2        The move motion event that triggered the current onScroll.
Packit 1fb8d4
         * @param distanceX The distance along the X axis that has been scrolled since the last
Packit 1fb8d4
         *                  call to onScroll. This is NOT the distance between {@code e1}
Packit 1fb8d4
         *                  and {@code e2}.
Packit 1fb8d4
         * @param distanceY The distance along the Y axis that has been scrolled since the last
Packit 1fb8d4
         *                  call to onScroll. This is NOT the distance between {@code e1}
Packit 1fb8d4
         *                  and {@code e2}.
Packit 1fb8d4
         * @return true if the event is consumed, else false
Packit 1fb8d4
         */
Packit 1fb8d4
        boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a long press occurs with the initial on down {@link MotionEvent}
Packit 1fb8d4
         * that trigged it.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The initial on down motion event that started the longpress.
Packit 1fb8d4
         */
Packit 1fb8d4
        void onLongPress(MotionEvent e);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a long press ends with the final {@link MotionEvent}.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The up motion event that ended the longpress.
Packit 1fb8d4
         */
Packit 1fb8d4
        void onLongPressUp(MotionEvent e);
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * The listener that is used to notify when a double-tap or a confirmed
Packit 1fb8d4
     * single-tap occur.
Packit 1fb8d4
     */
Packit 1fb8d4
    public interface OnDoubleTapListener {
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a single-tap occurs.
Packit 1fb8d4
         * 

Packit 1fb8d4
         * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this
Packit 1fb8d4
         * will only be called after the detector is confident that the user's
Packit 1fb8d4
         * first tap is not followed by a second tap leading to a double-tap
Packit 1fb8d4
         * gesture.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The down motion event of the single-tap.
Packit 1fb8d4
         * @return true if the event is consumed, else false
Packit 1fb8d4
         */
Packit 1fb8d4
        boolean onSingleTapConfirmed(MotionEvent e);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when a double-tap occurs.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The down motion event of the first tap of the double-tap.
Packit 1fb8d4
         * @return true if the event is consumed, else false
Packit 1fb8d4
         */
Packit 1fb8d4
        boolean onDoubleTap(MotionEvent e);
Packit 1fb8d4
Packit 1fb8d4
        /**
Packit 1fb8d4
         * Notified when an event within a double-tap gesture occurs, including
Packit 1fb8d4
         * the down, move, and up events.
Packit 1fb8d4
         *
Packit 1fb8d4
         * @param e The motion event that occurred during the double-tap gesture.
Packit 1fb8d4
         * @return true if the event is consumed, else false
Packit 1fb8d4
         */
Packit 1fb8d4
        boolean onDoubleTapEvent(MotionEvent e);
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    /**
Packit 1fb8d4
     * A convenience class to extend when you only want to listen for a subset
Packit 1fb8d4
     * of all the gestures. This implements all methods in the
Packit 1fb8d4
     * {@link OnGestureListener} and {@link OnDoubleTapListener} but does
Packit 1fb8d4
     * nothing and return {@code false} for all applicable methods.
Packit 1fb8d4
     */
Packit 1fb8d4
    public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener {
Packit 1fb8d4
        public boolean onSingleTapUp(MotionEvent e) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public void onLongPress(MotionEvent e) {
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public void onLongPressUp(MotionEvent e) {
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public boolean onScroll(MotionEvent e1, MotionEvent e2,
Packit 1fb8d4
                                float distanceX, float distanceY) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public void onShowPress(MotionEvent e) {
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public boolean onDown(MotionEvent e) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public boolean onUp(MotionEvent e) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public boolean onDoubleTap(MotionEvent e) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public boolean onDoubleTapEvent(MotionEvent e) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        public boolean onSingleTapConfirmed(MotionEvent e) {
Packit 1fb8d4
            return false;
Packit 1fb8d4
        }
Packit 1fb8d4
    }
Packit 1fb8d4
Packit 1fb8d4
    private class GestureHandler extends Handler {
Packit 1fb8d4
        GestureHandler() {
Packit 1fb8d4
            super();
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        GestureHandler(Handler handler) {
Packit 1fb8d4
            super(handler.getLooper());
Packit 1fb8d4
        }
Packit 1fb8d4
Packit 1fb8d4
        @Override
Packit 1fb8d4
        public void handleMessage(Message msg) {
Packit 1fb8d4
            switch (msg.what) {
Packit 1fb8d4
                case SHOW_PRESS:
Packit 1fb8d4
                    mListener.onShowPress(mCurrentDownEvent);
Packit 1fb8d4
                    break;
Packit 1fb8d4
Packit 1fb8d4
                case LONG_PRESS:
Packit 1fb8d4
                    dispatchLongPress();
Packit 1fb8d4
                    break;
Packit 1fb8d4
Packit 1fb8d4
                case TAP:
Packit 1fb8d4
                    // If the user's finger is still down, do not count it as a tap
Packit 1fb8d4
                    if (mDoubleTapListener != null && !mStillDown) {
Packit 1fb8d4
                        mDoubleTapListener.onSingleTapConfirmed(mCurrentDownEvent);
Packit 1fb8d4
                    }
Packit 1fb8d4
                    break;
Packit 1fb8d4
Packit 1fb8d4
                default:
Packit 1fb8d4
                    throw new RuntimeException("Unknown message " + msg); //never
Packit 1fb8d4
            }
Packit 1fb8d4
        }
Packit 1fb8d4
    }
Packit 1fb8d4
}